diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..b6f9048 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,9 @@ +#!/bin/bash + +json_files=$(git diff --cached --name-only | grep '\.json$') +if [ -n "$json_files" ]; then +for file in $json_files; do + jq . "$file" > tmp.$$.json && mv tmp.$$.json "$file" + git add "$file" +done +fi diff --git a/README.md b/README.md index 084387f..3c6cbf6 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,19 @@ ![python >=3.10,<4](https://img.shields.io/badge/python-≥3.10,<4-blue) ![poetry ^1.8](https://img.shields.io/badge/poetry-^1.8-blue) +![NodeJs >=20](https://img.shields.io/badge/NodeJS-≥20-yellow) ![license MIT](https://img.shields.io/badge/license-MIT-brightgreen) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) -Diff your Ethereum smart contracts code from GitHub against Blockchain explorer verified source code. +Diff deployed EVM-compatible smart contract sourcecode and bytecode against the specified GitHub repo commit. -Supports reformatting solidity code by means of prettifier solidity plugin before comparing the sources (option `--prettify`). +Key features: +- retrieve and diff sources from the GitHub repo against the queried ones from a blockscan service (e.g. Etherscan) +- compare the bytecode compiled and deployed on the forked network locally against remote (see section 'bytecode_comparison' in `./config_samples/lido_dao_sepolia_config.json` as an example) +- preprocess solidity sourcecode by means of prettifier solidity plugin before comparing the sources (option `--prettify`) if needed. +- preprocess imports to flat paths for Brownie compatibility (option `--support-brownie`) +- exclude binary comparison (option `--skip-binary-comparison`) +- provide own Hardhat config as optional argument ## Install @@ -15,7 +22,7 @@ Supports reformatting solidity code by means of prettifier solidity plugin befor pipx install git+https://github.com/lidofinance/diffyscan ``` -If need `--prettify` option +If deployed bytecode binary comparison or pretifier sources preprocessing are needed: ```shell npm install @@ -35,13 +42,24 @@ Set your Github token to query API without strict rate limiting, export GITHUB_API_TOKEN= ``` +Set remote RPC URL to validate contract bytecode at remote rpc node, + +```bash +export REMOTE_RPC_URL = +``` + +Set local RPC URL to check immutables against the local deployment and provided constructor arguments, + +```bash +export LOCAL_RPC_URL = (example `http://127.0.0.1:7545`) + Start script with one of the examples provided (or entire folder of configs) ```bash diffyscan config_samples/lido_dao_sepolia_config.json ``` -Alternatively, create a new config file named `config.json`, +Alternatively, create a new config file named `config.json` near the diffyscan.py, ```json { @@ -62,14 +80,54 @@ Alternatively, create a new config file named `config.json`, "commit": "6bd6b76d1156e20e45d1016f355d154141c7e5b9", "relative_root": "contracts" } + }, + "fail_on_comparison_error": true, + "bytecode_comparison": { + "hardhat_config_name": "holesky_hardhat.config.js", + "constructor_calldata": { + "0x28FAB2059C713A7F9D8c86Db49f9bb0e96Af1ef8": "000000000000000000000000ab89ed3d8f31bcf8bb7de53f02084d1e6f043d34000000000000000000000000e92329ec7ddb11d25e25b3c21eebf11f15eb325d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000" + }, + "constructor_args": { + "0xDba5Ad530425bb1b14EECD76F1b4a517780de537": [ + [ + "0x4E97A3972ce8511D87F334dA17a2C332542a5246", + "0x045dd46212A178428c088573A7d102B9d89a022A", + "0xE73a3602b99f1f913e72F8bdcBC235e206794Ac8", + "0x072f72BE3AcFE2c52715829F2CD9061A6C8fF019", + "0x3F1c547b21f65e10480dE3ad8E19fAAC46C95034", + "0xF0d576c7d934bBeCc68FE15F1c5DAF98ea2B78bb", + "0x072f72BE3AcFE2c52715829F2CD9061A6C8fF019", + "0x4E46BD7147ccf666E1d73A3A456fC7a68de82eCA", + "0xd6EbF043D30A7fe46D1Db32BA90a0A51207FE229", + "0xE92329EC7ddB11D25e25b3c21eeBf11f15eB325d", + "0xffDDF7025410412deaa05E3E1cE68FE53208afcb", + "0xc7cc160b58F8Bb0baC94b80847E2CF2800565C50", + "0xF0179dEC45a37423EAD4FaD5fCb136197872EAd9", + "0xC01fC1F2787687Bc656EAc0356ba9Db6e6b7afb7" + ] + ] + } } } ``` +then create a new Hardhat config file named `hardhat_config.js` near the diffyscan.py +```json +module.exports = { + solidity: "0.8.9", + networks: { + hardhat: { + chainId: 17000, + blockGasLimit: 92000000, + hardfork: "cancun", + } + }, +}; +``` Start the script ```bash -dyffyscan +dyffyscan /path/to/config.json /path/to/hardhat_config.js ``` > Note: Brownie verification tooling might rewrite the imports in the source submission. It transforms relative paths to imported contracts into flat paths ('./folder/contract.sol' -> 'contract.sol'), which makes Diffyscan unable to find a contract for verification. @@ -77,7 +135,7 @@ dyffyscan For contracts whose sources were verified by brownie tooling: ```bash -diffyscan --support-brownie +diffyscan /path/to/config.json /path/to/hardhat_config.js --support-brownie ``` ℹ️ See more config examples inside the [config_samples](./config_samples/) dir. @@ -90,7 +148,7 @@ This project was developed using these dependencies with their exact versions li - Python 3.12 - Poetry 1.8 -- if need `--prettify` option support: +- if deployed bytecode binary comparison or pretifier sources preprocessing are needed: - npm Other versions may work as well but were not tested at all. @@ -128,7 +186,7 @@ poetry shell poetry install ``` -5. If need `--prettify` option +5. If deployed bytecode binary comparison or pretifier sources preprocessing are needed: ```shell npm install diff --git a/config_samples/lido_dao_holesky_config.json b/config_samples/lido_dao_holesky_config.json index 1b94274..5ef782a 100644 --- a/config_samples/lido_dao_holesky_config.json +++ b/config_samples/lido_dao_holesky_config.json @@ -1,115 +1,169 @@ { - "contracts": { - "0x28FAB2059C713A7F9D8c86Db49f9bb0e96Af1ef8": "OssifiableProxy", - "0xDba5Ad530425bb1b14EECD76F1b4a517780de537": "LidoLocator", - "0x3F1c547b21f65e10480dE3ad8E19fAAC46C95034": "AppProxyUpgradeable", - "0x59034815464d18134A55EED3702b535D8A32c52b": "Lido", - "0x8d09a4502Cc8Cf1547aD300E066060D043f6982D": "WstETH", - "0xE154732c5Eab277fd88a9fF6Bdff7805eD97BCB1": "EIP712StETH", - "0xd6EbF043D30A7fe46D1Db32BA90a0A51207FE229": "OssifiableProxy", - "0x32f236423928c2c138F46351D9E5FD26331B1aa4": "StakingRouter", - "0x595F64Ddc3856a3b5Ff4f4CC1d1fb4B46cFd2bAC": "AppProxyUpgradeable", - "0xE0270CF2564d81E02284e16539F59C1B5a4718fE": "NodeOperatorsRegistry", - "0x045dd46212A178428c088573A7d102B9d89a022A": "DepositSecurityModule", - "0xE73a3602b99f1f913e72F8bdcBC235e206794Ac8": "LidoExecutionLayerRewardsVault", - "0xc7cc160b58F8Bb0baC94b80847E2CF2800565C50": "OssifiableProxy", - "0xFF72B5cdc701E9eE677966B2702c766c38F412a4": "WithdrawalQueueERC721", - "0xd517d9d04DA9B47dA23df91261bd3bF435BE964A": "WithdrawalVault", - "0x4E46BD7147ccf666E1d73A3A456fC7a68de82eCA": "Burner", - "0x4E97A3972ce8511D87F334dA17a2C332542a5246": "OssifiableProxy", - "0x6AcA050709469F1f98d8f40f68b1C83B533cd2b2": "AccountingOracle", - "0xa067FC95c22D51c3bC35fd4BE37414Ee8cc890d2": "HashConsensus", - "0xffDDF7025410412deaa05E3E1cE68FE53208afcb": "OssifiableProxy", - "0x210f60EC8A4D020b3e22f15fee2d2364e9b22357": "ValidatorsExitBusOracle", - "0xe77Cf1A027d7C10Ee6bb7Ede5E922a181FF40E8f": "HashConsensus", - "0xF0d576c7d934bBeCc68FE15F1c5DAF98ea2B78bb": "OracleReportSanityChecker", - "0x072f72BE3AcFE2c52715829F2CD9061A6C8fF019": "AppProxyUpgradeable", - "0xcE4B3D5bd6259F5dD73253c51b17e5a87bb9Ee64": "LegacyOracle", - "0x14ae7daeecdf57034f3E9db8564e46Dba8D97344": "MiniMeToken", - "0xdA7d2573Df555002503F29aA4003e398d28cc00f": "AppProxyUpgradeable", - "0x994c92228803e8b2D0fb8a610AbCB47412EeF8eF": "Voting", - "0xFaa1692c6eea8eeF534e7819749aD93a1420379A": "AppProxyUpgradeable", - "0x6f0b994E6827faC1fDb58AF66f365676247bAD71": "TokenManager", - "0xf0F281E5d7FBc54EAFcE0dA225CDbde04173AB16": "AppProxyUpgradeable", - "0x1a76ED38B14C768e02b96A879d89Db18AC83EC53": "Finance", - "0xE92329EC7ddB11D25e25b3c21eeBf11f15eB325d": "AppProxyUpgradeable", - "0xF4aDA7Ff34c508B9Af2dE4160B6078D2b58FD46B": "Agent", - "0xfd1E42595CeC3E83239bf8dFc535250e7F48E0bC": "AppProxyUpgradeable", - "0xF1A087E055EA1C11ec3B540795Bd1A544e6dcbe9": "ACL", - "0xC01fC1F2787687Bc656EAc0356ba9Db6e6b7afb7": "OracleDaemonConfig", - "0xA37fb4C41e7D30af5172618a863BBB0f9042c604": "AppProxyUpgradeable", - "0x8959360c48D601a6817BAf2449E5D00cC543FA3A": "Repo", - "0xB3d74c319C0C792522705fFD3097f873eEc71764": "AppProxyUpgradeable", - "0x4E8970d148CB38460bE9b6ddaab20aE2A74879AF": "AppProxyUpgradeable", - "0x3b03f75Ec541Ca11a223bB58621A3146246E1644": "KernelProxy", - "0x34c0cbf9836FD945423bD3d2d72880da9d068E5F": "Kernel", - "0xAa8B4F258a4817bfb0058b861447878168ddf7B0": "CallsScript", - "0xE1200ae048163B67D69Bc0492bF5FddC3a2899C0": "AppProxyPinned", - "0x923B9Cab88E4a1d3de7EE921dEFBF9e2AC6e0791": "EVMScriptRegistry", - "0xB576A85c310CC7Af5C106ab26d2942fA3a5ea94A": "AppProxyUpgradeable", - "0x3EcF7190312F50043DB0494bA0389135Fc3833F3": "APMRegistry", - "0x54eF0022cc769344D0cBCeF12e051281cCBb9fad": "APMRegistryFactory", - "0xe7b4567913AaF2bD54A26E742cec22727D8109eA": "AppProxyUpgradeable", - "0x0df65b7c78Dc42a872010d031D3601C284D8fE71": "AppProxyUpgradeable", - "0xD327b4Fb87fa01599DaD491Aa63B333c44C74472": "AppProxyUpgradeable", - "0x2997EA0D07D79038D83Cb04b3BB9A2Bc512E3fDA": "AppProxyUpgradeable" + "contracts": { + "0x28FAB2059C713A7F9D8c86Db49f9bb0e96Af1ef8": "OssifiableProxy", + "0xDba5Ad530425bb1b14EECD76F1b4a517780de537": "LidoLocator", + "0x3F1c547b21f65e10480dE3ad8E19fAAC46C95034": "AppProxyUpgradeable", + "0x59034815464d18134A55EED3702b535D8A32c52b": "Lido", + "0x8d09a4502Cc8Cf1547aD300E066060D043f6982D": "WstETH", + "0xE154732c5Eab277fd88a9fF6Bdff7805eD97BCB1": "EIP712StETH", + "0xd6EbF043D30A7fe46D1Db32BA90a0A51207FE229": "OssifiableProxy", + "0x32f236423928c2c138F46351D9E5FD26331B1aa4": "StakingRouter", + "0x595F64Ddc3856a3b5Ff4f4CC1d1fb4B46cFd2bAC": "AppProxyUpgradeable", + "0xE0270CF2564d81E02284e16539F59C1B5a4718fE": "NodeOperatorsRegistry", + "0x045dd46212A178428c088573A7d102B9d89a022A": "DepositSecurityModule", + "0xE73a3602b99f1f913e72F8bdcBC235e206794Ac8": "LidoExecutionLayerRewardsVault", + "0xc7cc160b58F8Bb0baC94b80847E2CF2800565C50": "OssifiableProxy", + "0xFF72B5cdc701E9eE677966B2702c766c38F412a4": "WithdrawalQueueERC721", + "0xd517d9d04DA9B47dA23df91261bd3bF435BE964A": "WithdrawalVault", + "0x4E46BD7147ccf666E1d73A3A456fC7a68de82eCA": "Burner", + "0x4E97A3972ce8511D87F334dA17a2C332542a5246": "OssifiableProxy", + "0x6AcA050709469F1f98d8f40f68b1C83B533cd2b2": "AccountingOracle", + "0xa067FC95c22D51c3bC35fd4BE37414Ee8cc890d2": "HashConsensus", + "0xffDDF7025410412deaa05E3E1cE68FE53208afcb": "OssifiableProxy", + "0x210f60EC8A4D020b3e22f15fee2d2364e9b22357": "ValidatorsExitBusOracle", + "0xe77Cf1A027d7C10Ee6bb7Ede5E922a181FF40E8f": "HashConsensus", + "0xF0d576c7d934bBeCc68FE15F1c5DAF98ea2B78bb": "OracleReportSanityChecker", + "0x072f72BE3AcFE2c52715829F2CD9061A6C8fF019": "AppProxyUpgradeable", + "0xcE4B3D5bd6259F5dD73253c51b17e5a87bb9Ee64": "LegacyOracle", + "0x14ae7daeecdf57034f3E9db8564e46Dba8D97344": "MiniMeToken", + "0xdA7d2573Df555002503F29aA4003e398d28cc00f": "AppProxyUpgradeable", + "0x994c92228803e8b2D0fb8a610AbCB47412EeF8eF": "Voting", + "0xFaa1692c6eea8eeF534e7819749aD93a1420379A": "AppProxyUpgradeable", + "0x6f0b994E6827faC1fDb58AF66f365676247bAD71": "TokenManager", + "0xf0F281E5d7FBc54EAFcE0dA225CDbde04173AB16": "AppProxyUpgradeable", + "0x1a76ED38B14C768e02b96A879d89Db18AC83EC53": "Finance", + "0xE92329EC7ddB11D25e25b3c21eeBf11f15eB325d": "AppProxyUpgradeable", + "0xF4aDA7Ff34c508B9Af2dE4160B6078D2b58FD46B": "Agent", + "0xfd1E42595CeC3E83239bf8dFc535250e7F48E0bC": "AppProxyUpgradeable", + "0xF1A087E055EA1C11ec3B540795Bd1A544e6dcbe9": "ACL", + "0xC01fC1F2787687Bc656EAc0356ba9Db6e6b7afb7": "OracleDaemonConfig", + "0xA37fb4C41e7D30af5172618a863BBB0f9042c604": "AppProxyUpgradeable", + "0x8959360c48D601a6817BAf2449E5D00cC543FA3A": "Repo", + "0xB3d74c319C0C792522705fFD3097f873eEc71764": "AppProxyUpgradeable", + "0x4E8970d148CB38460bE9b6ddaab20aE2A74879AF": "AppProxyUpgradeable", + "0x3b03f75Ec541Ca11a223bB58621A3146246E1644": "KernelProxy", + "0x34c0cbf9836FD945423bD3d2d72880da9d068E5F": "Kernel", + "0xAa8B4F258a4817bfb0058b861447878168ddf7B0": "CallsScript", + "0xE1200ae048163B67D69Bc0492bF5FddC3a2899C0": "AppProxyPinned", + "0x923B9Cab88E4a1d3de7EE921dEFBF9e2AC6e0791": "EVMScriptRegistry", + "0xB576A85c310CC7Af5C106ab26d2942fA3a5ea94A": "AppProxyUpgradeable", + "0x3EcF7190312F50043DB0494bA0389135Fc3833F3": "APMRegistry", + "0x54eF0022cc769344D0cBCeF12e051281cCBb9fad": "APMRegistryFactory", + "0xe7b4567913AaF2bD54A26E742cec22727D8109eA": "AppProxyUpgradeable", + "0x0df65b7c78Dc42a872010d031D3601C284D8fE71": "AppProxyUpgradeable", + "0xD327b4Fb87fa01599DaD491Aa63B333c44C74472": "AppProxyUpgradeable", + "0x2997EA0D07D79038D83Cb04b3BB9A2Bc512E3fDA": "AppProxyUpgradeable" + }, + "explorer_hostname": "api-holesky.etherscan.io", + "explorer_token_env_var": "ETHERSCAN_TOKEN", + "github_repo": { + "url": "https://github.com/lidofinance/lido-dao", + "commit": "cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf", + "relative_root": "" + }, + "dependencies": { + "@aragon/os": { + "url": "https://github.com/aragon/aragonOS", + "commit": "f3ae59b00f73984e562df00129c925339cd069ff", + "relative_root": "" }, - "explorer_hostname": "api-holesky.etherscan.io", - "github_repo": { - "url": "https://github.com/lidofinance/lido-dao", - "commit": "cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf", - "relative_root": "" + "@aragon/minime": { + "url": "https://github.com/aragon/minime", + "commit": "1d5251fc88eee5024ff318d95bc9f4c5de130430", + "relative_root": "" }, - "dependencies": { - "@aragon/os": { - "url": "https://github.com/aragon/aragonOS", - "commit": "f3ae59b00f73984e562df00129c925339cd069ff", - "relative_root": "" - }, - "@aragon/minime": { - "url": "https://github.com/aragon/minime", - "commit": "1d5251fc88eee5024ff318d95bc9f4c5de130430", - "relative_root": "" - }, - "@aragon/apps-lido": { - "url": "https://github.com/lidofinance/aragon-apps/", - "commit": "b09834d29c0db211ddd50f50905cbeff257fc8e0", - "relative_root": "" - }, - "@aragon/apps-finance": { - "url": "https://github.com/lidofinance/aragon-apps/", - "commit": "b09834d29c0db211ddd50f50905cbeff257fc8e0", - "relative_root": "apps/finance" - }, - "@aragon/apps-vault": { - "url": "https://github.com/lidofinance/aragon-apps/", - "commit": "b09834d29c0db211ddd50f50905cbeff257fc8e0", - "relative_root": "apps/vault" - }, - "@aragon/apps-agent": { - "url": "https://github.com/lidofinance/aragon-apps/", - "commit": "b09834d29c0db211ddd50f50905cbeff257fc8e0", - "relative_root": "apps/agent" - }, - "openzeppelin-solidity": { - "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", - "commit": "06e265b38d3e9daeaa7b33f9035c700d6bc0c6a0", - "relative_root": "" - }, - "solidity-bytes-utils": { - "url": "https://github.com/GNSPS/solidity-bytes-utils", - "commit": "9776282d181839fbb4b18f2cf218e316d6df871c", - "relative_root": "" - }, - "@openzeppelin/contracts": { - "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", - "commit": "fa64a1ced0b70ab89073d5d0b6e01b0778f7e7d6", - "relative_root": "contracts" - }, - "@openzeppelin/contracts-v4.4": { - "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", - "commit": "6bd6b76d1156e20e45d1016f355d154141c7e5b9", - "relative_root": "contracts" - } + "@aragon/apps-lido": { + "url": "https://github.com/lidofinance/aragon-apps/", + "commit": "b09834d29c0db211ddd50f50905cbeff257fc8e0", + "relative_root": "" + }, + "@aragon/apps-finance": { + "url": "https://github.com/lidofinance/aragon-apps/", + "commit": "b09834d29c0db211ddd50f50905cbeff257fc8e0", + "relative_root": "apps/finance" + }, + "@aragon/apps-vault": { + "url": "https://github.com/lidofinance/aragon-apps/", + "commit": "b09834d29c0db211ddd50f50905cbeff257fc8e0", + "relative_root": "apps/vault" + }, + "@aragon/apps-agent": { + "url": "https://github.com/lidofinance/aragon-apps/", + "commit": "b09834d29c0db211ddd50f50905cbeff257fc8e0", + "relative_root": "apps/agent" + }, + "openzeppelin-solidity": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", + "commit": "06e265b38d3e9daeaa7b33f9035c700d6bc0c6a0", + "relative_root": "" + }, + "solidity-bytes-utils": { + "url": "https://github.com/GNSPS/solidity-bytes-utils", + "commit": "9776282d181839fbb4b18f2cf218e316d6df871c", + "relative_root": "" + }, + "@openzeppelin/contracts": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", + "commit": "fa64a1ced0b70ab89073d5d0b6e01b0778f7e7d6", + "relative_root": "contracts" + }, + "@openzeppelin/contracts-v4.4": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", + "commit": "6bd6b76d1156e20e45d1016f355d154141c7e5b9", + "relative_root": "contracts" + } + }, + "fail_on_comparison_error": true, + "bytecode_comparison": { + "constructor_calldata": { + "0x28FAB2059C713A7F9D8c86Db49f9bb0e96Af1ef8": "000000000000000000000000ab89ed3d8f31bcf8bb7de53f02084d1e6f043d34000000000000000000000000e92329ec7ddb11d25e25b3c21eebf11f15eb325d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000" + }, + "constructor_args": { + "0xF0d576c7d934bBeCc68FE15F1c5DAF98ea2B78bb": [ + "0x28FAB2059C713A7F9D8c86Db49f9bb0e96Af1ef8", + "0x22896Bfc68814BFD855b1a167255eE497006e730", + [ + 1500, + 500, + 1000, + 250, + 2000, + 100, + 100, + 128, + 5000000 + ], + [ + [], + [], + [], + [], + [], + [], + [], + [], + [], + [] + ] + ], + "0xDba5Ad530425bb1b14EECD76F1b4a517780de537": [ + [ + "0x4E97A3972ce8511D87F334dA17a2C332542a5246", + "0x045dd46212A178428c088573A7d102B9d89a022A", + "0xE73a3602b99f1f913e72F8bdcBC235e206794Ac8", + "0x072f72BE3AcFE2c52715829F2CD9061A6C8fF019", + "0x3F1c547b21f65e10480dE3ad8E19fAAC46C95034", + "0xF0d576c7d934bBeCc68FE15F1c5DAF98ea2B78bb", + "0x072f72BE3AcFE2c52715829F2CD9061A6C8fF019", + "0x4E46BD7147ccf666E1d73A3A456fC7a68de82eCA", + "0xd6EbF043D30A7fe46D1Db32BA90a0A51207FE229", + "0xE92329EC7ddB11D25e25b3c21eeBf11f15eB325d", + "0xffDDF7025410412deaa05E3E1cE68FE53208afcb", + "0xc7cc160b58F8Bb0baC94b80847E2CF2800565C50", + "0xF0179dEC45a37423EAD4FaD5fCb136197872EAd9", + "0xC01fC1F2787687Bc656EAc0356ba9Db6e6b7afb7" + ] + ] } + } } diff --git a/config_samples/lido_dao_sepolia_config.json b/config_samples/lido_dao_sepolia_config.json index f03da40..35599d4 100644 --- a/config_samples/lido_dao_sepolia_config.json +++ b/config_samples/lido_dao_sepolia_config.json @@ -1,101 +1,292 @@ { - "contracts": { - "0x8f6254332f69557A72b0DA2D5F0Bc07d4CA991E7": "OssifiableProxy", - "0x604dc1776eEbe7ddCf4cf5429226Ad20a5a294eE": "LidoLocator", - "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af": "AppProxyUpgradeable", - "0x3e7e93bA66d26608c2Ffe1630F445D8D29aC6C92": "Lido", - "0xB82381A3fBD3FaFA77B3a7bE693342618240067b": "WstETH", - "0x9726CA9AEFF4BC8FB8C084BdAbdB71608248E3f8": "EIP712StETH", - "0x4F36aAEb18Ab56A4e380241bea6ebF215b9cb12c": "OssifiableProxy", - "0x46cF57508B0565decC0419B833C2dAFa50B132e0": "StakingRouter", - "0x33d6E15047E8644F8DDf5CD05d202dfE587DA6E3": "AppProxyUpgradeable", - "0xC3704E12c34D929e082257B793c8F114b7Bc7546": "NodeOperatorsRegistry", - "0x94B1B8e2680882f8652882e7F196169dE3d9a3B2": "LidoExecutionLayerRewardsVault", - "0x1583C7b3f4C3B008720E6BcE5726336b0aB25fdd": "OssifiableProxy", - "0x0220A1cF6C3a548BE75aEabCdA509CaB08CDe063": "WithdrawalQueueERC721", - "0xee386d787Db24AbEe4dcc591F35405E323b70Dad": "WithdrawalVault", - "0x61Bb0Ef69262d5EF1cc2873cf61766751D99B699": "Burner", - "0xd497Be005638efCf09F6BFC8DAFBBB0BB72cD991": "OssifiableProxy", - "0x082d16150BF75BB8F2197eEC1d293DbA96c93638": "AccountingOracle", - "0x758D8c3CE794b3Dfe3b3A3482B7eD33de2109D95": "HashConsensus", - "0x7637d44c9f2e9cA584a8B5D2EA493012A5cdaEB6": "OssifiableProxy", - "0xC40801b88C835a58e54eEE6679D301ba31a4C72b": "ValidatorsExitBusOracle", - "0x098a952BD200005382aEb3229e38ae39A7616F56": "HashConsensus", - "0xbac2A471443F18aC5C31078b96C5797A78fCc680": "OracleReportSanityChecker", - "0x7bC76076b0f3879b4A750450C0Ccf02c6Ca11220": "OracleDaemonConfig", - "0x3483c140EF7F2716460198Ff831a8e53F05F1606": "AppProxyUpgradeable", - "0x3F3609d02779Ef8C38AA93c4f5E1b9a44169a6Da": "LegacyOracle", - "0x6155bD199ECcc79Ff4e8B392f6cBD9c9874E8916": "KernelProxy", - "0x1c2807B207f140a1DE0b39E5546eDEf67Af2568c": "Kernel", - "0xd06dF83b8ad6D89C86a187fba4Eae918d497BdCB": "MiniMeToken", - "0x39A0EbdEE54cB319f4F42141daaBDb6ba25D341A": "AppProxyUpgradeable", - "0x9a4384837a49F1CAbfC1daBC4Df268E111864d77": "Voting", - "0xC73cd4B2A7c1CBC5BF046eB4A7019365558ABF66": "AppProxyUpgradeable", - "0x05766b9Ea781343721261BC35E037223438033c2": "TokenManager", - "0x52AD3004Bc993d63931142Dd4f3DD647414048a1": "AppProxyUpgradeable", - "0x6a2ae4361D305c2A87F932555A067612578CE499": "Finance", - "0x32A0E5828B62AAb932362a4816ae03b860b65e83": "AppProxyUpgradeable", - "0xdd4F0f62878022Bc61d5D7FDCFEe66aceadBc234": "Agent", - "0x8A1AA86d35b2EE8C9369618E7D7b40000cCD3295": "AppProxyUpgradeable", - "0x2dfF8E2c55959f719Faa6dCC4a3B0937bcA71F73": "ACL" + "contracts": { + "0x8f6254332f69557A72b0DA2D5F0Bc07d4CA991E7": "OssifiableProxy", + "0x604dc1776eEbe7ddCf4cf5429226Ad20a5a294eE": "LidoLocator", + "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af": "AppProxyUpgradeable", + "0x3e7e93bA66d26608c2Ffe1630F445D8D29aC6C92": "Lido", + "0xB82381A3fBD3FaFA77B3a7bE693342618240067b": "WstETH", + "0x9726CA9AEFF4BC8FB8C084BdAbdB71608248E3f8": "EIP712StETH", + "0x4F36aAEb18Ab56A4e380241bea6ebF215b9cb12c": "OssifiableProxy", + "0x46cF57508B0565decC0419B833C2dAFa50B132e0": "StakingRouter", + "0x33d6E15047E8644F8DDf5CD05d202dfE587DA6E3": "AppProxyUpgradeable", + "0xC3704E12c34D929e082257B793c8F114b7Bc7546": "NodeOperatorsRegistry", + "0x94B1B8e2680882f8652882e7F196169dE3d9a3B2": "LidoExecutionLayerRewardsVault", + "0x1583C7b3f4C3B008720E6BcE5726336b0aB25fdd": "OssifiableProxy", + "0x0220A1cF6C3a548BE75aEabCdA509CaB08CDe063": "WithdrawalQueueERC721", + "0xee386d787Db24AbEe4dcc591F35405E323b70Dad": "WithdrawalVault", + "0x61Bb0Ef69262d5EF1cc2873cf61766751D99B699": "Burner", + "0xd497Be005638efCf09F6BFC8DAFBBB0BB72cD991": "OssifiableProxy", + "0x082d16150BF75BB8F2197eEC1d293DbA96c93638": "AccountingOracle", + "0x758D8c3CE794b3Dfe3b3A3482B7eD33de2109D95": "HashConsensus", + "0x7637d44c9f2e9cA584a8B5D2EA493012A5cdaEB6": "OssifiableProxy", + "0xC40801b88C835a58e54eEE6679D301ba31a4C72b": "ValidatorsExitBusOracle", + "0x098a952BD200005382aEb3229e38ae39A7616F56": "HashConsensus", + "0xbac2A471443F18aC5C31078b96C5797A78fCc680": "OracleReportSanityChecker", + "0x7bC76076b0f3879b4A750450C0Ccf02c6Ca11220": "OracleDaemonConfig", + "0x3483c140EF7F2716460198Ff831a8e53F05F1606": "AppProxyUpgradeable", + "0x3F3609d02779Ef8C38AA93c4f5E1b9a44169a6Da": "LegacyOracle", + "0x6155bD199ECcc79Ff4e8B392f6cBD9c9874E8916": "KernelProxy", + "0x1c2807B207f140a1DE0b39E5546eDEf67Af2568c": "Kernel", + "0xd06dF83b8ad6D89C86a187fba4Eae918d497BdCB": "MiniMeToken", + "0x39A0EbdEE54cB319f4F42141daaBDb6ba25D341A": "AppProxyUpgradeable", + "0x9a4384837a49F1CAbfC1daBC4Df268E111864d77": "Voting", + "0xC73cd4B2A7c1CBC5BF046eB4A7019365558ABF66": "AppProxyUpgradeable", + "0x05766b9Ea781343721261BC35E037223438033c2": "TokenManager", + "0x52AD3004Bc993d63931142Dd4f3DD647414048a1": "AppProxyUpgradeable", + "0x6a2ae4361D305c2A87F932555A067612578CE499": "Finance", + "0x32A0E5828B62AAb932362a4816ae03b860b65e83": "AppProxyUpgradeable", + "0xdd4F0f62878022Bc61d5D7FDCFEe66aceadBc234": "Agent", + "0x8A1AA86d35b2EE8C9369618E7D7b40000cCD3295": "AppProxyUpgradeable", + "0x2dfF8E2c55959f719Faa6dCC4a3B0937bcA71F73": "ACL" + }, + "explorer_token_env_var": "ETHERSCAN_TOKEN", + "explorer_hostname": "api-sepolia.etherscan.io", + "github_repo": { + "url": "https://github.com/lidofinance/lido-dao", + "commit": "cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf", + "relative_root": "" + }, + "dependencies": { + "@aragon/os": { + "url": "https://github.com/aragon/aragonOS", + "commit": "f3ae59b00f73984e562df00129c925339cd069ff", + "relative_root": "" }, - "explorer_token_env_var": "ETHERSCAN_TOKEN", - "explorer_hostname": "api-sepolia.etherscan.io", - "github_repo": { - "url": "https://github.com/lidofinance/lido-dao", - "commit": "cadffa46a2b8ed6cfa1127fca2468bae1a82d6bf", - "relative_root": "" + "@aragon/minime": { + "url": "https://github.com/aragon/minime", + "commit": "1d5251fc88eee5024ff318d95bc9f4c5de130430", + "relative_root": "" }, - "dependencies": { - "@aragon/os": { - "url": "https://github.com/aragon/aragonOS", - "commit": "f3ae59b00f73984e562df00129c925339cd069ff", - "relative_root": "" - }, - "@aragon/minime": { - "url": "https://github.com/aragon/minime", - "commit": "1d5251fc88eee5024ff318d95bc9f4c5de130430", - "relative_root": "" - }, - "@aragon/apps-lido": { - "url": "https://github.com/lidofinance/aragon-apps/", - "commit": "b09834d29c0db211ddd50f50905cbeff257fc8e0", - "relative_root": "" - }, - "@aragon/apps-finance": { - "url": "https://github.com/lidofinance/aragon-apps/", - "commit": "b09834d29c0db211ddd50f50905cbeff257fc8e0", - "relative_root": "apps/finance" - }, - "@aragon/apps-vault": { - "url": "https://github.com/lidofinance/aragon-apps/", - "commit": "b09834d29c0db211ddd50f50905cbeff257fc8e0", - "relative_root": "apps/vault" - }, - "@aragon/apps-agent": { - "url": "https://github.com/lidofinance/aragon-apps/", - "commit": "b09834d29c0db211ddd50f50905cbeff257fc8e0", - "relative_root": "apps/agent" - }, - "openzeppelin-solidity": { - "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", - "commit": "06e265b38d3e9daeaa7b33f9035c700d6bc0c6a0", - "relative_root": "" - }, - "solidity-bytes-utils": { - "url": "https://github.com/GNSPS/solidity-bytes-utils", - "commit": "9776282d181839fbb4b18f2cf218e316d6df871c", - "relative_root": "" - }, - "@openzeppelin/contracts": { - "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", - "commit": "fa64a1ced0b70ab89073d5d0b6e01b0778f7e7d6", - "relative_root": "contracts" - }, - "@openzeppelin/contracts-v4.4": { - "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", - "commit": "6bd6b76d1156e20e45d1016f355d154141c7e5b9", - "relative_root": "contracts" - } + "@aragon/apps-lido": { + "url": "https://github.com/lidofinance/aragon-apps/", + "commit": "b09834d29c0db211ddd50f50905cbeff257fc8e0", + "relative_root": "" + }, + "@aragon/apps-finance": { + "url": "https://github.com/lidofinance/aragon-apps/", + "commit": "b09834d29c0db211ddd50f50905cbeff257fc8e0", + "relative_root": "apps/finance" + }, + "@aragon/apps-vault": { + "url": "https://github.com/lidofinance/aragon-apps/", + "commit": "b09834d29c0db211ddd50f50905cbeff257fc8e0", + "relative_root": "apps/vault" + }, + "@aragon/apps-agent": { + "url": "https://github.com/lidofinance/aragon-apps/", + "commit": "b09834d29c0db211ddd50f50905cbeff257fc8e0", + "relative_root": "apps/agent" + }, + "openzeppelin-solidity": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", + "commit": "06e265b38d3e9daeaa7b33f9035c700d6bc0c6a0", + "relative_root": "" + }, + "solidity-bytes-utils": { + "url": "https://github.com/GNSPS/solidity-bytes-utils", + "commit": "9776282d181839fbb4b18f2cf218e316d6df871c", + "relative_root": "" + }, + "@openzeppelin/contracts": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", + "commit": "fa64a1ced0b70ab89073d5d0b6e01b0778f7e7d6", + "relative_root": "contracts" + }, + "@openzeppelin/contracts-v4.4": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", + "commit": "6bd6b76d1156e20e45d1016f355d154141c7e5b9", + "relative_root": "contracts" + } + }, + "fail_on_comparison_error": true, + "bytecode_comparison": { + "constructor_calldata": { + "0x8f6254332f69557A72b0DA2D5F0Bc07d4CA991E7": "000000000000000000000000f30a674935479cc6f2254ba65d7534eab8bd6ba20000000000000000000000006885e36bfcb68cb383dfe90023a462c03bcb2ae500000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000" + }, + "constructor_args": { + "0x9726CA9AEFF4BC8FB8C084BdAbdB71608248E3f8": [ + "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af" + ], + "0x604dc1776eEbe7ddCf4cf5429226Ad20a5a294eE": [ + [ + "0xd497be005638efcf09f6bfc8dafbbb0bb72cd991", + "0x6885e36bfcb68cb383dfe90023a462c03bcb2ae5", + "0x94b1b8e2680882f8652882e7f196169de3d9a3b2", + "0x3483c140ef7f2716460198ff831a8e53f05f1606", + "0x3e3fe7dbc6b4c189e7128855dd526361c49b40af", + "0xbac2a471443f18ac5c31078b96c5797a78fcc680", + "0x3483c140ef7f2716460198ff831a8e53f05f1606", + "0x61bb0ef69262d5ef1cc2873cf61766751d99b699", + "0x4f36aaeb18ab56a4e380241bea6ebf215b9cb12c", + "0x32a0e5828b62aab932362a4816ae03b860b65e83", + "0x7637d44c9f2e9ca584a8b5d2ea493012a5cdaeb6", + "0x1583c7b3f4c3b008720e6bce5726336b0ab25fdd", + "0xde7318afa67ead6d6bbc8224dfce5ed6e4b86d76", + "0x7bc76076b0f3879b4a750450c0ccf02c6ca11220" + ] + ], + "0xB82381A3fBD3FaFA77B3a7bE693342618240067b": [ + "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af" + ], + "0x46cF57508B0565decC0419B833C2dAFa50B132e0": [ + "0x80b5DC88C98E528bF9cb4B7F0f076aC41da24651" + ], + "0x94B1B8e2680882f8652882e7F196169dE3d9a3B2": [ + "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af", + "0x32A0E5828B62AAb932362a4816ae03b860b65e83" + ], + "0x0220A1cF6C3a548BE75aEabCdA509CaB08CDe063": [ + "0xB82381A3fBD3FaFA77B3a7bE693342618240067b", + "Lido: stETH Withdrawal NFT", + "unstETH" + ], + "0xee386d787Db24AbEe4dcc591F35405E323b70Dad": [ + "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af", + "0x32A0E5828B62AAb932362a4816ae03b860b65e83" + ], + "0x61Bb0Ef69262d5EF1cc2873cf61766751D99B699": [ + "0x6885E36BFcb68CB383DfE90023a462C03BCB2AE5", + "0x32A0E5828B62AAb932362a4816ae03b860b65e83", + "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af", + 0, + 0 + ], + "0x082d16150BF75BB8F2197eEC1d293DbA96c93638": [ + "0x8f6254332f69557A72b0DA2D5F0Bc07d4CA991E7", + "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af", + "0x3483c140EF7F2716460198Ff831a8e53F05F1606", + 12, + 1655733600 + ], + "0x1c2807B207f140a1DE0b39E5546eDEf67Af2568c": [ + 1 + ], + "0xd06dF83b8ad6D89C86a187fba4Eae918d497BdCB": [ + "0x9D381f44d1fbdf8190fA0EcdC028e2Af24DdD3FE", + "0x0000000000000000000000000000000000000000", + 0, + "TEST Lido DAO Token", + 18, + "TLDO", + 1 + ], + "0x758D8c3CE794b3Dfe3b3A3482B7eD33de2109D95": [ + 32, + 12, + 1655733600, + 12, + 10, + "0x6885E36BFcb68CB383DfE90023a462C03BCB2AE5", + "0xd497Be005638efCf09F6BFC8DAFBBB0BB72cD991" + ], + "0xC40801b88C835a58e54eEE6679D301ba31a4C72b": [ + 12, + 1655733600, + "0x8f6254332f69557A72b0DA2D5F0Bc07d4CA991E7" + ], + "0xbac2A471443F18aC5C31078b96C5797A78fCc680": [ + "0x8f6254332f69557A72b0DA2D5F0Bc07d4CA991E7", + "0x6885e36bfcb68cb383dfe90023a462c03bcb2ae5", + [ + 1500, + 500, + 1000, + 250, + 2000, + 100, + 100, + 128, + 5000000 + ], + [ + [], + [], + [], + [], + [], + [], + [], + [], + [], + [] + ] + ], + "0x7bC76076b0f3879b4A750450C0Ccf02c6Ca11220": [ + "0x6885E36BFcb68CB383DfE90023a462C03BCB2AE5", + "" + ], + "0x6155bD199ECcc79Ff4e8B392f6cBD9c9874E8916": [ + "0x1c2807B207f140a1DE0b39E5546eDEf67Af2568c" + ], + "0xC73cd4B2A7c1CBC5BF046eB4A7019365558ABF66": [ + "0x6155bD199ECcc79Ff4e8B392f6cBD9c9874E8916", + "0xcd567bdf93dd0f6acc3bc7f2155f83244d56a65abbfbefb763e015420102c67b", + "" + ], + "0x52AD3004Bc993d63931142Dd4f3DD647414048a1": [ + "0x6155bD199ECcc79Ff4e8B392f6cBD9c9874E8916", + "0x5c9918c99c4081ca9459c178381be71d9da40e49e151687da55099c49a4237f1", + "" + ], + "0x098a952BD200005382aEb3229e38ae39A7616F56": [ + 32, + 12, + 1655733600, + 75, + 10, + "0x7FAcEF1c7248ed171FDd9ea3B25B4550b38e6133", + "0x7637d44c9f2e9cA584a8B5D2EA493012A5cdaEB6" + ], + "0x1583C7b3f4C3B008720E6BcE5726336b0aB25fdd": [ + "0x0220A1cF6C3a548BE75aEabCdA509CaB08CDe063", + "0x32A0E5828B62AAb932362a4816ae03b860b65e83", + "0x0" + ], + "0x32A0E5828B62AAb932362a4816ae03b860b65e83": [ + "0x6155bD199ECcc79Ff4e8B392f6cBD9c9874E8916", + "0x701a4fd1f5174d12a0f1d9ad2c88d0ad11ab6aad0ac72b7d9ce621815f8016a9", + "0" + ], + "0x33d6E15047E8644F8DDf5CD05d202dfE587DA6E3": [ + "0x6155bD199ECcc79Ff4e8B392f6cBD9c9874E8916", + "0x7071f283424072341f856ac9e947e7ec0eb68719f757a7e785979b6b8717579d", + "0" + ], + "0x3483c140EF7F2716460198Ff831a8e53F05F1606": [ + "0x6155bD199ECcc79Ff4e8B392f6cBD9c9874E8916", + "0x8b47ba2a8454ec799cd91646e7ec47168e91fd139b23f017455f3e5898aaba93", + "0" + ], + "0x39A0EbdEE54cB319f4F42141daaBDb6ba25D341A": [ + "0x6155bD199ECcc79Ff4e8B392f6cBD9c9874E8916", + "0x0abcd104777321a82b010357f20887d61247493d89d2e987ff57bcecbde00e1e", + "0" + ], + "0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af": [ + "0x6155bD199ECcc79Ff4e8B392f6cBD9c9874E8916", + "0x3ca7c3e38968823ccb4c78ea688df41356f182ae1d159e4ee608d30d68cef320", + "0" + ], + "0x4F36aAEb18Ab56A4e380241bea6ebF215b9cb12c": [ + "0x46cF57508B0565decC0419B833C2dAFa50B132e0", + "0x32A0E5828B62AAb932362a4816ae03b860b65e83", + "0" + ], + "0x7637d44c9f2e9cA584a8B5D2EA493012A5cdaEB6": [ + "0xC40801b88C835a58e54eEE6679D301ba31a4C72b", + "0x32A0E5828B62AAb932362a4816ae03b860b65e83", + "0" + ], + "0x8A1AA86d35b2EE8C9369618E7D7b40000cCD3295": [ + "0x6155bD199ECcc79Ff4e8B392f6cBD9c9874E8916", + "0xe3262375f45a6e2026b7e7b18c2b807434f2508fe1a2a3dfb493c7df8f4aad6a", + "0" + ], + "0xd497Be005638efCf09F6BFC8DAFBBB0BB72cD991": [ + "0x082d16150BF75BB8F2197eEC1d293DbA96c93638", + "0x32A0E5828B62AAb932362a4816ae03b860b65e83", + "0" + ] } + } } diff --git a/config_samples/optimism/testnet/optimism_testnet_config_L2.json b/config_samples/optimism/testnet/optimism_testnet_config_L2.json index b66a653..8577011 100644 --- a/config_samples/optimism/testnet/optimism_testnet_config_L2.json +++ b/config_samples/optimism/testnet/optimism_testnet_config_L2.json @@ -1,26 +1,36 @@ { - "contracts": { - "0xB34F2747BCd9BCC4107A0ccEb43D5dcdd7Fabf89": "OssifiableProxy", - "0xa989A4B3A26e28DC9d106F163B2B1f35153E0517": "TokenRateOracle", - "0x24B47cd3A74f1799b32B2de11073764Cb1bb318B": "OssifiableProxy", - "0x298953B9426eba4F35a137a4754278a16d97A063": "ERC20BridgedPermit", - "0xf49D208B5C7b10415C7BeAFe9e656F2DF9eDfe3B": "OssifiableProxy", - "0xFd21C82c99ddFa56EB0B9B2D1d0709b7E26D1B2C": "ERC20RebasableBridgedPermit", - "0xdBA2760246f315203F8B716b3a7590F0FFdc704a": "OssifiableProxy", - "0xD48c69358193a34aC035ea7dfB70daDea1600112": "L2ERC20ExtendedTokensBridge" - }, - "explorer_hostname": "api-sepolia-optimistic.etherscan.io", - "explorer_token_env_var": "OPTISCAN_EXPLORER_TOKEN", - "github_repo": { - "url": "https://github.com/lidofinance/lido-l2-with-steth", - "commit": "8f19e1101a211c8f3d42af7ffcb87ab0ebcf750c", - "relative_root": "" - }, - "dependencies": { - "@openzeppelin/contracts": { - "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", - "commit": "d4fb3a89f9d0a39c7ee6f2601d33ffbf30085322", - "relative_root": "contracts" - } - } -} + "contracts": { + "0xB34F2747BCd9BCC4107A0ccEb43D5dcdd7Fabf89": "OssifiableProxy", + "0xa989A4B3A26e28DC9d106F163B2B1f35153E0517": "TokenRateOracle", + "0x24B47cd3A74f1799b32B2de11073764Cb1bb318B": "OssifiableProxy", + "0x298953B9426eba4F35a137a4754278a16d97A063": "ERC20BridgedPermit", + "0xf49D208B5C7b10415C7BeAFe9e656F2DF9eDfe3B": "OssifiableProxy", + "0xFd21C82c99ddFa56EB0B9B2D1d0709b7E26D1B2C": "ERC20RebasableBridgedPermit", + "0xdBA2760246f315203F8B716b3a7590F0FFdc704a": "OssifiableProxy", + "0xD48c69358193a34aC035ea7dfB70daDea1600112": "L2ERC20ExtendedTokensBridge" + }, + "explorer_hostname": "api-sepolia-optimistic.etherscan.io", + "explorer_token_env_var": "OPTISCAN_EXPLORER_TOKEN", + "github_repo": { + "url": "https://github.com/lidofinance/lido-l2", + "commit": "384be204288d04ea8557242cee57d4dc8e521aa4", + "relative_root": "" + }, + "dependencies": { + "@openzeppelin/contracts": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts", + "commit": "d4fb3a89f9d0a39c7ee6f2601d33ffbf30085322", + "relative_root": "contracts" + } + }, + "fail_on_comparison_error": true, + "bytecode_comparison": { + "constructor_args": { + "0xf49D208B5C7b10415C7BeAFe9e656F2DF9eDfe3B": [ + "0xFd21C82c99ddFa56EB0B9B2D1d0709b7E26D1B2C", + "0xf695357C66bA514150Da95b189acb37b46DDe602", + "0xa6487c53000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000174c6971756964207374616b656420457468657220322e300000000000000000000000000000000000000000000000000000000000000000000000000000000005737445544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013100000000000000000000000000000000000000000000000000000000000000" + ] + } + } +} \ No newline at end of file diff --git a/diffyscan/diffyscan.py b/diffyscan/diffyscan.py old mode 100644 new mode 100755 index f53d9cf..bb9e02b --- a/diffyscan/diffyscan.py +++ b/diffyscan/diffyscan.py @@ -3,39 +3,109 @@ import time import argparse import os -import subprocess -import tempfile - -from .utils.common import load_config, load_env -from .utils.constants import DIFFS_DIR, START_TIME, DEFAULT_CONFIG_PATH -from .utils.explorer import get_contract_from_explorer -from .utils.github import get_file_from_github, get_file_from_github_recursive, resolve_dep +import traceback + +from .utils.common import load_config, load_env, prettify_solidity + +from .utils.constants import ( + DIFFS_DIR, + DEFAULT_CONFIG_PATH, + DEFAULT_HARDHAT_CONFIG_PATH, + START_TIME, +) +from .utils.explorer import ( + get_contract_from_explorer, + compile_contract_from_explorer, + parse_compiled_contract, +) +from .utils.github import ( + get_file_from_github, + get_file_from_github_recursive, + resolve_dep, +) from .utils.helpers import create_dirs from .utils.logger import logger - +from .utils.binary_verifier import deep_match_bytecode +from .utils.hardhat import hardhat +from .utils.node_handler import get_bytecode_from_node, get_account, deploy_contract +from .utils.calldata import get_calldata +from .utils.custom_exceptions import ExceptionHandler, BaseCustomException __version__ = "0.0.0" g_skip_user_input: bool = False -def prettify_solidity(solidity_contract_content: str): - github_file_name = os.path.join(tempfile.gettempdir(), "9B91E897-EA51-4FCC-8DAF-FCFF135A6963.sol") - with open(github_file_name, "w") as fp: - fp.write(solidity_contract_content) - prettier_return_code = subprocess.call( - ["npx", "prettier", "--plugin=prettier-plugin-solidity", "--write", github_file_name], - stdout=subprocess.DEVNULL) - if prettier_return_code != 0: - logger.error("Prettier/npx subprocess failed (see the error above)") - sys.exit() - with open(github_file_name, "r") as fp: - return fp.read() - - -def run_diff(config, name, address, explorer_api_token, github_api_token, recursive_parsing=False, prettify=False): + +def run_bytecode_diff( + contract_address_from_config, + contract_name_from_config, + contract_source_code, + config, + deployer_account, + local_rpc_url, + remote_rpc_url, +): + address_name = f"{contract_address_from_config} : {contract_name_from_config}" logger.divider() - logger.okay("Contract", address) + logger.info(f"Binary bytecode comparison started for {address_name}") + target_compiled_contract = compile_contract_from_explorer(contract_source_code) + + contract_creation_code, local_compiled_bytecode, immutables = ( + parse_compiled_contract(target_compiled_contract) + ) + + remote_deployed_bytecode = get_bytecode_from_node( + contract_address_from_config, remote_rpc_url + ) + + is_fully_matched = local_compiled_bytecode == remote_deployed_bytecode + + if is_fully_matched: + logger.okay(f"Bytecodes are fully matched") + return + + logger.info(f"Automated match hasn't worked out") + + calldata = get_calldata( + contract_address_from_config, + target_compiled_contract, + config["bytecode_comparison"], + ) + + contract_creation_code += calldata + + local_contract_address = deploy_contract( + local_rpc_url, deployer_account, contract_creation_code + ) + + local_deployed_bytecode = get_bytecode_from_node( + local_contract_address, local_rpc_url + ) + + is_fully_matched = local_deployed_bytecode == remote_deployed_bytecode + + if is_fully_matched: + logger.okay(f"Bytecodes are fully matched") + return + + deep_match_bytecode( + local_deployed_bytecode, + remote_deployed_bytecode, + immutables, + ) + + +def run_source_diff( + contract_address_from_config, + contract_code, + config, + github_api_token, + recursive_parsing=False, + prettify=False, +): + logger.divider() + logger.okay("Contract", contract_address_from_config) logger.okay("Blockchain explorer Hostname", config["explorer_hostname"]) logger.okay("Repo", config["github_repo"]["url"]) logger.okay("Repo commit", config["github_repo"]["commit"]) @@ -46,21 +116,14 @@ def run_diff(config, name, address, explorer_api_token, github_api_token, recurs logger.info( f"Fetching source code from blockchain explorer {config['explorer_hostname']} ..." ) - contract_name, source_files = get_contract_from_explorer( - token=explorer_api_token, - explorer_hostname=config["explorer_hostname"], - contract=address, - ) - - if contract_name != name: - logger.error( - "Contract name in config does not match with Blockchain explorer", - f"{address}: {name} != {contract_name}", - ) - sys.exit(1) + source_files = ( + contract_code["solcInput"].items() + if not "sources" in contract_code["solcInput"] + else contract_code["solcInput"]["sources"].items() + ) files_count = len(source_files) - logger.okay("Contract", contract_name) + logger.okay("Contract", contract_code["name"]) logger.okay("Files", files_count) if not g_skip_user_input: @@ -96,9 +159,13 @@ def run_diff(config, name, address, explorer_api_token, github_api_token, recurs file_found = bool(repo) if recursive_parsing: - github_file = get_file_from_github_recursive(github_api_token, repo, path_to_file, dep_name) + github_file = get_file_from_github_recursive( + github_api_token, repo, path_to_file, dep_name + ) else: - github_file = get_file_from_github(github_api_token, repo, path_to_file, dep_name) + github_file = get_file_from_github( + github_api_token, repo, path_to_file, dep_name + ) if not github_file: github_file = "" @@ -114,7 +181,9 @@ def run_diff(config, name, address, explorer_api_token, github_api_token, recurs explorer_lines = explorer_content.splitlines() diff_html = difflib.HtmlDiff().make_file(github_lines, explorer_lines) - diff_report_filename = f"{DIFFS_DIR}/{address}/{filename}.html" + diff_report_filename = ( + f"{DIFFS_DIR}/{contract_address_from_config}/{filename}.html" + ) create_dirs(diff_report_filename) with open(diff_report_filename, "w") as f: @@ -145,32 +214,129 @@ def run_diff(config, name, address, explorer_api_token, github_api_token, recurs logger.report_table(report) -def process_config(path: str, recursive_parsing: bool, unify_formatting: bool): +def process_config( + path: str, + hardhat_config_path: str, + recursive_parsing: bool, + unify_formatting: bool, + skip_binary_comparison: bool, +): logger.info(f"Loading config {path}...") config = load_config(path) - github_api_token = load_env("GITHUB_API_TOKEN", masked=True) explorer_token = None if "explorer_token_env_var" in config: - explorer_token = load_env(config["explorer_token_env_var"], masked=True, required=False) + explorer_token = load_env( + config["explorer_token_env_var"], masked=True, required=False + ) + if explorer_token is None: + logger.warn( + f'Failed to find an explorer token in the config ("explorer_token_env_var")' + ) + explorer_token = os.getenv("ETHERSCAN_EXPLORER_TOKEN", default=None) + if explorer_token is None: + logger.warn( + f'Failed to find explorer token in env ("ETHERSCAN_EXPLORER_TOKEN")' + ) - contracts = config["contracts"] - logger.info(f"Running diff for contracts from config {contracts}...") - for address, name in config["contracts"].items(): - run_diff(config, name, address, explorer_token, github_api_token, recursive_parsing, unify_formatting) + if not skip_binary_comparison: + if "bytecode_comparison" not in config: + raise ValueError(f'Failed to find "bytecode_comparison" section in config') + + github_api_token = os.getenv("GITHUB_API_TOKEN", "") + if not github_api_token: + raise ValueError("GITHUB_API_TOKEN variable is not set") + + local_rpc_url = os.getenv("LOCAL_RPC_URL", "") + if not local_rpc_url: + raise ValueError("LOCAL_RPC_URL variable is not set") + + remote_rpc_url = os.getenv("REMOTE_RPC_URL", "") + if not remote_rpc_url: + raise ValueError("REMOTE_RPC_URL variable is not set") + + ExceptionHandler.initialize(config["fail_on_comparison_error"]) + + try: + if not skip_binary_comparison: + hardhat.start( + hardhat_config_path, + local_rpc_url, + remote_rpc_url, + ) + deployer_account = get_account(local_rpc_url) + + for contract_address, contract_name in config["contracts"].items(): + try: + contract_code = get_contract_from_explorer( + explorer_token, + config["explorer_hostname"], + contract_address, + contract_name, + ) + run_source_diff( + contract_address, + contract_code, + config, + github_api_token, + recursive_parsing, + unify_formatting, + ) + if not skip_binary_comparison: + run_bytecode_diff( + contract_address, + contract_name, + contract_code, + config, + deployer_account, + local_rpc_url, + remote_rpc_url, + ) + except BaseCustomException as custom_exc: + ExceptionHandler.raise_exception_or_log(custom_exc) + traceback.print_exc() + except KeyboardInterrupt: + logger.info(f"Keyboard interrupt by user") + + finally: + if not skip_binary_comparison: + hardhat.stop() def parse_arguments(): parser = argparse.ArgumentParser() - parser.add_argument("--version", "-V", action="store_true", help="Display version information") - parser.add_argument("path", nargs="?", default=None, help="Path to config or directory with configs") - parser.add_argument("--yes", "-y", help="If set don't ask for input before validating each contract", action="store_true") + parser.add_argument( + "--version", "-V", action="store_true", help="Display version information" + ) + parser.add_argument( + "path", nargs="?", default=None, help="Path to config or directory with configs" + ) + parser.add_argument( + "hardhat_path", nargs="?", default=None, help="Path to Hardhat config" + ) + parser.add_argument( + "--yes", + "-Y", + help="If set don't ask for input before validating each contract", + action="store_true", + ) parser.add_argument( "--support-brownie", help="Support recursive retrieving for contracts. It may be useful for contracts whose sources have been verified by the brownie tooling, which automatically replaces relative paths to contracts in imports with plain contract names.", action=argparse.BooleanOptionalAction, ) - parser.add_argument("--prettify", "-p", help="Unify formatting by prettier before comparing", action="store_true") + parser.add_argument( + "--prettify", + "-P", + help="Unify formatting by prettier before comparing", + action="store_true", + ) + parser.add_argument( + "--skip-binary-comparison", + "-B", + help="Skip binary bytecode comparison", + action="store_true", + ) return parser.parse_args() @@ -179,23 +345,41 @@ def main(): args = parse_arguments() g_skip_user_input = args.yes - if args.version: print(f"Diffyscan {__version__}") return - logger.info("Welcome to Diffyscan!") logger.divider() - + hardhat_config_path = ( + DEFAULT_HARDHAT_CONFIG_PATH if args.hardhat_path is None else args.hardhat_path + ) if args.path is None: - process_config(DEFAULT_CONFIG_PATH, args.support_brownie, args.prettify) + process_config( + DEFAULT_CONFIG_PATH, + hardhat_config_path, + args.support_brownie, + args.prettify, + args.skip_binary_comparison, + ) elif os.path.isfile(args.path): - process_config(args.path, args.support_brownie, args.prettify) + process_config( + args.path, + hardhat_config_path, + args.support_brownie, + args.prettify, + args.skip_binary_comparison, + ) elif os.path.isdir(args.path): for filename in os.listdir(args.path): - config_path = os.path.join(args.path, filename) + config_path = os.path.join(args.path, filename, args.skip_binary_comparison) if os.path.isfile(config_path): - process_config(config_path, args.support_brownie, args.prettify) + process_config( + config_path, + hardhat_config_path, + args.support_brownie, + args.prettify, + args.skip_binary_comparison, + ) else: logger.error(f"Specified config path {args.path} not found") sys.exit(1) diff --git a/diffyscan/utils/binary_verifier.py b/diffyscan/utils/binary_verifier.py new file mode 100644 index 0000000..1bd7fef --- /dev/null +++ b/diffyscan/utils/binary_verifier.py @@ -0,0 +1,190 @@ +import itertools + +from .logger import logger, bgYellow, bgRed, bgGreen, red, green, to_hex +from .constants import OPCODES, PUSH0, PUSH32 +from .custom_exceptions import BinVerifierError + + +def format_bytecode(bytecode): + return "0x" + bytecode[2:] if len(bytecode) > 2 else "" + + +def trim_solidity_meta(bytecode: str) -> dict: + meta_size = int(bytecode[-4:], 16) * 2 + 4 + + if meta_size > len(bytecode): + return {"bytecode": bytecode, "metadata": ""} + + return { + "bytecode": bytecode[:-meta_size], + "metadata": bytecode[-meta_size:], + } + + +def deep_match_bytecode( + actual_bytecode: str, expected_bytecode: str, immutables: dict +) -> None: + logger.info("Comparing actual code with the expected one...") + + actual_trimmed_bytecode = trim_solidity_meta(actual_bytecode) + expected_trimmed_bytecode = trim_solidity_meta(expected_bytecode) + + if actual_trimmed_bytecode["metadata"] or expected_trimmed_bytecode["metadata"]: + logger.info("Metadata has been detected and trimmed") + + actual_instructions, unknown_opcodes_first_half = parse( + actual_trimmed_bytecode["bytecode"] + ) + expected_instructions, unknown_opcodes_second_half = parse( + expected_trimmed_bytecode["bytecode"] + ) + + unknown_opcodes = ( + unknown_opcodes_first_half or set() | unknown_opcodes_second_half or set() + ) + if unknown_opcodes: + logger.warn(f"Detected unknown opcodes: {unknown_opcodes}") + + if len(actual_instructions) != len(expected_instructions): + logger.warn(f"Codes have a different length") + + zipped_instructions = list( + itertools.zip_longest(actual_instructions, expected_instructions) + ) + + is_mismatch = ( + lambda pair: pair[0] is None + or pair[1] is None + or pair[0].get("bytecode") != pair[1].get("bytecode") + ) + mismatches = [ + index for index, pair in enumerate(zipped_instructions) if is_mismatch(pair) + ] + + near_lines_count = 3 # context depth, i.e., the number of lines above and \below to be displayed for each diff + + checkpoints = {0, *mismatches} + + if actual_instructions: + checkpoints.add(len(actual_instructions) - 1) + + if expected_instructions: + checkpoints.add(len(expected_instructions) - 1) + + for ind in list(checkpoints): + start_index = max(0, ind - near_lines_count) + end_index = min(ind + near_lines_count, len(zipped_instructions) - 1) + + checkpoints.update(range(start_index, end_index + 1)) + + checkpoints = sorted(checkpoints) + + logger.divider() + logger.info(f"0000 00 STOP - both expected and actual bytecode instructions match") + logger.info(f'{bgRed("0x0002")} - the actual bytecode differs') + logger.info( + f'{bgYellow("0x0001")} - the actual bytecode differs on the immutable reference position' + ) + logger.info( + f'{bgGreen("0x0003")} - the expected bytecode value when it doesn\'t match the actual one' + ) + logger.info( + f'{red("0000 00 STOP")} - the actual bytecode instruction doesn\'t exist, but expected is present' + ) + logger.info( + f'{green("0000 00 STOP")} - the actual bytecode instruction exists when the expected doesn\'t' + ) + logger.divider() + + is_matched_with_excluded_immutables = True + for previous_index, current_index in zip(checkpoints, checkpoints[1:]): + if previous_index != current_index - 1: + print("...") + + actual = ( + actual_instructions[current_index] + if current_index < len(actual_instructions) + else None + ) + expected = ( + expected_instructions[current_index] + if current_index < len(expected_instructions) + else None + ) + + if not actual and expected: + params = "0x" + expected["bytecode"][2:] + print( + red( + f'{to_hex(current_index, 4)} {to_hex(expected["op"]["code"])} {expected["op"]["name"]} {params}' + ) + ) + elif actual and not expected: + params = "0x" + actual["bytecode"][2:] + print( + green( + f'{to_hex(current_index, 4)} {to_hex(actual["op"]["code"])} {actual["op"]["name"]} {params}' + ) + ) + elif actual and expected: + opcode = ( + to_hex(actual["op"]["code"]) + if actual["op"]["code"] == expected["op"]["code"] + else bgRed(to_hex(actual["op"]["code"])) + + " " + + bgGreen(to_hex(expected["op"]["code"])) + ) + opname = ( + actual["op"]["name"] + if actual["op"]["name"] == expected["op"]["name"] + else bgRed(actual["op"]["name"]) + " " + bgGreen(expected["op"]["name"]) + ) + + actual_params = format_bytecode(actual["bytecode"]) + expected_params = format_bytecode(expected["bytecode"]) + + params_length = len(expected["bytecode"]) // 2 - 1 + is_immutable = immutables.get(expected["start"] + 1) == params_length + if actual_params != expected_params and not is_immutable: + is_matched_with_excluded_immutables = False + params = ( + actual_params + if actual_params == expected_params + else ( + bgYellow(actual_params) + " " + bgGreen(expected_params) + if is_immutable + else bgRed(actual_params) + " " + bgGreen(expected_params) + ) + ) + print(f"{to_hex(current_index, 4)} {opcode} {opname} {params}") + else: + raise BinVerifierError("Invalid bytecode difference data") + + if not is_matched_with_excluded_immutables: + raise BinVerifierError( + f"Bytecodes have differences not on the immutable reference position" + ) + + logger.okay(f"Bytecodes have differences only on the immutable reference position") + + +def parse(bytecode): + buffer = bytes.fromhex(bytecode[2:] if bytecode.startswith("0x") else bytecode) + instructions = [] + i = 0 + unknown_opcodes = set() + while i < len(buffer): + opcode = buffer[i] + if opcode not in OPCODES: + unknown_opcodes.add(hex(opcode)) + length = 1 + (opcode - PUSH0 if PUSH0 <= opcode <= PUSH32 else 0) + instructions.append( + { + "start": i, + "length": length, + "op": {"name": OPCODES.get(opcode, "INVALID"), "code": opcode}, + "bytecode": buffer[i : i + length].hex(), + } + ) + i += length + return instructions, unknown_opcodes diff --git a/diffyscan/utils/calldata.py b/diffyscan/utils/calldata.py new file mode 100644 index 0000000..f4620d1 --- /dev/null +++ b/diffyscan/utils/calldata.py @@ -0,0 +1,80 @@ +from .logger import logger +from .encoder import encode_constructor_arguments +from .custom_exceptions import CalldataError + + +def get_calldata(contract_address_from_config, target_compiled_contract, binary_config): + + raw_calldata_exist = ( + "constructor_calldata" in binary_config + and contract_address_from_config in binary_config["constructor_calldata"] + ) + + calldata_args_exist = ( + "constructor_args" in binary_config + and contract_address_from_config in binary_config["constructor_args"] + ) + + if raw_calldata_exist and calldata_args_exist: + raise CalldataError( + f"Contract address found in 'constructor_args' and in 'constructor_calldata' in config" + ) + if not raw_calldata_exist and not calldata_args_exist: + raise CalldataError( + "Contract address not found in 'constructor_args' and in 'constructor_calldata' in config" + ) + if raw_calldata_exist: + return get_raw_calldata_from_config(contract_address_from_config, binary_config) + + return parse_calldata_from_config( + contract_address_from_config, + binary_config["constructor_args"], + target_compiled_contract, + ) + + +def get_constructor_abi(target_compiled_contract): + constructor_abi = None + try: + constructor_abi = [ + entry["inputs"] + for entry in target_compiled_contract["abi"] + if entry["type"] == "constructor" + ][0] + except IndexError: + logger.okay( + f"Contract's ABI doesn't have a constructor, calldata calculation skipped" + ) + return None + + logger.okay(f"Constructor in ABI successfully found") + return constructor_abi + + +def get_raw_calldata_from_config(contract_address_from_config, binary_config): + logger.info(f"Trying to use prepared calldata from config") + + calldata_field = binary_config["constructor_calldata"] + prepared_calldata_from_config = calldata_field[contract_address_from_config] + return prepared_calldata_from_config + + +def parse_calldata_from_config( + contract_address_from_config, constructor_args, target_compiled_contract +): + logger.info(f"Trying to parse calldata from config") + constructor_abi = get_constructor_abi(target_compiled_contract) + if constructor_abi is None: + raise CalldataError("Failed to find ABI constructor in compiled contract") + + if constructor_args is None: + raise CalldataError("Failed to find constructor's args in config") + + calldata = encode_constructor_arguments( + constructor_abi, constructor_args[contract_address_from_config] + ) + + if not calldata: + raise CalldataError("Contract calldata is empty") + + return calldata diff --git a/diffyscan/utils/common.py b/diffyscan/utils/common.py index afae8fe..f41e23a 100644 --- a/diffyscan/utils/common.py +++ b/diffyscan/utils/common.py @@ -1,12 +1,16 @@ import json import os import sys -from urllib.parse import urlparse - +import subprocess +import tempfile import requests +import uuid + +from urllib.parse import urlparse from .logger import logger -from .types import Config +from .custom_types import Config +from .custom_exceptions import NodeError, ExplorerError def load_env(variable_name, required=True, masked=False): @@ -31,19 +35,38 @@ def load_config(path: str) -> Config: return json.load(config_file) -def fetch(url, headers={}): +def fetch(url, headers=None): logger.log(f"Fetch: {url}") - response = requests.get(url, headers=headers) - - if response.status_code == 404: - return None - - if not response.ok and response.status_code != 200: - logger.error("Request failed", url) - logger.error("Status", response.status_code) - logger.error("Response", response.text) - - return response.json() + try: + response = requests.get(url, headers=headers) + response.raise_for_status() + except requests.exceptions.HTTPError as http_err: + raise ExplorerError(f"HTTP error occurred: {http_err}") + except requests.exceptions.ConnectionError as conn_err: + raise ExplorerError(f"Connection error occurred: {conn_err}") + except requests.exceptions.Timeout as timeout_err: + raise ExplorerError(f"Timeout error occurred: {timeout_err}") + except requests.exceptions.RequestException as req_err: + raise ExplorerError(f"Request exception occurred: {req_err}") + + return response + + +def pull(url, payload=None, headers=None): + logger.log(f"Pull: {url}") + try: + response = requests.post(url, data=payload, headers=headers) + response.raise_for_status() + except requests.exceptions.HTTPError as http_err: + raise NodeError(f"HTTP error occurred: {http_err}") + except requests.exceptions.ConnectionError as conn_err: + raise NodeError(f"Connection error occurred: {conn_err}") + except requests.exceptions.Timeout as timeout_err: + raise NodeError(f"Timeout error occurred: {timeout_err}") + except requests.exceptions.RequestException as req_err: + raise NodeError(f"Request exception occurred: {req_err}") + + return response def mask_text(text, mask_start=3, mask_end=3): @@ -57,3 +80,25 @@ def parse_repo_link(repo_link): repo_location = [item.strip("/") for item in parse_result[2].split("tree")] user_slash_repo = repo_location[0] return user_slash_repo + + +def prettify_solidity(solidity_contract_content: str): + github_file_name = os.path.join(tempfile.gettempdir(), f"{uuid.uuid4()}.sol") + with open(github_file_name, "w") as fp: + fp.write(solidity_contract_content) + + prettier_return_code = subprocess.call( + [ + "npx", + "prettier", + "--plugin=prettier-plugin-solidity", + "--write", + github_file_name, + ], + stdout=subprocess.DEVNULL, + ) + if prettier_return_code != 0: + logger.error("Prettier/npx subprocess failed (see the error above)") + sys.exit() + with open(github_file_name, "r") as fp: + return fp.read() diff --git a/diffyscan/utils/compiler.py b/diffyscan/utils/compiler.py new file mode 100644 index 0000000..11d1500 --- /dev/null +++ b/diffyscan/utils/compiler.py @@ -0,0 +1,114 @@ +import platform +import hashlib +import subprocess +import json +import os +import stat +import sys + +from .common import fetch +from .helpers import create_dirs +from .logger import logger +from .custom_exceptions import CompileError + + +def get_solc_native_platform_from_os(): + platform_name = sys.platform + if platform_name == "linux": + return "linux-amd64" + elif platform_name == "darwin": + return "macosx-amd64" if platform.machine() == "x86_64" else "macosx-arm64" + elif platform_name == "win32": + return "windows-amd64" + else: + raise CompileError(f"Unsupported platform {platform_name}") + + +def get_compiler_info(required_platform, required_compiler_version): + compilers_list_url = f"https://raw.githubusercontent.com/ethereum/solc-bin/gh-pages/{required_platform}/list.json" + available_compilers_list = fetch(compilers_list_url).json() + required_build_info = next( + ( + compiler + for compiler in available_compilers_list["builds"] + if compiler["longVersion"] == required_compiler_version + ), + None, + ) + + if not required_build_info: + raise CompileError( + f'Required compiler version "{required_compiler_version}" for "{required_platform}" is not found' + ) + + return required_build_info + + +def download_compiler(required_platform, build_info, destination_path): + compiler_url = ( + f'https://binaries.soliditylang.org/{required_platform}/{build_info["path"]}' + ) + download_compiler_response = fetch(compiler_url) + + try: + with open(destination_path, "wb") as compiler_file: + compiler_file.write(download_compiler_response.content) + except IOError as e: + raise CompileError(f"Error writing to file: {e}") + except Exception as e: + raise CompileError(f"An error occurred: {e}") + return download_compiler_response.content + + +def check_compiler_checksum(compiler, valid_checksum): + compiler_checksum = hashlib.sha256(compiler).hexdigest() + if compiler_checksum != valid_checksum: + raise CompileError( + f"Compiler checksum mismatch. Expected: {valid_checksum}, Got: {compiler_checksum}" + ) + + +def set_compiler_executable(compiler_path): + compiler_file_rights = os.stat(compiler_path) + os.chmod(compiler_path, compiler_file_rights.st_mode | stat.S_IEXEC) + + +def prepare_compiler(required_platform, build_info, compiler_path): + create_dirs(compiler_path) + compiler_binary = download_compiler(required_platform, build_info, compiler_path) + valid_checksum = build_info["sha256"][2:] + check_compiler_checksum(compiler_binary, valid_checksum) + set_compiler_executable(compiler_path) + + +def compile_contracts(compiler_path, input_settings): + try: + process = subprocess.run( + [compiler_path, "--standard-json"], + input=input_settings.encode(), + capture_output=True, + check=True, + timeout=30, + ) + except subprocess.CalledProcessError as e: + raise CompileError(f"Error during compiler subprocess execution: {e}") + except subprocess.TimeoutExpired as e: + raise CompileError(f"Compiler process timed out: {e}") + except Exception as e: + raise CompileError(f"An unexpected error occurred: {e}") + return json.loads(process.stdout) + + +def get_target_compiled_contract(compiled_contracts, target_contract_name): + contracts_to_check = [] + for contracts in compiled_contracts: + for name, contract in contracts.items(): + if name == target_contract_name: + contracts_to_check.append(contract) + + if len(contracts_to_check) != 1: + raise CompileError("multiple contracts with the same name") + + logger.okay(f"Contracts were successfully compiled") + + return contracts_to_check[0] diff --git a/diffyscan/utils/constants.py b/diffyscan/utils/constants.py index 757e5a2..5c640c6 100644 --- a/diffyscan/utils/constants.py +++ b/diffyscan/utils/constants.py @@ -1,4 +1,6 @@ import time +import os +import tempfile DIGEST_DIR = "digest" START_TIME = time.time() @@ -6,3 +8,55 @@ DIFFS_DIR = f"{DIGEST_DIR}/{START_TIME_INT}/diffs" LOGS_PATH = f"{DIGEST_DIR}/{START_TIME_INT}/logs.txt" DEFAULT_CONFIG_PATH = "config.json" +DEFAULT_HARDHAT_CONFIG_PATH = "hardhat_config.js" + +SOLC_DIR = os.path.join(tempfile.gettempdir(), "solc_builds") + +# fmt: off +OPCODES = { + 0x00: 'STOP', 0x01: 'ADD', 0x02: 'MUL', 0x03: 'SUB', 0x04: 'DIV', 0x05: 'SDIV', + 0x06: 'MOD', 0x07: 'SMOD', 0x08: 'ADDMOD', 0x09: 'MULMOD', 0x0A: 'EXP', 0x0B: 'SIGNEXTEND', + 0x10: 'LT', 0x11: 'GT', 0x12: 'SLT', 0x13: 'SGT', 0x14: 'EQ', 0x15: 'ISZERO', 0x16: 'AND', + 0x17: 'OR', 0x18: 'XOR', 0x19: 'NOT', 0x1A: 'BYTE', 0x1B: 'SHL', 0x1C: 'SHR', 0x1D: 'SAR', + 0x20: 'SHA3', + 0x30: 'ADDRESS', 0x31: 'BALANCE', 0x32: 'ORIGIN', 0x33: 'CALLER', + 0x34: 'CALLVALUE', 0x35: 'CALLDATALOAD', 0x36: 'CALLDATASIZE', 0x37: 'CALLDATACOPY', + 0x38: 'CODESIZE', 0x39: 'CODECOPY', 0x3A: 'GASPRICE', 0x3B: 'EXTCODESIZE', + 0x3C: 'EXTCODECOPY', 0x3D: 'RETURNDATASIZE', 0x3E: 'RETURNDATACOPY', 0x3F: 'EXTCODEHASH', + 0x40: 'BLOCKHASH', 0x41: 'COINBASE', 0x42: 'TIMESTAMP', 0x43: 'NUMBER', + 0x44: 'PREVRANDAO', 0x45: 'GASLIMIT', 0x46: 'CHAINID', 0x47: 'SELFBALANCE', 0x48: 'BASEFEE', + 0x50: 'POP', 0x51: 'MLOAD', 0x52: 'MSTORE', 0x53: 'MSTORE8', + 0x54: 'SLOAD', 0x55: 'SSTORE', 0x56: 'JUMP', 0x57: 'JUMPI', + 0x58: 'PC', 0x59: 'MSIZE', 0x5A: 'GAS', 0x5B: 'JUMPDEST', + 0x5F: 'PUSH0', 0x60: 'PUSH1', 0x61: 'PUSH2', 0x62: 'PUSH3', 0x63: 'PUSH4', 0x64: 'PUSH5', + 0x65: 'PUSH6', 0x66: 'PUSH7', 0x67: 'PUSH8', 0x68: 'PUSH9', 0x69: 'PUSH10', 0x6A: 'PUSH11', + 0x6B: 'PUSH12', 0x6C: 'PUSH13', 0x6D: 'PUSH14', 0x6E: 'PUSH15', 0x6F: 'PUSH16', 0x70: 'PUSH17', + 0x71: 'PUSH18', 0x72: 'PUSH19', 0x73: 'PUSH20', 0x74: 'PUSH21', 0x75: 'PUSH22', 0x76: 'PUSH23', + 0x77: 'PUSH24', 0x78: 'PUSH25', 0x79: 'PUSH26', 0x7A: 'PUSH27', 0x7B: 'PUSH28', 0x7C: 'PUSH29', + 0x7D: 'PUSH30', 0x7E: 'PUSH31', 0x7F: 'PUSH32', + 0x80: 'DUP1', 0x81: 'DUP2', 0x82: 'DUP3', 0x83: 'DUP4', + 0x84: 'DUP5', 0x85: 'DUP6', 0x86: 'DUP7', 0x87: 'DUP8', + 0x88: 'DUP9', 0x89: 'DUP10', 0x8A: 'DUP11', 0x8B: 'DUP12', + 0x8C: 'DUP13', 0x8D: 'DUP14', 0x8E: 'DUP15', 0x8F: 'DUP16', + 0x90: 'SWAP1', 0x91: 'SWAP2', 0x92: 'SWAP3', 0x93: 'SWAP4', + 0x94: 'SWAP5', 0x95: 'SWAP6', 0x96: 'SWAP7', 0x97: 'SWAP8', + 0x98: 'SWAP9', 0x99: 'SWAP10', 0x9A: 'SWAP11', 0x9B: 'SWAP12', + 0x9C: 'SWAP13', 0x9D: 'SWAP14', 0x9E: 'SWAP15', 0x9F: 'SWAP16', + 0xA0: 'LOG0', 0xA1: 'LOG1', 0xA2: 'LOG2', 0xA3: 'LOG3', 0xA4: 'LOG4', + 0xF0: 'CREATE', 0xF1: 'CALL', 0xF2: 'CALLCODE', 0xF3: 'RETURN', 0xF4: 'DELEGATECALL', + 0xF5: 'CREATE2', 0xFA: 'STATICCALL', 0xFD: 'REVERT', 0xFE: 'INVALID', 0xFF: 'SELFDESTRUCT', +} +# fmt: on + + +def get_key_from_value(dictinary: dict, value: str): + keys = [ + dict_key for dict_key, dict_value in dictinary.items() if dict_value == value + ] + if keys: + return keys[0] + return None + + +PUSH0 = get_key_from_value(OPCODES, "PUSH0") +PUSH32 = get_key_from_value(OPCODES, "PUSH32") diff --git a/diffyscan/utils/custom_exceptions.py b/diffyscan/utils/custom_exceptions.py new file mode 100644 index 0000000..5b1c7bc --- /dev/null +++ b/diffyscan/utils/custom_exceptions.py @@ -0,0 +1,56 @@ +from .logger import logger + + +class BaseCustomException(Exception): + def __init__(self, message: str): + super().__init__(message) + self.message = message + + +class CompileError(BaseCustomException): + def __init__(self, reason: str): + super().__init__(f"Failed to compile contract: {reason}") + + +class NodeError(BaseCustomException): + def __init__(self, reason: str): + super().__init__(f"Failed to receive bytecode from node: {reason}") + + +class CalldataError(BaseCustomException): + def __init__(self, reason: str): + super().__init__(f"Failed to get calldata: {reason}") + + +class EncoderError(BaseCustomException): + def __init__(self, reason: str): + super().__init__(f"Failed to encode calldata arguments: {reason}") + + +class HardhatError(BaseCustomException): + def __init__(self, reason: str): + super().__init__(f"Failed to start Hardhat: {reason}") + + +class ExplorerError(BaseCustomException): + def __init__(self, reason: str): + super().__init__(f"Failed to communicate with Blockchain explorer: {reason}") + + +class BinVerifierError(BaseCustomException): + def __init__(self, reason: str): + super().__init__(f"Failed in binary comparison: {reason}") + + +class ExceptionHandler: + raise_exception = True + + @staticmethod + def initialize(raise_exception: bool) -> None: + ExceptionHandler.raise_exception = raise_exception + + @staticmethod + def raise_exception_or_log(custom_exception: BaseCustomException) -> None: + if ExceptionHandler.raise_exception: + raise custom_exception + logger.error(str(custom_exception)) diff --git a/diffyscan/utils/custom_types.py b/diffyscan/utils/custom_types.py new file mode 100644 index 0000000..9e79acd --- /dev/null +++ b/diffyscan/utils/custom_types.py @@ -0,0 +1,18 @@ +from typing import TypedDict + + +class BinartConfig(TypedDict): + hardhat_config_name: str + constructor_calldata: set + constructor_args: set + + +class Config(TypedDict): + contracts: dict[str, str] + network: str + github_repo: str + dependencies: dict[str, str] + explorer_hostname: str + explorer_token_env_var: str + bytecode_comparison: BinartConfig + fail_on_comparison_error: bool diff --git a/diffyscan/utils/encoder.py b/diffyscan/utils/encoder.py new file mode 100644 index 0000000..a60c237 --- /dev/null +++ b/diffyscan/utils/encoder.py @@ -0,0 +1,126 @@ +from .custom_exceptions import EncoderError + + +def to_hex_with_alignment(value: int) -> str: + return format(value, "064x") + + +def encode_address(address: str) -> str: + number = int(address, 16) + return to_hex_with_alignment(number) + + +def encode_bytes32(data: str) -> str: + return data.replace("0x", "") + + +def encode_bytes(data: str) -> str: + bytes_str = data.lstrip("0x") + if not bytes_str: + return to_hex_with_alignment(0) + + # Calculate the length of the hex-encoded 32-bytes padded data + # since EVM uses 32-byte (256-bit) words + count_of_bytes_from_hex = len(bytes_str) // 2 + encoded_length = 0 + if count_of_bytes_from_hex > 0: + encoded_length = ((len(bytes_str) - 1) // 64 + 1) * 64 + bytes_str += "0" * (encoded_length - len(bytes_str)) + return to_hex_with_alignment(count_of_bytes_from_hex) + bytes_str + + +def encode_tuple(types: list, args: list): + args_length = len(types) + encoded_offsets = "" + encoded_data = "" + for arg_index in range(args_length): + arg_type = types[arg_index] + arg_value = args[arg_index] + if arg_type == "address": + encoded_offsets += encode_address(arg_value) + elif arg_type == "uint256" or arg_type == "bool" or arg_type == "uint8": + encoded_offsets += to_hex_with_alignment(arg_value) + elif arg_type == "bytes32": + encoded_offsets += encode_bytes32(arg_value) + elif arg_type == "address[]" and not arg_value: + encoded_data += to_hex_with_alignment(0) + offset = to_hex_with_alignment((arg_index + args_length) * 32) + encoded_offsets += offset + else: + raise EncoderError( + f"Unknown constructor argument type '{arg_type}' in tuple" + ) + return encoded_offsets + encoded_data + + +def encode_dynamic_type(arg_value: str, argument_index: int): + offset_to_start_of_data_part = to_hex_with_alignment((argument_index + 1) * 32) + encoded_value = encode_bytes(arg_value) + return offset_to_start_of_data_part, encoded_value + + +def encode_string(arg_length: int, compl_data: list, arg_value: str): + argument_index = arg_length + len(compl_data) + encoded_value = arg_value.encode("utf-8") + offset_to_start_of_data_part = to_hex_with_alignment(argument_index * 32) + encoded_value_length = to_hex_with_alignment(len(encoded_value)) + return ( + offset_to_start_of_data_part, + encoded_value_length, + encoded_value.hex().ljust(64, "0"), + ) + + +def encode_constructor_arguments(constructor_abi: list, constructor_config_args: list): + # see https://docs.soliditylang.org/en/develop/abi-spec.html#contract-abi-specification + # transferred from here: + # https://github.com/lidofinance/lido-dao/blob/master/bytecode-verificator/bytecode_verificator.sh#L369-L405 + arg_length = len(constructor_abi) + + constructor_calldata = "" + compl_data = [] + try: + for argument_index in range(arg_length): + arg_type = constructor_abi[argument_index]["type"] + arg_value = constructor_config_args[argument_index] + if arg_type == "address": + constructor_calldata += encode_address(arg_value) + elif arg_type == "uint256" or arg_type == "bool" or arg_type == "uint8": + constructor_calldata += to_hex_with_alignment(arg_value) + elif arg_type == "bytes32": + constructor_calldata += encode_bytes32(arg_value) + elif arg_type == "bytes" or arg_type.endswith("[]"): + offset_to_start_of_data_part, encoded_value = encode_dynamic_type( + arg_value, argument_index + ) + constructor_calldata += offset_to_start_of_data_part + compl_data.append(encoded_value) + elif arg_type == "string": + offset_to_start_of_data_part, encoded_value_length, encoded_value = ( + encode_string(arg_length, compl_data, arg_value) + ) + constructor_calldata += offset_to_start_of_data_part + compl_data.append(encoded_value_length) + compl_data.append(encoded_value) + elif arg_type == "tuple": + args_tuple_types = [ + component["type"] + for component in constructor_abi[argument_index]["components"] + ] + if all(arg == "address[]" for arg in args_tuple_types): + argument_index = len(constructor_calldata) // 64 + offset_to_start_of_data_part = to_hex_with_alignment( + (argument_index + 1) * 32 + ) + constructor_calldata += offset_to_start_of_data_part + compl_data.append(encode_tuple(args_tuple_types, arg_value)) + else: + constructor_calldata += encode_tuple(args_tuple_types, arg_value) + else: + raise EncoderError(f"Unknown constructor argument type: {arg_type}") + except Exception as e: + raise EncoderError(e) from None + for offset_to_start_of_data_part in compl_data: + constructor_calldata += offset_to_start_of_data_part + + return constructor_calldata diff --git a/diffyscan/utils/explorer.py b/diffyscan/utils/explorer.py index e22213d..d0e8669 100644 --- a/diffyscan/utils/explorer.py +++ b/diffyscan/utils/explorer.py @@ -1,9 +1,18 @@ import json import sys +import os from .common import fetch from .logger import logger - +from .compiler import ( + get_solc_native_platform_from_os, + get_compiler_info, + prepare_compiler, + compile_contracts, + get_target_compiled_contract, +) +from .constants import SOLC_DIR +from .custom_exceptions import ExplorerError def _errorNoSourceCodeAndExit(address): logger.error("source code is not verified or an EOA address", address) @@ -15,36 +24,53 @@ def _get_contract_from_etherscan(token, etherscan_hostname, contract): if token is not None: etherscan_link = f"{etherscan_link}&apikey={token}" - response = fetch(etherscan_link) + response = fetch(etherscan_link).json() if response["message"] == "NOTOK": - logger.error("Failed", response["result"]) - logger.error("Status", response.status_code) - logger.error("Response", response.text) - sys.exit(1) + raise ExplorerError(f'Received bad response: {response["result"]}') - data = response["result"][0] - if "ContractName" not in data: + result = response["result"][0] + if "ContractName" not in result: _errorNoSourceCodeAndExit(contract) - contract_name = data["ContractName"] - - json_escaped = data["SourceCode"].startswith("{{") - source_files = ( - json.loads(data["SourceCode"][1:-1])["sources"].items() - if json_escaped - else json.loads(data["SourceCode"]).items() - ) - - return (contract_name, source_files) - - + solc_input = result["SourceCode"] + contract = { + "name": result["ContractName"], + "compiler": result["CompilerVersion"], + } + if solc_input.startswith("{{"): + contract["solcInput"] = json.loads(solc_input[1:-1]) + else: + contract["solcInput":] = { + "language": "Solidity", + "sources": {result["ContractName"]: {"content": solc_input}}, + "settings": { + "optimizer": { + "enabled": result["OptimizationUsed"] == "1", + "runs": int(result["Runs"]), + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + ], + "": ["ast"], + } + }, + }, + } + return contract + def _get_contract_from_zksync(zksync_explorer_hostname, contract): zksync_explorer_link = ( f"https://{zksync_explorer_hostname}/contract_verification/info/{contract}" ) - response = fetch(zksync_explorer_link) + response = fetch(zksync_explorer_link).json() if not response.get("verifiedAt"): logger.error("Status", response.status_code) @@ -55,16 +81,17 @@ def _get_contract_from_zksync(zksync_explorer_hostname, contract): if "contractName" not in data: _errorNoSourceCodeAndExit(contract) - contract_name = data["contractName"].split(":")[-1] - source_files = data["sourceCode"]["sources"].items() - - return (contract_name, source_files) + contract = { + "name": data["ContractName"], + "sources": json.loads(data["sourceCode"]["sources"]), + "compiler": data["CompilerVersion"], + } + return contract def _get_contract_from_mantle(mantle_explorer_hostname, contract): etherscan_link = f"https://{mantle_explorer_hostname}/api?module=contract&action=getsourcecode&address={contract}" - - response = fetch(etherscan_link) + response = fetch(etherscan_link).json() data = response["result"][0] if "ContractName" not in data: @@ -74,32 +101,87 @@ def _get_contract_from_mantle(mantle_explorer_hostname, contract): for entry in data.get("AdditionalSources", []): source_files.append((entry["Filename"], {"content": entry["SourceCode"]})) - return (data["ContractName"], source_files) + contract = { + "name": data["ContractName"], + "sources": json.loads(data["sourceCode"]["sources"]), + "compiler": data["CompilerVersion"], + } + return contract def _get_contract_from_mode(mode_explorer_hostname, contract): mode_explorer_link = ( f"https://{mode_explorer_hostname}/api/v2/smart-contracts/{contract}" ) - response = fetch(mode_explorer_link) + response = fetch(mode_explorer_link).json() if "name" not in response: _errorNoSourceCodeAndExit(contract) - source_files = [(response["file_path"], {"content": response["source_code"]})] + source_files = {response["file_path"]: {"content": response["source_code"]}} + for entry in response.get("additional_sources", []): - source_files.append((entry["file_path"], {"content": entry["source_code"]})) + source_files[entry["file_path"]] = {"content": entry["source_code"]} - return (response["name"], source_files) + contract = { + "name": response["name"], + "solcInput": {"language": "Solidity", "sources": source_files}, + "compiler": response["compiler_version"], + } + return contract -def get_contract_from_explorer(token, explorer_hostname, contract): +def get_contract_from_explorer( + token, explorer_hostname, contract_address, contract_name_from_config +): + result = {} if explorer_hostname.startswith("zksync"): - return _get_contract_from_zksync(explorer_hostname, contract) - if explorer_hostname.endswith("mantle.xyz"): - return _get_contract_from_mantle(explorer_hostname, contract) - if explorer_hostname.endswith("lineascan.build"): - return _get_contract_from_etherscan(None, explorer_hostname, contract) - if explorer_hostname.endswith("mode.network"): - return _get_contract_from_mode(explorer_hostname, contract) - return _get_contract_from_etherscan(token, explorer_hostname, contract) + result = _get_contract_from_zksync(explorer_hostname, contract_address) + elif explorer_hostname.endswith("mantle.xyz"): + result = _get_contract_from_mantle(explorer_hostname, contract_address) + elif explorer_hostname.endswith("lineascan.build"): + result = _get_contract_from_etherscan(None, explorer_hostname, contract_address) + elif explorer_hostname.endswith("mode.network"): + result = _get_contract_from_mode(explorer_hostname, contract_address) + else: + result = _get_contract_from_etherscan( + token, explorer_hostname, contract_address + ) + + contract_name_from_etherscan = result["name"] + if contract_name_from_etherscan != contract_name_from_config: + raise ExplorerError( + f"Contract name in config does not match with Blockchain explorer {contract_address}: \ + {contract_name_from_config} != {contract_name_from_etherscan}", + ) + + return result + +def compile_contract_from_explorer(contract_code): + required_platform = get_solc_native_platform_from_os() + build_name = contract_code["compiler"][1:] + build_info = get_compiler_info(required_platform, build_name) + compiler_path = os.path.join(SOLC_DIR, build_info['path']) + + is_compiler_already_prepared = os.path.isfile(compiler_path) + + if not is_compiler_already_prepared: + prepare_compiler(required_platform, build_info, compiler_path) + + input_settings = json.dumps(contract_code["solcInput"]) + compiled_contracts = compile_contracts(compiler_path, input_settings)['contracts'].values() + + target_contract_name = contract_code['name'] + return get_target_compiled_contract(compiled_contracts, target_contract_name) + +def parse_compiled_contract(target_compiled_contract): + contract_creation_code_without_calldata = f'0x{target_compiled_contract['evm']['bytecode']['object']}' + deployed_bytecode = f'0x{target_compiled_contract['evm']['deployedBytecode']['object']}' + immutables = {} + if ('immutableReferences' in target_compiled_contract['evm']['deployedBytecode']): + immutable_references = target_compiled_contract['evm']['deployedBytecode']['immutableReferences'] + for refs in immutable_references.values(): + for ref in refs: + immutables[ref['start']] = ref['length'] + + return contract_creation_code_without_calldata, deployed_bytecode, immutables diff --git a/diffyscan/utils/github.py b/diffyscan/utils/github.py index 97d8128..b202da3 100644 --- a/diffyscan/utils/github.py +++ b/diffyscan/utils/github.py @@ -18,7 +18,7 @@ def get_file_from_github(github_api_token, dependency_repo, path_to_file, dep_na github_data = fetch( github_api_url, headers={"Authorization": f"token {github_api_token}"} - ) + ).json() if not github_data: logger.error("No github data for", github_api_url) @@ -66,7 +66,7 @@ def _get_direct_file( ) response = fetch( github_api_url, headers={"Authorization": f"token {github_api_token}"} - ) + ).json() if response is None: return None @@ -98,7 +98,7 @@ def _recursive_search( ) github_data = fetch( github_api_url, headers={"Authorization": f"token {github_api_token}"} - ) + ).json() if github_data and isinstance(github_data, dict) and "content" in github_data: return base64.b64decode(github_data["content"]).decode() @@ -106,7 +106,7 @@ def _recursive_search( github_api_url = get_github_api_url(user_slash_repo, relative_path, None, commit) github_data = fetch( github_api_url, headers={"Authorization": f"token {github_api_token}"} - ) + ).json() if github_data and isinstance(github_data, list): directories = [item["path"] for item in github_data if item["type"] == "dir"] diff --git a/diffyscan/utils/hardhat.py b/diffyscan/utils/hardhat.py new file mode 100644 index 0000000..e98e536 --- /dev/null +++ b/diffyscan/utils/hardhat.py @@ -0,0 +1,91 @@ +import os +import subprocess +import signal +import time + +from urllib.parse import urlparse +from .logger import logger +from .custom_exceptions import HardhatError + + +class Hardhat: + sub_process = None + TIMEOUT_FOR_CONNECT_SEC = 10 + ATTEMPTS_FOR_CONNECT = 5 + + def start( + self, + hardhat_config_path: str, + local_rpc_url: str, + remote_rpc_url: str, + ): + parsed_url = urlparse(local_rpc_url) + if not parsed_url.port or not parsed_url.hostname: + raise HardhatError(f"Invalid LOCAL_RPC_URL: '{local_rpc_url}'") + + if not os.path.isfile(hardhat_config_path): + raise HardhatError( + f"Failed to find Hardhat config by path '{hardhat_config_path}'" + ) + + local_node_command = ( + f"npx hardhat node --hostname {parsed_url.hostname} " + f"--port {parsed_url.port} " + f"--config {hardhat_config_path} " + f"--fork {remote_rpc_url}" + ) + + logger.info(f'Trying to start Hardhat: "{local_node_command}"') + is_port_used = self._is_port_in_use_(parsed_url) + if is_port_used: + answer = input( + f'Port {parsed_url.port} is busy. Kill the app instance occupying the port? write "yes": ' + ) + if answer.lower() == "yes": + return_code = subprocess.call( + f"exec npx kill-port {parsed_url.port}", shell=True + ) + if return_code == 0: + is_port_used = self._is_port_in_use_(parsed_url) + if is_port_used: + raise HardhatError(f"{parsed_url.netloc} is busy") + self.sub_process = subprocess.Popen( + "exec " + local_node_command, + shell=True, + stdout=subprocess.DEVNULL, + stderr=subprocess.PIPE, + ) + try: + _, errs = self.sub_process.communicate(timeout=self.TIMEOUT_FOR_CONNECT_SEC) + if errs: + raise HardhatError(f"{errs.decode()}") + except subprocess.TimeoutExpired: + self._handle_timeout(parsed_url) + + def stop(self): + if self.sub_process is not None and self.sub_process.poll() is None: + os.kill(self.sub_process.pid, signal.SIGTERM) + logger.info(f"Hardhat stopped, PID {self.sub_process.pid}") + + def _is_port_in_use_(self, parsed_url) -> bool: + import socket + + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + return s.connect_ex((parsed_url.hostname, parsed_url.port)) == 0 + + def _handle_timeout(self, parsed_url): + attempt = 1 + logger.info("The connection to Hardhat is taking longer than expected") + + while attempt <= self.ATTEMPTS_FOR_CONNECT: + logger.info(f"Reconnecting to Hardhat, attempt #{attempt}") + if self._is_port_in_use_(parsed_url): + logger.okay(f"Hardhat successfully started, PID {self.sub_process.pid}") + return + attempt += 1 + time.sleep(self.TIMEOUT_FOR_CONNECT_SEC) + + raise HardhatError("Something is wrong") + + +hardhat = Hardhat() diff --git a/diffyscan/utils/logger.py b/diffyscan/utils/logger.py index 256ef90..ca55aae 100644 --- a/diffyscan/utils/logger.py +++ b/diffyscan/utils/logger.py @@ -138,3 +138,27 @@ def divider(self): logger = Logger(LOGS_PATH) + + +def to_hex(index, padStart=2): + return f"{index:0{padStart}X}" + + +def red(text): + return f"\u001b[31m{text}\x1b[0m" + + +def bgRed(text): + return f"\u001b[37;41m{text}\x1b[0m" + + +def green(text): + return f"\u001b[32m{text}\x1b[0m" + + +def bgGreen(text): + return f"\u001b[37;42m{text}\x1b[0m" + + +def bgYellow(text): + return f"\u001b[37;43m{text}\x1b[0m" diff --git a/diffyscan/utils/node_handler.py b/diffyscan/utils/node_handler.py new file mode 100644 index 0000000..d1d0f05 --- /dev/null +++ b/diffyscan/utils/node_handler.py @@ -0,0 +1,93 @@ +import json + +from .common import pull +from .logger import logger +from .custom_exceptions import NodeError + + +def get_bytecode_from_node(contract_address, rpc_url): + logger.info(f'Receiving the bytecode from "{rpc_url}" ...') + + payload = json.dumps( + { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getCode", + "params": [contract_address, "latest"], + } + ) + + sources_url_response_in_json = pull(rpc_url, payload).json() + if ( + "result" not in sources_url_response_in_json + or sources_url_response_in_json["result"] == "0x" + ): + raise NodeError(f"Received bad response: {sources_url_response_in_json}") + + logger.okay(f"Bytecode was successfully received") + return sources_url_response_in_json["result"] + + +def get_account(rpc_url): + logger.info(f'Receiving the account from "{rpc_url}" ...') + + payload = json.dumps( + {"id": 42, "jsonrpc": "2.0", "method": "eth_accounts", "params": []} + ) + + account_address_response = pull(rpc_url, payload).json() + + if "result" not in account_address_response: + raise NodeError(f"The deployer account isn't set") + + logger.okay(f"The account was successfully received") + + return account_address_response["result"][0] + + +def deploy_contract(rpc_url, deployer, data): + logger.info(f'Trying to deploy transaction to "{rpc_url}" ...') + + payload_sendTransaction = json.dumps( + { + "jsonrpc": "2.0", + "method": "eth_sendTransaction", + "params": [{"from": deployer, "gas": 9000000, "input": data}], + "id": 1, + } + ) + response_sendTransaction = pull(rpc_url, payload_sendTransaction).json() + + if "error" in response_sendTransaction: + raise NodeError(response_sendTransaction["error"]["message"]) + + logger.okay(f"Transaction was successfully deployed") + + tx_hash = response_sendTransaction["result"] + + payload_getTransactionReceipt = json.dumps( + { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getTransactionReceipt", + "params": [tx_hash], + } + ) + response_getTransactionReceipt = pull(rpc_url, payload_getTransactionReceipt).json() + + if ( + "result" not in response_getTransactionReceipt + or "contractAddress" not in response_getTransactionReceipt["result"] + or "status" not in response_getTransactionReceipt["result"] + ): + raise NodeError(f"Failed to received transaction receipt") + + if response_getTransactionReceipt["result"]["status"] != "0x1": + raise NodeError( + f"Failed to received transaction receipt. \ + Transaction has been reverted (status 0x0). Input missmatch?", + ) + + contract_address = response_getTransactionReceipt["result"]["contractAddress"] + + return contract_address diff --git a/diffyscan/utils/types.py b/diffyscan/utils/types.py deleted file mode 100644 index 7a3d570..0000000 --- a/diffyscan/utils/types.py +++ /dev/null @@ -1,8 +0,0 @@ -from typing import TypedDict - - -class Config(TypedDict): - contracts: dict[str, str] - network: str - github_repo: str - dependencies: dict[str, str] diff --git a/hardhat_configs/holesky_hardhat_config.js b/hardhat_configs/holesky_hardhat_config.js new file mode 100644 index 0000000..41523f5 --- /dev/null +++ b/hardhat_configs/holesky_hardhat_config.js @@ -0,0 +1,10 @@ +module.exports = { + solidity: "0.8.9", + networks: { + hardhat: { + chainId: 17000, + blockGasLimit: 92000000, + hardfork: "cancun", + } + }, +}; diff --git a/hardhat_configs/sepolia_hardhat_config.js b/hardhat_configs/sepolia_hardhat_config.js new file mode 100644 index 0000000..435644f --- /dev/null +++ b/hardhat_configs/sepolia_hardhat_config.js @@ -0,0 +1,10 @@ +module.exports = { + solidity: "0.8.9", + networks: { + hardhat: { + chainId: 11155111, + blockGasLimit: 92000000, + hardfork: "cancun", + } + }, +}; diff --git a/hardhat_configs/sepolia_optimizm_hardhat_config.js b/hardhat_configs/sepolia_optimizm_hardhat_config.js new file mode 100644 index 0000000..de60c95 --- /dev/null +++ b/hardhat_configs/sepolia_optimizm_hardhat_config.js @@ -0,0 +1,10 @@ +module.exports = { + solidity: "0.8.9", + networks: { + hardhat: { + chainId: 11155420, + blockGasLimit: 92000000, + hardfork: "cancun", + } + }, +}; diff --git a/package-lock.json b/package-lock.json index 2a945af..aca6d6c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,21 +4,2488 @@ "requires": true, "packages": { "": { + "dependencies": { + "hardhat": "^2.22.7", + "kill-port": "^2.0.1" + }, "devDependencies": { + "husky": "^9.1.6", "prettier": "^3.3.0", "prettier-plugin-solidity": "^1.3.1" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ] + }, + "node_modules/@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@metamask/eth-sig-util": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz", + "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", + "dependencies": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^6.2.1", + "ethjs-util": "^0.1.6", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@noble/hashes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@nomicfoundation/edr": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.6.1.tgz", + "integrity": "sha512-ILlhHzUgVQ+5kpZ35fxMI1xwaqxfZV8V8l+pKo1RZHvLKf80Azvq1OLg1RfxstLIA2QB+KBpch9QfPiD5fBpdw==", + "dependencies": { + "@nomicfoundation/edr-darwin-arm64": "0.6.1", + "@nomicfoundation/edr-darwin-x64": "0.6.1", + "@nomicfoundation/edr-linux-arm64-gnu": "0.6.1", + "@nomicfoundation/edr-linux-arm64-musl": "0.6.1", + "@nomicfoundation/edr-linux-x64-gnu": "0.6.1", + "@nomicfoundation/edr-linux-x64-musl": "0.6.1", + "@nomicfoundation/edr-win32-x64-msvc": "0.6.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-darwin-arm64": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.6.1.tgz", + "integrity": "sha512-ncZs0yRoxbiJB+sg7w2K6BLgMnAgOK/IcGuuZaNHKwiMHk19Kn2JDl+5fUOzkIGNpaCf8uvoEb2q6K7212KjQA==", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-darwin-x64": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.6.1.tgz", + "integrity": "sha512-Akubo27DS0D921aaApD+IRlv1niLiARWPrUDDBOKjCYKGVrJUKmAdH14qBzZwHBcQBhyVMXgxlSiyIgiqIHHjA==", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.6.1.tgz", + "integrity": "sha512-t+Lb5pyWYe4xJs9dA1jdhUOLxmgzFAa/SSmDZBC5vbCiDic5brUfgtPL//uMI8DKElXm9RSsRwXB5x/6+UhFEw==", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-musl": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.6.1.tgz", + "integrity": "sha512-dxv2wtnb1vE7MLQfy7mmXObhX585gBGB+kJZRj+K5z+0uVNM1Xep0kH+XpuGHAT0C/w/7YEWXrrsjTpxadcpnw==", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-gnu": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.6.1.tgz", + "integrity": "sha512-8XwZRYCcChHNrdWPdsyE8lotJ/0702hKMA7tueo5T2SSK8YRLAq8tbshDPxzrNKztP1I+SbH2Y+sucKCscJOUg==", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-musl": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.6.1.tgz", + "integrity": "sha512-aySKfZtDxaD365qkEVqqMXatDa0tsq3gVGUz18lvy+14lGCzEAPIQNo2lJAM26k0w3HbOuIFCzI2FbksAi245A==", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-win32-x64-msvc": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.6.1.tgz", + "integrity": "sha512-yNBdEjC6fi3dUizgTNRNcgs4y7CnGxkyC4bJkGcwZzJ7Hb88/ODay+RWcVpwyZNobzsiDc9zrKs2h3+4j/0FLQ==", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/ethereumjs-common": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.4.tgz", + "integrity": "sha512-9Rgb658lcWsjiicr5GzNCjI1llow/7r0k50dLL95OJ+6iZJcVbi15r3Y0xh2cIO+zgX0WIHcbzIu6FeQf9KPrg==", + "dependencies": { + "@nomicfoundation/ethereumjs-util": "9.0.4" + } + }, + "node_modules/@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.4.tgz", + "integrity": "sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw==", + "bin": { + "rlp": "bin/rlp.cjs" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@nomicfoundation/ethereumjs-tx": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.4.tgz", + "integrity": "sha512-Xjv8wAKJGMrP1f0n2PeyfFCCojHd7iS3s/Ab7qzF1S64kxZ8Z22LCMynArYsVqiFx6rzYy548HNVEyI+AYN/kw==", + "dependencies": { + "@nomicfoundation/ethereumjs-common": "4.0.4", + "@nomicfoundation/ethereumjs-rlp": "5.0.4", + "@nomicfoundation/ethereumjs-util": "9.0.4", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "c-kzg": "^2.1.2" + }, + "peerDependenciesMeta": { + "c-kzg": { + "optional": true + } + } + }, + "node_modules/@nomicfoundation/ethereumjs-tx/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@nomicfoundation/ethereumjs-util": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.4.tgz", + "integrity": "sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q==", + "dependencies": { + "@nomicfoundation/ethereumjs-rlp": "5.0.4", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "c-kzg": "^2.1.2" + }, + "peerDependenciesMeta": { + "c-kzg": { + "optional": true + } + } + }, + "node_modules/@nomicfoundation/ethereumjs-util/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.2.tgz", + "integrity": "sha512-q4n32/FNKIhQ3zQGGw5CvPF6GTvDCpYwIf7bEY/dZTZbgfDsHyjJwURxUJf3VQuuJj+fDIFl4+KkBVbw4Ef6jA==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "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==", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/@scure/bip39": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/@sentry/core": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", + "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/hub": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", + "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", + "dependencies": { + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/minimal": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", + "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/node": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.30.0.tgz", + "integrity": "sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==", + "dependencies": { + "@sentry/core": "5.30.0", + "@sentry/hub": "5.30.0", + "@sentry/tracing": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/tracing": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.30.0.tgz", + "integrity": "sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==", + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", + "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==", + "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==", + "dependencies": { + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@solidity-parser/parser": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.18.0.tgz", + "integrity": "sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA==", + "dev": true + }, + "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==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==" + }, + "node_modules/@types/node": { + "version": "22.6.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.6.1.tgz", + "integrity": "sha512-V48tCfcKb/e6cVUigLAaJDAILdMP0fUW6BidkPK4GpGjXcfbnoHasCZDwz3N3yVt5we2RHm4XTQCpv0KJz9zqw==", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "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==", + "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==", + "dependencies": { + "@types/node": "*" + } + }, + "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==", + "engines": { + "node": ">=0.3.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "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==", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "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==", + "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==", + "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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "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==" + }, + "node_modules/base-x": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.10.tgz", + "integrity": "sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "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==", + "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==" + }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, + "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==", + "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/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "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==", + "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/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==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/boxen/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==" + }, + "node_modules/boxen/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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/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==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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==", + "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==" + }, + "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==" + }, + "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==", + "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==", + "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==", + "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==" + }, + "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==" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chokidar": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", + "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "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==" + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "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==", + "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==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "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==" + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "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==", + "engines": { + "node": ">= 0.6" + } + }, + "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==", + "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==", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "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==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "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==" + }, + "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==", + "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==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "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==", + "dependencies": { + "@noble/hashes": "1.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" + } + }, + "node_modules/ethereumjs-abi": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", + "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", + "dependencies": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + } + }, + "node_modules/ethereumjs-abi/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dependencies": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + }, + "node_modules/ethereumjs-util/node_modules/@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/ethereumjs-util/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "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==", + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "dependencies": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "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==", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "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==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "bin": { + "flat": "cli.js" + } + }, + "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==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/fp-ts": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", + "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==" + }, + "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==", + "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==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "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==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-them-args": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/get-them-args/-/get-them-args-1.3.2.tgz", + "integrity": "sha512-LRn8Jlk+DwZE4GTlDbT3Hikd1wSHgLMme/+7ddlqKd7ldwR6LjJgTVWzBnR01wnYGe4KgrXjg287RaI22UHmAw==" + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "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==" + }, + "node_modules/hardhat": { + "version": "2.22.12", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.12.tgz", + "integrity": "sha512-yok65M+LsOeTBHQsjg//QreGCyrsaNmeLVzhTFqlOvZ4ZE5y69N0wRxH1b2BC9dGK8S8OPUJMNiL9X0RAvbm8w==", + "dependencies": { + "@ethersproject/abi": "^5.1.2", + "@metamask/eth-sig-util": "^4.0.0", + "@nomicfoundation/edr": "^0.6.1", + "@nomicfoundation/ethereumjs-common": "4.0.4", + "@nomicfoundation/ethereumjs-tx": "5.0.4", + "@nomicfoundation/ethereumjs-util": "9.0.4", + "@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", + "chalk": "^2.4.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", + "ethereumjs-abi": "^0.6.8", + "find-up": "^2.1.0", + "fp-ts": "1.19.3", + "fs-extra": "^7.0.1", + "glob": "7.2.0", + "immutable": "^4.0.0-rc.12", + "io-ts": "1.10.4", + "json-stream-stringify": "^3.1.4", + "keccak": "^3.0.2", + "lodash": "^4.17.11", + "mnemonist": "^0.38.0", + "mocha": "^10.0.0", + "p-map": "^4.0.0", + "raw-body": "^2.4.1", + "resolve": "1.17.0", + "semver": "^6.3.0", + "solc": "0.8.26", + "source-map-support": "^0.5.13", + "stacktrace-parser": "^0.1.10", + "tsort": "0.0.1", + "undici": "^5.14.0", + "uuid": "^8.3.2", + "ws": "^7.4.6" + }, + "bin": { + "hardhat": "internal/cli/bootstrap.js" + }, + "peerDependencies": { + "ts-node": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/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==", + "engines": { + "node": ">=4" + } + }, + "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==", + "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==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/husky": { + "version": "9.1.6", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.6.tgz", + "integrity": "sha512-sqbjZKK7kf44hfdE94EoX8MZNk0n7HeW37O4YrVGCF4wzgQjp+akPAkfUK5LZ6KuR/6sqeAVuXHji+RzQgOn5A==", + "dev": true, + "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==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/immutable": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", + "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==" + }, + "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==", + "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.", + "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==" + }, + "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==", + "dependencies": { + "fp-ts": "^1.0.0" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "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==", + "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==", + "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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + }, + "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==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-stream-stringify": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-3.1.4.tgz", + "integrity": "sha512-oGoz05ft577LolnXFQHD2CjnXDxXVA5b8lHwfEZgRXQUZeCMo6sObQQRq+NXuHQ3oTeMZHHmmPY2rjVwyqR62A==", + "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==", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keccak": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", + "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/kill-port": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/kill-port/-/kill-port-2.0.1.tgz", + "integrity": "sha512-e0SVOV5jFo0mx8r7bS29maVWp17qGqLBZ5ricNSajON6//kmb7qqqNnml4twNE8Dtj97UQD+gNFOaipS/q1zzQ==", + "dependencies": { + "get-them-args": "1.3.2", + "shell-exec": "1.0.2" + }, + "bin": { + "kill-port": "cli.js" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "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==", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lru_map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==" + }, + "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==", + "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==", + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "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==" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mnemonist": { + "version": "0.38.5", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", + "integrity": "sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==", + "dependencies": { + "obliterator": "^2.0.0" + } + }, + "node_modules/mocha": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz", + "integrity": "sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==", + "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/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "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/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "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", + "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/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "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==", + "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==", + "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==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "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==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "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==" + }, + "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==" + }, + "node_modules/node-gyp-build": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.2.tgz", + "integrity": "sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/obliterator": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", + "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==" + }, + "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==", + "dependencies": { + "wrappy": "1" } }, - "node_modules/@solidity-parser/parser": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.17.0.tgz", - "integrity": "sha512-Nko8R0/kUo391jsEHHxrGM07QFdnPGvlmox4rmH0kNiNAashItAilhy4Mv4pK5gQmW5f4sXAF58fwJbmlkGcVw==", - "dev": true + "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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "engines": { + "node": ">=4" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, "node_modules/prettier": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.0.tgz", - "integrity": "sha512-J9odKxERhCQ10OC2yb93583f6UnYutOeiV5i0zEDS7UGTdUt0u+y8erxl3lBKvwo/JHyyoEdXjwp4dke9oyZ/g==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -31,14 +2498,13 @@ } }, "node_modules/prettier-plugin-solidity": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.3.1.tgz", - "integrity": "sha512-MN4OP5I2gHAzHZG1wcuJl0FsLS3c4Cc5494bbg+6oQWBPuEamjwDvmGfFMZ6NFzsh3Efd9UUxeT7ImgjNH4ozA==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.4.1.tgz", + "integrity": "sha512-Mq8EtfacVZ/0+uDKTtHZGW3Aa7vEbX/BNx63hmVg6YTiTXSiuKP0amj0G6pGwjmLaOfymWh3QgXEZkjQbU8QRg==", "dev": true, "dependencies": { - "@solidity-parser/parser": "^0.17.0", - "semver": "^7.5.4", - "solidity-comments-extractor": "^0.0.8" + "@solidity-parser/parser": "^0.18.0", + "semver": "^7.5.4" }, "engines": { "node": ">=16" @@ -47,10 +2513,10 @@ "prettier": ">=2.3.0" } }, - "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "node_modules/prettier-plugin-solidity/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -59,11 +2525,566 @@ "node": ">=10" } }, - "node_modules/solidity-comments-extractor": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/solidity-comments-extractor/-/solidity-comments-extractor-0.0.8.tgz", - "integrity": "sha512-htM7Vn6LhHreR+EglVMd2s+sZhcXAirB1Zlyrv5zBuTxieCvjfnRpd7iZk75m/u6NOlEyQ94C6TWbBn2cY7w8g==", - "dev": true + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "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==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.1.tgz", + "integrity": "sha512-GkMg9uOTpIWWKbSsgwb5fA4EavTR+SG/PMPoAY8hkhHfEEY0/vqljY+XHqtDf2cr2IJtoNRDbrrEpZUiZCkYRw==", + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "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==", + "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==", + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "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==", + "dependencies": { + "bn.js": "^5.2.0" + }, + "bin": { + "rlp": "bin/rlp" + } + }, + "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==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" + }, + "node_modules/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "hasInstallScript": true, + "dependencies": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "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==", + "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==" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "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==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/shell-exec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/shell-exec/-/shell-exec-1.0.2.tgz", + "integrity": "sha512-jyVd+kU2X+mWKMmGhx4fpWbPsjvD53k9ivqetutVW/BQ+WIZoDoP4d8vUMGezV6saZsiNoW2f9GIhg9Dondohg==" + }, + "node_modules/solc": { + "version": "0.8.26", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.26.tgz", + "integrity": "sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g==", + "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/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" + } + }, + "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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/stacktrace-parser": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", + "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==", + "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==", + "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==", + "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==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", + "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==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "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==", + "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==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/tsort": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", + "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==" + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, + "node_modules/tweetnacl-util": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", + "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==" + }, + "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==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/undici": { + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "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==" + }, + "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==", + "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==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "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==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "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==", + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/workerpool": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==" + }, + "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==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "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==" + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "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 + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "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==", + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 99b33ec..7b30557 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,18 @@ { "devDependencies": { + "husky": "^9.1.6", "prettier": "^3.3.0", "prettier-plugin-solidity": "^1.3.1" + }, + "dependencies": { + "hardhat": "^2.22.7", + "kill-port": "^2.0.1" + }, + "packageManager": "npm@10.8.2", + "engines": { + "node": ">=20.0" + }, + "scripts": { + "prepare": "husky" } }