diff --git a/.github/workflows/app-deploy-preview.yml b/.github/workflows/app-deploy-preview.yml index 791a5298e5..e28ece8b2c 100644 --- a/.github/workflows/app-deploy-preview.yml +++ b/.github/workflows/app-deploy-preview.yml @@ -91,3 +91,4 @@ jobs: default_network_value_for_e2e: "/?network=mainnet" publish_to_allure: true environmentTags: "and not @featureEnv" + \ No newline at end of file diff --git a/README.md b/README.md index 43eabb9129..ade8feeb42 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ This repository is a monorepo consisting of 4 packages: - [API](./packages/api) - a service providing Web API for retrieving structured [zkSync Era](https://zksync.io) blockchain data collected by [Worker](./packages/worker). It connects to the Worker's database to be able to query the collected data. - [App](./packages/app) - a front-end app providing an easy-to-use interface for users to view and inspect transactions, blocks, contracts and more. It makes requests to the [API](./packages/api) to get the data and presents it in a way that's easy to read and understand. +Also the repository contains [integration-test](./packages/integration-tests) package with a set of API and UI tests. Follow this [Readme](./packages/integration-tests/README.md) for more details. + ## 🏛 Architecture The following diagram illustrates how are the block explorer components connected: diff --git a/package.json b/package.json index 0fb2e53abb..66f4518ed2 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,8 @@ "test": "lerna run test", "test:ci": "lerna run test:ci", "test:e2e": "lerna run test:e2e", + "test:integration:ui": "lerna run integration-test:ui", + "test:integration:api": "lerna run integration-test:api", "dev": "lerna run dev", "build": "lerna run build", "start": "lerna run start", diff --git a/packages/app/tests/e2e/testId.json b/packages/app/tests/e2e/testId.json index 1eacc3774b..071e946243 100644 --- a/packages/app/tests/e2e/testId.json +++ b/packages/app/tests/e2e/testId.json @@ -1,35 +1,36 @@ { - "badge": "badge", - "statusBadge": "status-badge", - "blocksNumber": "blocks-number", - "blocksTable": "blocks-table", - "byteCodeDropDown": "bytecode-dropdown", - "contractsAddress": "contracts-address", - "contractVerificationButton": "contract-verification-button", - "direction": "direction", - "initiatorsAddress": "initiators-address", - "fromAddress": "from-address", - "optimizationRadioButtons": "radio-buttons", - "pageTitle": "page-title", - "previousInstructionButton": "previous-instruction-navigation-button", - "showInstructionMetadataButton": "show-instruction-metadata-button", - "nextInstructionButton": "next-instruction-navigation-button", - "traceSearchInput": "trace-search-input", - "tokensIcon": "tokens-icon", - "tokenAddress":"tokenAddress", - "tokenAmount":"token-amount", - "tokenAmountPrice":"token-amount-price", - "transactionsHash": "transactions-hash", - "transactionsMethodName": "transactions-method-name", - "timestamp": "timestamp", - "transactionsTable": "transactions-table", - "latestTransactionsTable": "latest-transaction-table", - "latestBatchesTable": "latest-batches-table", - "tokensTable": "tokens-table", - "toAddress": "to-address", - "transferType": "transfer-type", - "transferFromOrigin": "transfer-from-origin", - "transferToOrigin": "transfer-to-origin", - "transferFromOriginTablet": "transfer-from-origin-tablet", - "transferToOriginTablet": "transfer-to-origin-tablet" -} + "badge": "badge", + "statusBadge": "status-badge", + "blocksNumber": "blocks-number", + "blocksTable": "blocks-table", + "byteCodeDropDown": "bytecode-dropdown", + "contractsAddress": "contracts-address", + "contractVerificationButton": "contract-verification-button", + "direction": "direction", + "initiatorsAddress": "initiators-address", + "fromAddress": "from-address", + "optimizationRadioButtons": "radio-buttons", + "pageTitle": "page-title", + "previousInstructionButton": "previous-instruction-navigation-button", + "showInstructionMetadataButton": "show-instruction-metadata-button", + "nextInstructionButton": "next-instruction-navigation-button", + "traceSearchInput": "trace-search-input", + "tokensIcon": "tokens-icon", + "tokenAddress":"tokenAddress", + "tokenAmount":"token-amount", + "tokenAmountPrice":"token-amount-price", + "transactionsHash": "transactions-hash", + "transactionsMethodName": "transactions-method-name", + "timestamp": "timestamp", + "transactionsTable": "transactions-table", + "latestTransactionsTable": "latest-transaction-table", + "latestBatchesTable": "latest-batches-table", + "tokensTable": "tokens-table", + "toAddress": "to-address", + "transferType": "transfer-type", + "transferFromOrigin": "transfer-from-origin", + "transferToOrigin": "transfer-to-origin", + "transferFromOriginTablet": "transfer-from-origin-tablet", + "transferToOriginTablet": "transfer-to-origin-tablet" + } + \ No newline at end of file diff --git a/packages/integration-tests/.eslintrc.js b/packages/integration-tests/.eslintrc.js new file mode 100644 index 0000000000..db031bf078 --- /dev/null +++ b/packages/integration-tests/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: ["@matterlabs/eslint-config-vue"], +}; diff --git a/packages/integration-tests/README.md b/packages/integration-tests/README.md new file mode 100644 index 0000000000..748dbf5059 --- /dev/null +++ b/packages/integration-tests/README.md @@ -0,0 +1,50 @@ +# Integration tests for for Block Explorer UI and API + +Based on Jest.io/TypeScript/TDD. + +## Installation + +```bash +npm install +``` + +## Preparing a local environment + +Make sure you have `Docker` installed. Before running the tests you need to spin up a local environment (use `docker-compose.yaml` from the root directory): +```bash +docker-compose up +``` + +## Running API tests +-- +all tests: + +```bash +npm run integration-test:api +``` +## Running UI tests +-- +all tests: + +```bash +npm run integration-test:ui +``` + +If you need to run the exact test or/and suite you can change +key-words from `it` to `fit` (for the test) and `describe` to `fdescribe` for suite. + +If you need to exclude some specific test/suites, you can change keywords `it` to `xit` and/or +`describe` to `xdescribe`. + +The test solution contains two main folders: [src](./src) and [tests](./tests). +[src](./src) folder contains: +- essential [scenarios](./src/playbook/scenarios/) +- predefined [entities](./src/entities.ts) and [config](./src/config.ts) config files +- [contracts](./src/playbook/contracts/) folder with a set of contracts +- [deploy](./src/playbook/deploy/) folder with a set of deploy scripts +- [buffer](./src/playbook/buffer/) folder as a temporary storage of transaction hashes and addresses +- [utils](./src/playbook/utils/) folder with utils scripts + +[tests](./tests) folder contains sets of: +- [api](./tests/api/) endpoints tests, which cover essential part of [worker](../packages/worker/) and [api](../packages/api/) functionality +- [ui](./tests/ui/) UI tests, which cover essential part of [Block explorer](../packages/app/) functionality diff --git a/packages/integration-tests/jest.config.json b/packages/integration-tests/jest.config.json new file mode 100644 index 0000000000..d6589b6ee7 --- /dev/null +++ b/packages/integration-tests/jest.config.json @@ -0,0 +1,12 @@ +{ + "moduleFileExtensions": ["js", "json", "ts"], + "rootDir": ".", + "testEnvironment": "node", + "testRegex": ".test.ts$", + "modulePathIgnorePatterns": ["/src/playbook"], + "transform": { + "^.+\\.(t|j)s$": "ts-jest" + }, + "reporters": ["default"], + "maxWorkers": 1 +} \ No newline at end of file diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json new file mode 100644 index 0000000000..71f17b519a --- /dev/null +++ b/packages/integration-tests/package.json @@ -0,0 +1,48 @@ +{ + "name": "integration-tests", + "version": "0.0.0", + "title": "Integration tests", + "description": "The test solution for transaction processing`", + "repository": "https://github.com/matter-labs/block-explorer", + "private": true, + "author": "Matter Labs", + "license": "MIT", + "scripts": { + "postinstall": "cd src/playbook && npm install", + "integration-test:api": "jest --verbose --testPathPattern=tokens.test.ts && jest --verbose --testPathPattern=deposit.test.ts && jest --verbose --testPathPattern=common && jest --verbose --testPathPattern=transactions", + "integration-test:ui": "npx playwright test", + "block-explorer:start": "docker-compose up", + "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-pattern 'repos' --ignore-pattern 'git add .'" + }, + "devDependencies": { + "@matterlabs/eslint-config-vue": "^1.1.4", + "@matterlabs/hardhat-zksync-deploy": "^0.6.3", + "@matterlabs/hardhat-zksync-solc": "^0.3.14", + "@matterlabs/prettier-config": "^1.0.2", + "@matterlabs/zksync-contracts": "^0.6.1", + "@nomiclabs/hardhat-ethers": "^2.2.2", + "@openzeppelin/contracts": "^4.6.0", + "@openzeppelin/contracts-upgradeable": "^4.6.0", + "@playwright/test": "^1.37.1", + "@types/jest": "^29.2.4", + "@types/node": "^18.15.0", + "dotenv": "^16.0.3", + "eslint": "^8.31.0", + "ethers": "^5.7.2", + "hardhat": "^2.12.0", + "jest": "^29.6.2", + "lint-staged": "^13.1.0", + "prettier": "^2.8.2", + "supertest": "^6.3.3", + "ts-jest": "^29.0.5", + "ts-node": "^10.9.1", + "zksync-web3": "^0.14.3" + }, + "dependencies": { + "ts-jest-resolver": "^2.0.0" + }, + "prettier": "@matterlabs/prettier-config", + "lint-staged": { + "*.{vue,js,ts}": "npm run lint" + } +} diff --git a/packages/integration-tests/playwright.config.ts b/packages/integration-tests/playwright.config.ts new file mode 100644 index 0000000000..9718b2c1f5 --- /dev/null +++ b/packages/integration-tests/playwright.config.ts @@ -0,0 +1,21 @@ +import { defineConfig, devices } from "@playwright/test"; +import { config } from "tests/ui/config"; + +export default defineConfig({ + testDir: "tests/ui", + fullyParallel: true, + projects: [ + { + name: "chromium", + use: { + ...devices["Desktop Chrome"], + launchOptions: { + headless: config.headless, + }, + contextOptions: { + viewport: config.mainWindowSize, + }, + }, + }, + ], +}); diff --git a/packages/integration-tests/src/config.ts b/packages/integration-tests/src/config.ts new file mode 100644 index 0000000000..543bdd9509 --- /dev/null +++ b/packages/integration-tests/src/config.ts @@ -0,0 +1,18 @@ +import { Wallets } from "./entities"; + +export const localConfig = { + gasLimit: { gasLimit: 8000000 }, + l2GasLimit: 8000000, + L1Network: "http://localhost:8545", + L2Network: "http://localhost:3050", + privateKey: Wallets.richWalletPrivateKey, + extendedTimeout: 1200 * 1000, + standardTimeout: 60 * 1000, + extendedPause: 20 * 1000, + standardPause: 5 * 1000, + minimalPause: 1 * 1000, +}; + +export const environment = { + blockExplorerAPI: "http://localhost:3020", +}; diff --git a/packages/integration-tests/src/entities.ts b/packages/integration-tests/src/entities.ts new file mode 100644 index 0000000000..f0f4d545c5 --- /dev/null +++ b/packages/integration-tests/src/entities.ts @@ -0,0 +1,69 @@ +export enum Buffer { + greeterL2 = "./buffer/greeterL2.txt", + executeGreeterTx = "./buffer/executeGreeterTx.txt", + NFTtoL1 = "./buffer/NFTtoL1.txt", + NFTtoL2 = "./buffer/NFTtoL2.txt", + L1 = "./buffer/L1.txt", + L2 = "./buffer/L2.txt", + L2deposited = "./buffer/L2deposited.txt", + paymaster = "./buffer/paymaster.txt", + paymasterTx = "./buffer/paymasterTx.txt", + addressMultiTransferETH = "./buffer/multiTransferETH.txt", + txMultiTransferETH = "./buffer/txMultiTransferETH.txt", + txMultiTransferCustomTokenI = "./buffer/txMultiTransferCustomTokenI.txt", + txMultiTransferCustomTokenII = "./buffer/txMultiTransferCustomTokenII.txt", + addressMultiCallMiddle = "./buffer/multiCallMiddle.txt", + addressMultiCallCaller = "./buffer/multiCallCaller.txt", + addressMultiCallRoot = "./buffer/multiCallRoot.txt", + txMultiCallMiddle = "./buffer/txMultiCallMiddle.txt", + txMultiCallCaller = "./buffer/txMultiCallCaller.txt", + txMultiCallRoot = "./buffer/txmultiCallRoot.txt", + txUseMultiCallContracts = "./buffer/txUseMultiCallContracts.txt", + emptyWalletPrivateKey = "./buffer/emptyWalletPrivateKey.txt", + emptyWalletAddress = "./buffer/emptyWalletAddress.txt", + failedState = "./buffer/failedState.txt", + customToken = "./buffer/customToken.txt", +} + +export enum Logger { + deposit = "DEPOSIT", + withdraw = "WITHDRAW", + transfer = "TRANSFER", + txHashStartsWith = "0x", + textSeparator = "======================= ", + txFailedState = "FAILED STATE", +} + +export enum Token { + CUST_Address = "0x0928008B245A76E105E02C522b5d309c0887ecA5", + customL2TokenName = "L2 ERC20 token", + customL2TokenSymbol = "L2", + customL2TokenDecimals = 18, + ETHER_PULL_Address = "0x0000000000000000000000000000000000008001", + ETHER_Address = "0x0000000000000000000000000000000000000000", + ETHER_ERC20_Address = "0x000000000000000000000000000000000000800A", +} + +export enum TransactionsType { + fee = "fee", + transfer = "transfer", + refund = "refund", +} + +export enum TransactionsStatus { + failed = "failed", +} + +export enum Wallets { + mainWalletAddress = "0x586607935E1462ab762F438E0A7b2968A4158975", + secondWalletAddress = "0x26A4c5Dfe2cA3c9E7E8C417B689F41b6b5745C37", + richWalletAddress = "0x36615Cf349d7F6344891B1e7CA7C72883F5dc049", + mainWalletPrivateKey = "0x06ac1584dd1cf69f97a784b2b7812cd0c65a867ec997add028cdf56483c1c299", + secondWalletPrivateKey = "e14e6e0b3b610411cf15c3a5aa3252cac9e0a40a9bbe67ceb3b5d506f56576fd", + richWalletPrivateKey = "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110", +} + +export enum BlockExplorer { + baseUrl = "http://localhost:3010", + localNetwork = "/?network=local", +} diff --git a/packages/integration-tests/src/helper.ts b/packages/integration-tests/src/helper.ts new file mode 100644 index 0000000000..92605228d1 --- /dev/null +++ b/packages/integration-tests/src/helper.ts @@ -0,0 +1,38 @@ +import { execSync } from "child_process"; +import { promises as fs } from "fs"; +import * as path from "path"; + +import { Logger } from "./entities"; + +export class Helper { + async txHashLogger(txType: string, txValue: string, tokenName?: string) { + const logMessage = `TxHash for ${txType} ${Logger.textSeparator} ${txValue}`; + + if (tokenName === undefined) { + return console.log(logMessage); + } else { + return console.log(logMessage, ` ${tokenName}`); + } + } + + async executeScript(script: string) { + const output = execSync(script, { encoding: "utf-8" }); + + try { + console.log(`> Run NPM Script "${script}":\n`, output); + return output; + } catch (e) { + console.log(e); + } + } + + async getStringFromFile(fileName: string) { + const absoluteRoute = path.join(__dirname, "..", fileName); + + try { + return await fs.readFile(absoluteRoute, { encoding: "utf-8" }); + } catch { + console.log(`There is no the expected file: ${fileName}`); + } + } +} diff --git a/packages/integration-tests/src/playbook/buffer/.gitkeep b/packages/integration-tests/src/playbook/buffer/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/integration-tests/src/playbook/contracts/Caller.sol b/packages/integration-tests/src/playbook/contracts/Caller.sol new file mode 100644 index 0000000000..06fbb8d08a --- /dev/null +++ b/packages/integration-tests/src/playbook/contracts/Caller.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.0; + +interface IGreeter2 { + function callGreeter() external view returns (string memory); + function setGreet(string memory greeting) external; +} + +contract GCaller { + address public myAddress; + address public callAddress; + string private defaultGreeting = "Hi from Caller"; + + constructor(address _callAddress) { + myAddress = address(this); + callAddress = _callAddress; + } + + function newSetGreet(string memory _greeting) external { + bytes memory greetingBytes = bytes(_greeting); + string memory greeting = (greetingBytes.length > 0) ? _greeting : defaultGreeting; + IGreeter2(callAddress).setGreet(greeting); + } + + function newCallGreeter() external view returns (string memory) { + return IGreeter2(callAddress).callGreeter(); + } +} \ No newline at end of file diff --git a/packages/integration-tests/src/playbook/contracts/Greeter.sol b/packages/integration-tests/src/playbook/contracts/Greeter.sol new file mode 100644 index 0000000000..a387ffea88 --- /dev/null +++ b/packages/integration-tests/src/playbook/contracts/Greeter.sol @@ -0,0 +1,22 @@ +//SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.0; + +contract Greeter { + string private greeting; + + event SetGreeting(string greeting); + + constructor(string memory _greeting) { + greeting = _greeting; + } + + function greet() public view returns (string memory) { + return greeting; + } + + function setGreeting(string memory _greeting) public { + greeting = _greeting; + + emit SetGreeting(_greeting); + } +} \ No newline at end of file diff --git a/packages/integration-tests/src/playbook/contracts/L1.sol b/packages/integration-tests/src/playbook/contracts/L1.sol new file mode 100644 index 0000000000..9ab266f345 --- /dev/null +++ b/packages/integration-tests/src/playbook/contracts/L1.sol @@ -0,0 +1,12 @@ +//SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract L1 is ERC20 { + uint256 constant _initial_supply = 1000 * (10 ** 18); + + constructor(address _recipient) public ERC20("L1 ERC20 token", "L1") { + _mint(_recipient, _initial_supply); + } +} \ No newline at end of file diff --git a/packages/integration-tests/src/playbook/contracts/L2.sol b/packages/integration-tests/src/playbook/contracts/L2.sol new file mode 100644 index 0000000000..d75566e808 --- /dev/null +++ b/packages/integration-tests/src/playbook/contracts/L2.sol @@ -0,0 +1,12 @@ +//SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract L2 is ERC20 { + uint256 constant _initial_supply = 1000 * (10 ** 18); + + constructor() ERC20("L2 ERC20 token", "L2") { + _mint(msg.sender, _initial_supply); + } +} \ No newline at end of file diff --git a/packages/integration-tests/src/playbook/contracts/Middle.sol b/packages/integration-tests/src/playbook/contracts/Middle.sol new file mode 100644 index 0000000000..1064289caa --- /dev/null +++ b/packages/integration-tests/src/playbook/contracts/Middle.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.0; + +interface IGreeter { + function greet() external view returns (string memory); + function setGreeting(string memory) external; +} + +contract Middle { + address public myAddress; + + constructor(address _myAddress) { + myAddress = _myAddress; + } + + function setGreet(string memory newGreeting) external { + IGreeter(myAddress).setGreeting(newGreeting); + } + + function callGreeter() external view returns (string memory) { + return IGreeter(myAddress).greet(); + } +} \ No newline at end of file diff --git a/packages/integration-tests/src/playbook/contracts/MultiTransfer.sol b/packages/integration-tests/src/playbook/contracts/MultiTransfer.sol new file mode 100644 index 0000000000..9970afb6c5 --- /dev/null +++ b/packages/integration-tests/src/playbook/contracts/MultiTransfer.sol @@ -0,0 +1,63 @@ +// File @openzeppelin/contracts/token/ERC20/IERC20.sol@v4.6.0 + +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@openzeppelin/contracts/utils/Address.sol"; + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.16; + + +contract TokenF2L2 { + // Declare the using directive on the contract scope + using SafeERC20 for IERC20; + using Address for address payable; + + //Be able to receive any funds to the contract + receive() external payable { + pay(); + } + + function pay() public payable { + emit Paid(msg.sender, msg.value, block.timestamp); + } + + function getBalance() public view returns (uint) { + return address(this).balance; + } + + address public owner; + + constructor(address _owner) { + owner = _owner; + } + + event Paid(address indexed _from, uint _amount, uint _timestamp); + + modifier onlyOwner() { + require(owner == msg.sender, "You are not the owner"); + _; // continue + } + + function multiTransfer( + address[] memory _recivers, + address[] memory _tokenAddresses, + uint256[] memory _tokenAmounts + ) public payable onlyOwner { + // Check that the length of the tokenAddresses array is equal to the length of the tokenAmounts array + require(_tokenAddresses.length == _tokenAmounts.length, "Arrays must have the same length"); + require(_tokenAddresses.length == _recivers.length, "Arrays must have the same length"); + + // Iterate over the arrays and transfer the specified amount of each token + for (uint i = 0; i < _tokenAddresses.length; i++) { + if (_tokenAddresses[i] == address(0)) { + payable(_recivers[i]).sendValue(_tokenAmounts[i]); + } else { + // Cast the token address to an IERC20 contract to access its safeTransfer function + IERC20 token = IERC20(_tokenAddresses[i]); + + // Attempt to transfer the specified amount of the token + token.safeTransfer(_recivers[i], _tokenAmounts[i]); + } + } + } +} diff --git a/packages/integration-tests/src/playbook/contracts/MyERC20.sol b/packages/integration-tests/src/playbook/contracts/MyERC20.sol new file mode 100644 index 0000000000..0814c573e0 --- /dev/null +++ b/packages/integration-tests/src/playbook/contracts/MyERC20.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract MyERC20 is ERC20 { + uint8 private _decimals; + + constructor( + string memory name_, + string memory symbol_, + uint8 decimals_ + ) ERC20(name_, symbol_) { + _decimals = decimals_; + } + + function mint(address _to, uint256 _amount) public returns (bool) { + _mint(_to, _amount); + return true; + } + + function decimals() public view override returns (uint8) { + return _decimals; + } +} \ No newline at end of file diff --git a/packages/integration-tests/src/playbook/contracts/MyNFT.sol b/packages/integration-tests/src/playbook/contracts/MyNFT.sol new file mode 100644 index 0000000000..3ad305335d --- /dev/null +++ b/packages/integration-tests/src/playbook/contracts/MyNFT.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; +import "@openzeppelin/contracts/utils/Counters.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; + +contract MyNFT is ERC721URIStorage, Ownable { + using Counters for Counters.Counter; + Counters.Counter private _tokenIds; + + constructor() ERC721("MyNFT", "NFT") {} + + function mintNFT(address recipient, string memory tokenURI) public onlyOwner returns (uint256) { + _tokenIds.increment(); + + uint256 newItemId = _tokenIds.current(); + _mint(recipient, newItemId); + _setTokenURI(newItemId, tokenURI); + + return newItemId; + } +} diff --git a/packages/integration-tests/src/playbook/contracts/MyPaymaster.sol b/packages/integration-tests/src/playbook/contracts/MyPaymaster.sol new file mode 100644 index 0000000000..dd296f5ba9 --- /dev/null +++ b/packages/integration-tests/src/playbook/contracts/MyPaymaster.sol @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import {IPaymaster, ExecutionResult, PAYMASTER_VALIDATION_SUCCESS_MAGIC} from "@matterlabs/zksync-contracts/l2/system-contracts/interfaces/IPaymaster.sol"; +import {IPaymasterFlow} from "@matterlabs/zksync-contracts/l2/system-contracts/interfaces/IPaymasterFlow.sol"; +import {TransactionHelper, Transaction} from "@matterlabs/zksync-contracts/l2/system-contracts/libraries/TransactionHelper.sol"; + +import "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol"; + +contract MyPaymaster is IPaymaster { + uint256 constant PRICE_FOR_PAYING_FEES = 1; + + address public allowedToken; + + modifier onlyBootloader() { + require( + msg.sender == BOOTLOADER_FORMAL_ADDRESS, + "Only bootloader can call this method" + ); + // Continure execution if called from the bootloader. + _; + } + + constructor(address _erc20) { + allowedToken = _erc20; + } + + function validateAndPayForPaymasterTransaction( + bytes32, + bytes32, + Transaction calldata _transaction + ) external payable returns (bytes4 magic, bytes memory context) { + // By default we consider the transaction as accepted. + magic = PAYMASTER_VALIDATION_SUCCESS_MAGIC; + require( + _transaction.paymasterInput.length >= 4, + "The standard paymaster input must be at least 4 bytes long" + ); + + bytes4 paymasterInputSelector = bytes4( + _transaction.paymasterInput[0:4] + ); + if (paymasterInputSelector == IPaymasterFlow.approvalBased.selector) { + // While the transaction data consists of address, uint256 and bytes data, + // the data is not needed for this paymaster + (address token, uint256 amount, bytes memory data) = abi.decode( + _transaction.paymasterInput[4:], + (address, uint256, bytes) + ); + + // Verify if token is the correct one + require(token == allowedToken, "Invalid token"); + + // We verify that the user has provided enough allowance + address userAddress = address(uint160(_transaction.from)); + + address thisAddress = address(this); + + uint256 providedAllowance = IERC20(token).allowance( + userAddress, + thisAddress + ); + require( + providedAllowance >= PRICE_FOR_PAYING_FEES, + "Min allowance too low" + ); + + // Note, that while the minimal amount of ETH needed is tx.gasPrice * tx.gasLimit, + // neither paymaster nor account are allowed to access this context variable. + uint256 requiredETH = _transaction.gasLimit * + _transaction.maxFeePerGas; + + try + IERC20(token).transferFrom(userAddress, thisAddress, amount) + {} catch (bytes memory revertReason) { + // If the revert reason is empty or represented by just a function selector, + // we replace the error with a more user-friendly message + if (revertReason.length <= 4) { + revert("Failed to transferFrom from users' account"); + } else { + assembly { + revert(add(0x20, revertReason), mload(revertReason)) + } + } + } + + // The bootloader never returns any data, so it can safely be ignored here. + (bool success, ) = payable(BOOTLOADER_FORMAL_ADDRESS).call{ + value: requiredETH + }(""); + require(success, "Failed to transfer funds to the bootloader"); + } else { + revert("Unsupported paymaster flow"); + } + } + + function postTransaction( + bytes calldata _context, + Transaction calldata _transaction, + bytes32, + bytes32, + ExecutionResult _txResult, + uint256 _maxRefundedGas + ) external payable override { + // Refunds are not supported yet. + } + + receive() external payable {} +} diff --git a/packages/integration-tests/src/playbook/contracts/Root.sol b/packages/integration-tests/src/playbook/contracts/Root.sol new file mode 100644 index 0000000000..b5f3b2abc7 --- /dev/null +++ b/packages/integration-tests/src/playbook/contracts/Root.sol @@ -0,0 +1,22 @@ +//SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.0; + +contract Root { + string private greeting = "Hi from Root"; + + event SetGreeting(string greeting); + + constructor(string memory _greeting) { + greeting = _greeting; + } + + function greet() public view returns (string memory) { + return greeting; + } + + function setGreeting(string memory _greeting) public { + greeting = _greeting; + + emit SetGreeting(_greeting); + } +} \ No newline at end of file diff --git a/packages/integration-tests/src/playbook/deploy/deploy-greeter.ts b/packages/integration-tests/src/playbook/deploy/deploy-greeter.ts new file mode 100644 index 0000000000..ae4d4d9da6 --- /dev/null +++ b/packages/integration-tests/src/playbook/deploy/deploy-greeter.ts @@ -0,0 +1,19 @@ +import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; +import { promises as fs } from "fs"; + +import { localConfig } from "../../config"; +import { Buffer } from "../../entities"; +import getWallet from "../utils/getWallet"; + +import type { HardhatRuntimeEnvironment } from "hardhat/types"; + +export default async function (hre: HardhatRuntimeEnvironment) { + const wallet = await getWallet(hre); + + const deployer = new Deployer(hre, wallet); + const artifact = await deployer.loadArtifact("Greeter"); + const contract = await deployer.deploy(artifact, [], localConfig.gasLimit); + const contractAddress = contract.address; + console.log(`${artifact.contractName} was deployed to ${contractAddress}`); + await fs.writeFile(Buffer.greeterL2, contractAddress); +} diff --git a/packages/integration-tests/src/playbook/deploy/deploy-paymaster.ts b/packages/integration-tests/src/playbook/deploy/deploy-paymaster.ts new file mode 100644 index 0000000000..a8148f5b33 --- /dev/null +++ b/packages/integration-tests/src/playbook/deploy/deploy-paymaster.ts @@ -0,0 +1,49 @@ +import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; +import * as ethers from "ethers"; +import { promises as fs } from "fs"; +import { Wallet } from "zksync-web3"; + +import { Buffer, Wallets } from "../../entities"; + +import type { HardhatRuntimeEnvironment } from "hardhat/types"; + +export default async function (hre: HardhatRuntimeEnvironment) { + const wallet = new Wallet(Wallets.richWalletPrivateKey); + // The wallet that will receive ERC20 tokens + const emptyWallet = Wallet.createRandom(); + console.log(`Empty wallet's address: ${emptyWallet.address}`); + await fs.writeFile(Buffer.emptyWalletAddress, emptyWallet.address); + console.log(`Empty wallet's private key: ${emptyWallet.privateKey}`); + await fs.writeFile(Buffer.emptyWalletPrivateKey, emptyWallet.privateKey); + + const deployer = new Deployer(hre, wallet); + + // Deploying the ERC20 token + const erc20Artifact = await deployer.loadArtifact("MyERC20"); + const erc20 = await deployer.deploy(erc20Artifact, ["MyToken", "MyToken", 18]); + console.log(`ERC20 address: ${erc20.address}`); + await fs.writeFile(Buffer.customToken, erc20.address); + + const paymasterArtifact = await deployer.loadArtifact("MyPaymaster"); + const paymaster = await deployer.deploy(paymasterArtifact, [erc20.address]); + console.log(`Paymaster address: ${paymaster.address}`); + await fs.writeFile(Buffer.paymaster, paymaster.address); + + const deployTransaction = await paymaster.deployTransaction; + console.log(`Paymaster deploy transaction: ${deployTransaction.hash}`); + + await ( + await deployer.zkWallet.sendTransaction({ + to: paymaster.address, + value: ethers.utils.parseEther("0.03"), + }) + ).wait(); + + await // We will give the empty wallet 3 units of the token: + (await erc20.mint(emptyWallet.address, 3)).wait(); + + console.log("Minted 3 tokens for the empty wallet"); + console.log(`Done!`); + + return deployTransaction.hash; +} diff --git a/packages/integration-tests/src/playbook/deploy/erc20toL1.ts b/packages/integration-tests/src/playbook/deploy/erc20toL1.ts new file mode 100644 index 0000000000..63b7b72200 --- /dev/null +++ b/packages/integration-tests/src/playbook/deploy/erc20toL1.ts @@ -0,0 +1,27 @@ +import { promises as fs } from "fs"; +import { ethers } from "hardhat"; + +import { localConfig } from "../../config"; +import { Buffer, Wallets } from "../../entities"; + +async function main() { + const [deployer] = await ethers.getSigners(); + + console.log("Deploying contracts with the account:", deployer.address); + + const weiAmount = (await deployer.getBalance()).toString(); + + console.log("Account balance:", await ethers.utils.formatEther(weiAmount)); + + const contract = await ethers.getContractFactory("L1"); + const token = await contract.deploy(Wallets.richWalletAddress, localConfig.gasLimit); + + await fs.writeFile(Buffer.L1, token.address); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/packages/integration-tests/src/playbook/deploy/erc20toL2.ts b/packages/integration-tests/src/playbook/deploy/erc20toL2.ts new file mode 100644 index 0000000000..cbebe93761 --- /dev/null +++ b/packages/integration-tests/src/playbook/deploy/erc20toL2.ts @@ -0,0 +1,19 @@ +import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; +import { promises as fs } from "fs"; + +import { localConfig } from "../../config"; +import { Buffer } from "../../entities"; +import getWallet from "../utils/getWallet"; + +import type { HardhatRuntimeEnvironment } from "hardhat/types"; + +export default async function (hre: HardhatRuntimeEnvironment) { + const wallet = await getWallet(hre); + + const deployer = new Deployer(hre, wallet); + const artifact = await deployer.loadArtifact("L2"); + const contract = await deployer.deploy(artifact, [], localConfig.gasLimit); + const contractAddress = contract.address; + console.log(`${artifact.contractName} was deployed to ${contractAddress}`); + await fs.writeFile(Buffer.L2, contractAddress); +} diff --git a/packages/integration-tests/src/playbook/deploy/multiTransferETH.ts b/packages/integration-tests/src/playbook/deploy/multiTransferETH.ts new file mode 100644 index 0000000000..73b1924d62 --- /dev/null +++ b/packages/integration-tests/src/playbook/deploy/multiTransferETH.ts @@ -0,0 +1,35 @@ +import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; +import { promises as fs } from "fs"; + +import { Buffer, Wallets } from "../../entities"; +import verify from "../utils/displayVerificationInfo"; +import getWallet from "../utils/getWallet"; + +import type { HardhatRuntimeEnvironment } from "hardhat/types"; + +const contract_name = "TokenF2L2"; // insert the name of the contract you want to deploy +const constructor_arguments = [Wallets.richWalletAddress]; // insert the constructor arguments of the contract you want to deploy + +export default async function (hre: HardhatRuntimeEnvironment) { + console.log(`Running deploy script for the ${contract_name} contract`); + + const wallet = await getWallet(hre); + + // Create deployer object and load the artifact of the contract we want to deploy. + const deployer = new Deployer(hre, wallet); + const artifact = await deployer.loadArtifact(contract_name); + + // Deploy this contract. The returned object will be of a `Contract` type, similarly to ones in `ethers`. + console.log(`Deploying contract with arguments: ${JSON.stringify(constructor_arguments)}`); + const deployedContract = await deployer.deploy(artifact, constructor_arguments); + + await deployedContract.deployTransaction.wait(2); + + // Show the contract info. + console.log(`Contract "${artifact.contractName}" was deployed to ${deployedContract.address}`); + await fs.writeFile(Buffer.addressMultiTransferETH, deployedContract.address); + + await verify({ hre, contract: deployedContract, contractConstructorArguments: constructor_arguments, artifact }); + + return deployedContract.address; +} diff --git a/packages/integration-tests/src/playbook/deploy/multicallCaller.ts b/packages/integration-tests/src/playbook/deploy/multicallCaller.ts new file mode 100644 index 0000000000..d609e8e28a --- /dev/null +++ b/packages/integration-tests/src/playbook/deploy/multicallCaller.ts @@ -0,0 +1,41 @@ +import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; +import { promises as fs } from "fs"; + +import { Buffer } from "../../entities"; +import { Helper } from "../../helper"; +import getWallet from "../utils/getWallet"; + +import type { HardhatRuntimeEnvironment } from "hardhat/types"; + +export default async function (hre: HardhatRuntimeEnvironment) { + console.log(`Running deploy script for the contract`); + const helper = new Helper(); + const playbookRoot = "src/playbook/"; + const wallet = await getWallet(hre); + + // Create deployer object and load the artifact of the contract we want to deploy. + const deployer = new Deployer(hre, wallet); + const artifact = await deployer.loadArtifact("GCaller"); + + // Deploy this contract. The returned object will be of a `Contract` type, similarly to ones in `ethers`. + const addressContractMiddle = await helper.getStringFromFile(playbookRoot + Buffer.addressMultiCallMiddle); + const contractConstructorArguments = [addressContractMiddle]; + console.log(`Arguments for the contract constructor: ${JSON.stringify(contractConstructorArguments)}`); + const deployedContract = await deployer.deploy(artifact, contractConstructorArguments); + + // Show the contract info. + console.log(`Contract "${artifact.contractName}" was deployed to ${deployedContract.address}`); + + // Call the deployed contract. + const greetingFromContract = await deployedContract.newCallGreeter(); + + console.log(`Contract said something like this: ${greetingFromContract}`); + + const address = deployedContract.address; + const txHash = deployedContract.deployTransaction.hash; + + await fs.writeFile(Buffer.addressMultiCallCaller, address); + await fs.writeFile(Buffer.txMultiCallCaller, txHash); + + return [address, txHash]; +} diff --git a/packages/integration-tests/src/playbook/deploy/multicallMiddle.ts b/packages/integration-tests/src/playbook/deploy/multicallMiddle.ts new file mode 100644 index 0000000000..c4feb61249 --- /dev/null +++ b/packages/integration-tests/src/playbook/deploy/multicallMiddle.ts @@ -0,0 +1,42 @@ +import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; +import { promises as fs } from "fs"; + +import { Buffer } from "../../entities"; +import { Helper } from "../../helper"; +import getWallet from "../utils/getWallet"; + +import type { HardhatRuntimeEnvironment } from "hardhat/types"; + +export default async function (hre: HardhatRuntimeEnvironment) { + console.log(`Running deploy script for the contract`); + + const helper = new Helper(); + const playbookRoot = "src/playbook/"; + const wallet = await getWallet(hre); + + // Create deployer object and load the artifact of the contract we want to deploy. + const deployer = new Deployer(hre, wallet); + const artifact = await deployer.loadArtifact("Middle"); + + // Deploy this contract. The returned object will be of a `Contract` type, similarly to ones in `ethers`. + const addressContractRoot = await helper.getStringFromFile(playbookRoot + Buffer.addressMultiCallRoot); + const contractConstructorArguments = [addressContractRoot]; + console.log(`Arguments for the contract constructor: ${JSON.stringify(contractConstructorArguments)}`); + const deployedContract = await deployer.deploy(artifact, contractConstructorArguments); + + // Show the contract info. + console.log(`Contract "${artifact.contractName}" was deployed to ${deployedContract.address}`); + + // Call the deployed contract. + const greetingFromContract = await deployedContract.callGreeter(); + + console.log(`Contract said something like this: ${greetingFromContract}`); + + const address = deployedContract.address; + const txHash = deployedContract.deployTransaction.hash; + + await fs.writeFile(Buffer.addressMultiCallMiddle, address); + await fs.writeFile(Buffer.txMultiCallMiddle, txHash); + + return [address, txHash]; +} diff --git a/packages/integration-tests/src/playbook/deploy/multicallRoot.ts b/packages/integration-tests/src/playbook/deploy/multicallRoot.ts new file mode 100644 index 0000000000..b0236342a9 --- /dev/null +++ b/packages/integration-tests/src/playbook/deploy/multicallRoot.ts @@ -0,0 +1,55 @@ +import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; +import { promises as fs } from "fs"; + +import { Buffer } from "../../entities"; +import getWallet from "../utils/getWallet"; + +import type { HardhatRuntimeEnvironment } from "hardhat/types"; + +export default async function (hre: HardhatRuntimeEnvironment) { + console.log(`Running deploy script for the Greeter contract`); + + const wallet = await getWallet(hre); + + // Create deployer object and load the artifact of the contract we want to deploy. + const deployer = new Deployer(hre, wallet); + const artifact = await deployer.loadArtifact("Root"); + + // Deploy this contract. The returned object will be of a `Contract` type, similarly to ones in `ethers`. + // `greeting` is an argument for contract constructor. + const greeting = "Hi from root!"; + const contractConstructorArguments = [greeting]; + console.log(`Arguments for the contract constructor: ${JSON.stringify(contractConstructorArguments)}`); + const deployedContract = await deployer.deploy(artifact, contractConstructorArguments); + + // Show the contract info. + console.log(`Contract "${artifact.contractName}" was deployed to ${deployedContract.address}`); + + // Call the deployed contract. + const greetingFromContract = await deployedContract.greet(); + if (greetingFromContract == greeting) { + console.log(`Contract greets us with ${greeting}!`); + } else { + console.error(`Contract said something unexpected: ${greetingFromContract}`); + } + + // Edit the greeting of the contract + const newGreeting = "New Root"; + const setNewGreetingHandle = await deployedContract.setGreeting(newGreeting); + await setNewGreetingHandle.wait(1); + + const newGreetingFromContract = await deployedContract.greet(); + if (newGreetingFromContract == newGreeting) { + console.log(`Contract greets us with ${newGreeting}!`); + } else { + console.error(`Contract said something unexpected: ${newGreetingFromContract}`); + } + + const address = deployedContract.address; + const txHash = deployedContract.deployTransaction.hash; + + await fs.writeFile(Buffer.addressMultiCallRoot, address); + await fs.writeFile(Buffer.txMultiCallRoot, txHash); + + return [address, txHash]; +} diff --git a/packages/integration-tests/src/playbook/deploy/nftToL1.ts b/packages/integration-tests/src/playbook/deploy/nftToL1.ts new file mode 100644 index 0000000000..fb1af7d58b --- /dev/null +++ b/packages/integration-tests/src/playbook/deploy/nftToL1.ts @@ -0,0 +1,33 @@ +import { promises as fs } from "fs"; +import { ethers } from "hardhat"; +import * as hardhatConfig from "hardhat"; + +import { Buffer, Wallets } from "../../entities"; + +import type { HardhatRuntimeEnvironment } from "hardhat/types"; + +async function main() { + const hre: HardhatRuntimeEnvironment = hardhatConfig; + const MyNFTArtifact = await hre.artifacts.readArtifact("MyNFT"); + const [deployer] = await ethers.getSigners(); + const MyNFTFactory = new ethers.ContractFactory(MyNFTArtifact.abi, MyNFTArtifact.bytecode, deployer); + + const myNFT = await MyNFTFactory.deploy(); + console.log("Contract deployed to L1 address:", myNFT.address); + + const mintNFT = await myNFT.mintNFT(myNFT.address, Wallets.richWalletAddress); + if (mintNFT) { + console.log(`Contract mint for us!`); + } else { + console.error(`The NFT minting has been unsuccessful: ${mintNFT}`); + } + + await fs.writeFile(Buffer.NFTtoL1, myNFT.address); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/packages/integration-tests/src/playbook/deploy/nftToL2.ts b/packages/integration-tests/src/playbook/deploy/nftToL2.ts new file mode 100644 index 0000000000..6ae5c15547 --- /dev/null +++ b/packages/integration-tests/src/playbook/deploy/nftToL2.ts @@ -0,0 +1,34 @@ +import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; +import { promises as fs } from "fs"; + +import { Buffer, Wallets } from "../../entities"; +import displayVerificationInfo from "../utils/displayVerificationInfo"; +import getWallet from "../utils/getWallet"; + +import type { HardhatRuntimeEnvironment } from "hardhat/types"; + +export default async function (hre: HardhatRuntimeEnvironment) { + console.log(`Running deploy script for the Greeter contract`); + + const wallet = await getWallet(hre); + const deployer = new Deployer(hre, wallet); + const artifact = await deployer.loadArtifact("MyNFT"); + const contractConstructorArguments = []; + + console.log(`Arguments for the contract constructor: ${JSON.stringify(contractConstructorArguments)}`); + + const myNFT = await deployer.deploy(artifact, contractConstructorArguments); + + console.log(`Contract "${artifact.contractName}" was deployed to ${myNFT.address}`); + + const mintNFT = await myNFT.mintNFT(myNFT.address, Wallets.richWalletAddress); + if (mintNFT) { + console.log(`Contract mint for us!`); + } else { + console.error(`Contract said something unexpected: ${mintNFT}`); + } + + displayVerificationInfo({ hre, contract: myNFT, contractConstructorArguments, artifact }); + + await fs.writeFile(Buffer.NFTtoL2, myNFT.address); +} diff --git a/packages/integration-tests/src/playbook/deploy/use-greeter.ts b/packages/integration-tests/src/playbook/deploy/use-greeter.ts new file mode 100644 index 0000000000..d11a3b6610 --- /dev/null +++ b/packages/integration-tests/src/playbook/deploy/use-greeter.ts @@ -0,0 +1,39 @@ +import * as ethers from "ethers"; +import { promises as fs } from "fs"; +import { Provider, Wallet } from "zksync-web3"; + +import { localConfig } from "../../config"; +import { Wallets } from "../../entities"; +import { Buffer } from "../../entities"; +import { Helper } from "../../helper"; + +import type { HardhatRuntimeEnvironment } from "hardhat/types"; + +export default async function (hre: HardhatRuntimeEnvironment) { + const bufferRoute = "src/playbook/"; + const helper = new Helper(); + let contract: any; // eslint-disable-line + + const greeterContractAddress = await helper.getStringFromFile(bufferRoute + Buffer.greeterL2); + + const provider = new Provider(localConfig.L2Network); + const wallet = new Wallet(Wallets.richWalletPrivateKey, provider); + + function getContract(hre: HardhatRuntimeEnvironment, wallet: Wallet) { + const artifact = hre.artifacts.readArtifactSync("Greeter"); + contract = new ethers.Contract(greeterContractAddress, artifact.abi, wallet); + return contract; + } + + const executeGreetings = getContract(hre, wallet); + + const newGreeting = "New Greetings!"; + const transaction = await executeGreetings.setGreeting(newGreeting); + const transactionReceipt = await transaction.wait(1); + + console.log(`Transaction hash: ${transactionReceipt.transactionHash}`); + + await fs.writeFile(Buffer.executeGreeterTx, transactionReceipt.transactionHash); + + return transactionReceipt.transactionHash; +} diff --git a/packages/integration-tests/src/playbook/deploy/use-multiCall.ts b/packages/integration-tests/src/playbook/deploy/use-multiCall.ts new file mode 100644 index 0000000000..5941892677 --- /dev/null +++ b/packages/integration-tests/src/playbook/deploy/use-multiCall.ts @@ -0,0 +1,37 @@ +import * as ethers from "ethers"; +import { promises as fs } from "fs"; +import { Provider } from "zksync-web3"; + +import { localConfig } from "../../config"; +import { Buffer } from "../../entities"; +import { Helper } from "../../helper"; +import getWallet from "../utils/getWallet"; + +import type { HardhatRuntimeEnvironment } from "hardhat/types"; + +export default async function (hre: HardhatRuntimeEnvironment) { + const helper = new Helper(); + const playbookRoot = "src/playbook/"; + const TRANSFER_CONTRACT_ADDRESS = await helper.getStringFromFile(playbookRoot + Buffer.addressMultiCallCaller); + const CONTRACT_NAME = "GCaller"; + + console.log(`Running deploy script for the contract`); + const provider = new Provider(localConfig.L2Network); + const wallet = await (await getWallet(hre)).connect(provider); + const factoryArtifact = await hre.artifacts.readArtifact(CONTRACT_NAME); + + const attachedContract = new ethers.Contract(TRANSFER_CONTRACT_ADDRESS, factoryArtifact.abi, wallet); + console.log(`Contract said something like this by default: ${await attachedContract.newCallGreeter()}`); + const newGreet = "New Greet!"; + const setNewGreetingHandle = await attachedContract.newSetGreet(newGreet, localConfig.gasLimit); + await setNewGreetingHandle.wait(1); + + const txHash = setNewGreetingHandle.hash; + + console.log("Multicall contract caller: ", txHash); + console.log(`Contract said after new greeting: ${await attachedContract.newCallGreeter()}`); + + await fs.writeFile(Buffer.txUseMultiCallContracts, txHash); + + return txHash; +} diff --git a/packages/integration-tests/src/playbook/deploy/use-multitransferETH.ts b/packages/integration-tests/src/playbook/deploy/use-multitransferETH.ts new file mode 100644 index 0000000000..5995db64d5 --- /dev/null +++ b/packages/integration-tests/src/playbook/deploy/use-multitransferETH.ts @@ -0,0 +1,101 @@ +import * as ethers from "ethers"; +import { promises as fs } from "fs"; +import { Provider, Wallet } from "zksync-web3"; + +import { localConfig } from "../../config"; +import { Buffer, Token, Wallets } from "../../entities"; +import { Helper } from "../../helper"; + +import type { HardhatRuntimeEnvironment } from "hardhat/types"; + +export default async function callMultiTransferETH(hre: HardhatRuntimeEnvironment) { + const helper = new Helper(); + const playbookRoot = "src/playbook/"; + const firstToken = playbookRoot + Buffer.L2; + const secondToken = playbookRoot + Buffer.L2deposited; + const buffer = playbookRoot + Buffer.addressMultiTransferETH; + const contractName = "TokenF2L2"; // insert the name of the contract you want to deploy + const contractAddress = await helper.getStringFromFile(buffer); + + //wallets, To + const richWalletAddress = Wallets.richWalletAddress; + const mainWalletAddress = Wallets.mainWalletAddress; + const secondWalletAddress = Wallets.secondWalletAddress; + // type of coin, contract + const etherAddress = Token.ETHER_Address; //ETH + const customTokenI = await helper.getStringFromFile(firstToken); + const customTokenII = await helper.getStringFromFile(secondToken); + // amount of funds + const ethAmount = ethers.utils.parseEther("0.0001"); + const customTokenIAmount = ethers.utils.parseUnits("0.01", 18); + const customTokenIIAmount = ethers.utils.parseUnits("0.01", 18); + + console.log(`Running deploy script for the contract`); + + //get an access to contract + const provider = new Provider(localConfig.L2Network); + const wallet = new Wallet(Wallets.richWalletPrivateKey, provider); + const signer = wallet.connect(provider); + const attachedContract = await hre.ethers.getContractAt(contractName, contractAddress, signer); + + // top up the contract / transfer + const ethTransfer = await makeTransfer(etherAddress, ethers.utils.parseEther("0.101")); + const customToken1Transfer = await makeTransfer(customTokenI, ethers.utils.parseUnits("1", 18)); + const customToken2Transfer = await makeTransfer(customTokenII, ethers.utils.parseUnits("1", 18)); + + async function makeTransfer(token: string, amount: ethers.BigNumber) { + const transfer = await wallet.transfer({ + to: contractAddress, + token: token, + amount, + overrides: localConfig.gasLimit, + }); + + // await commitment + const transferReceipt = await transfer.wait(1); + console.log(`Tx transfer hash for ${token}: ${transferReceipt.transactionHash}`); + + return transferReceipt.transactionHash; + } + + //call the deployed contract. + const transferFromContract = await attachedContract.multiTransfer( + [richWalletAddress, mainWalletAddress, secondWalletAddress], + [etherAddress, customTokenI, customTokenII], + [ethAmount, customTokenIAmount, customTokenIIAmount] + ); + if (transferFromContract) { + console.log(`Contract transfer to us!`); + } else { + console.error(`Contract said something unexpected: ${transferFromContract}`); + } + + // Show the contract balance + console.log( + `Getting ETH balance from contract API: "${ethers.utils.formatUnits( + await provider.getBalance(contractAddress), + 18 + )}"` + ); + + // Show the balance of wallets + console.log( + `balance of wallet 1 is: "${ethers.utils.formatUnits(await provider.getBalance(richWalletAddress), 18)}" ETH` + ); + console.log( + `balance of wallet 2 is: "${ethers.utils.formatUnits( + await provider.getBalance(mainWalletAddress, "latest", customTokenI), + 18 + )}" Custom token I` + ); + console.log( + `balance of wallet 3 is: "${ethers.utils.formatUnits( + await provider.getBalance(secondWalletAddress, "latest", customTokenII), + 18 + )}" Custom token II` + ); + + await fs.writeFile(Buffer.txMultiTransferETH, ethTransfer); + await fs.writeFile(Buffer.txMultiTransferCustomTokenI, customToken1Transfer); + await fs.writeFile(Buffer.txMultiTransferCustomTokenII, customToken2Transfer); +} diff --git a/packages/integration-tests/src/playbook/deploy/use-paymaster.ts b/packages/integration-tests/src/playbook/deploy/use-paymaster.ts new file mode 100644 index 0000000000..c98d397eaa --- /dev/null +++ b/packages/integration-tests/src/playbook/deploy/use-paymaster.ts @@ -0,0 +1,71 @@ +import * as ethers from "ethers"; +import { promises as fs } from "fs"; +import { Provider, utils, Wallet } from "zksync-web3"; + +import { localConfig } from "../../config"; +import { Buffer } from "../../entities"; +import { Helper } from "../../helper"; + +import type { HardhatRuntimeEnvironment } from "hardhat/types"; +const helper = new Helper(); + +export default async function (hre: HardhatRuntimeEnvironment) { + const bufferRoute = "src/playbook/"; + + const PAYMASTER_ADDRESS = await helper.getStringFromFile(bufferRoute + Buffer.paymaster); + const TOKEN_ADDRESS = await helper.getStringFromFile(bufferRoute + Buffer.customToken); + const EMPTY_WALLET_PRIVATE_KEY = await helper.getStringFromFile(bufferRoute + Buffer.emptyWalletPrivateKey); + + const provider = new Provider(localConfig.L2Network); + const emptyWallet = new Wallet(EMPTY_WALLET_PRIVATE_KEY, provider); + + function getToken(hre: HardhatRuntimeEnvironment, wallet: Wallet) { + const artifact = hre.artifacts.readArtifactSync("MyERC20"); + return new ethers.Contract(TOKEN_ADDRESS, artifact.abi, wallet); + } + + const ethBalance = await emptyWallet.getBalance(); + if (!ethBalance.eq(0)) { + throw new Error("The wallet is not empty"); + } + + console.log(`Balance of the user before mint: ${await emptyWallet.getBalance(TOKEN_ADDRESS)}`); + + const erc20 = getToken(hre, emptyWallet); + + const gasPrice = await provider.getGasPrice(); + + const paymasterParams = utils.getPaymasterParams(PAYMASTER_ADDRESS, { + type: "ApprovalBased", + token: TOKEN_ADDRESS, + minimalAllowance: ethers.BigNumber.from(1), + innerInput: new Uint8Array(), + }); + + const gasLimit = await erc20.estimateGas.mint(emptyWallet.address, 100, { + customData: { + gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, + paymasterParams: paymasterParams, + }, + }); + + gasPrice.mul(gasLimit.toString()); + + const mintTx = await erc20.mint(emptyWallet.address, 90, { + customData: { + paymasterParams: paymasterParams, + gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, + }, + }); + + const receipt = await mintTx.wait(); + + console.log(`Balance of the user after mint: ${await emptyWallet.getBalance(TOKEN_ADDRESS)}`); + + console.log(`Balance of the user after mint: ${await emptyWallet.getBalance(TOKEN_ADDRESS)}`); + + await fs.writeFile(Buffer.paymasterTx, receipt.transactionHash); + console.log(`Transaction hash: ${receipt.transactionHash}`); + + return receipt.transactionHash; +} diff --git a/packages/integration-tests/src/playbook/hardhat.config.ts b/packages/integration-tests/src/playbook/hardhat.config.ts new file mode 100644 index 0000000000..ce93c51cdc --- /dev/null +++ b/packages/integration-tests/src/playbook/hardhat.config.ts @@ -0,0 +1,38 @@ +// eslint-disable-next-line @typescript-eslint/no-var-requires +require("dotenv").config({ path: __dirname + "/.env" }); + +import "@matterlabs/hardhat-zksync-deploy"; +import "@matterlabs/hardhat-zksync-solc"; +import "@nomiclabs/hardhat-ethers"; +import { localConfig } from "../config"; + +import type { HardhatUserConfig } from "hardhat/types"; + +const config: HardhatUserConfig = { + zksolc: { + version: "1.3.9", + compilerSource: "binary", + settings: {}, + }, + defaultNetwork: "zkSyncLocal", + + networks: { + zkSyncLocal: { + url: localConfig.L2Network, + ethNetwork: localConfig.L1Network, + zksync: true, + }, + }, + solidity: { + version: "0.8.18", + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + viaIR: true, + }, + }, +}; + +export default config; diff --git a/packages/integration-tests/src/playbook/package-lock.json b/packages/integration-tests/src/playbook/package-lock.json new file mode 100644 index 0000000000..17c7df6951 --- /dev/null +++ b/packages/integration-tests/src/playbook/package-lock.json @@ -0,0 +1,4296 @@ +{ + "name": "playbook", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "playbook", + "version": "0.0.0", + "license": "MIT", + "dependencies": { + "hardhat": "^2.17.3", + "ts-jest-resolver": "^2.0.0" + } + }, + "node_modules/@chainsafe/as-sha256": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@chainsafe/as-sha256/-/as-sha256-0.3.1.tgz", + "integrity": "sha512-hldFFYuf49ed7DAakWVXSJODuq3pzJEguD8tQ7h+sGkM18vja+OFoJI9krnGmgzyuZC2ETX0NOIcCTy31v2Mtg==" + }, + "node_modules/@chainsafe/persistent-merkle-tree": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.4.2.tgz", + "integrity": "sha512-lLO3ihKPngXLTus/L7WHKaw9PnNJWizlOF1H9NNzHP6Xvh82vzg9F2bzkXhYIFshMZ2gTCEz8tq6STe7r5NDfQ==", + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "node_modules/@chainsafe/ssz": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.9.4.tgz", + "integrity": "sha512-77Qtg2N1ayqs4Bg/wvnWfg5Bta7iy7IRh8XqXh7oNMeP2HBbBwx8m6yTpA8p0EHItWPEBkgZd5S5/LSlp3GXuQ==", + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.4.2", + "case": "^1.6.3" + } + }, + "node_modules/@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "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/basex": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", + "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "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/contracts": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", + "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abi": "^5.7.0", + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/hdnode": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", + "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/json-wallets": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", + "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "node_modules/@ethersproject/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/pbkdf2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", + "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/sha2": "^5.7.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, + "node_modules/@ethersproject/providers/node_modules/ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@ethersproject/random": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", + "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/sha2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", + "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "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/solidity": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", + "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "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/units": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", + "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/wallet": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/json-wallets": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/wordlists": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", + "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@metamask/eth-sig-util": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz", + "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", + "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/ethereumjs-block": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.2.tgz", + "integrity": "sha512-hSe6CuHI4SsSiWWjHDIzWhSiAVpzMUcDRpWYzN0T9l8/Rz7xNn3elwVOJ/tAyS0LqL6vitUD78Uk7lQDXZun7Q==", + "dependencies": { + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-trie": "6.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "ethereum-cryptography": "0.1.3", + "ethers": "^5.7.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-block/node_modules/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-blockchain": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.2.tgz", + "integrity": "sha512-8UUsSXJs+MFfIIAKdh3cG16iNmWzWC/91P40sazNvrqhhdR/RtGDlFk2iFTGbBAZPs2+klZVzhRX8m2wvuvz3w==", + "dependencies": { + "@nomicfoundation/ethereumjs-block": "5.0.2", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-ethash": "3.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-trie": "6.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "abstract-level": "^1.0.3", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "level": "^8.0.0", + "lru-cache": "^5.1.1", + "memory-level": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-blockchain/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@nomicfoundation/ethereumjs-common": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.2.tgz", + "integrity": "sha512-I2WGP3HMGsOoycSdOTSqIaES0ughQTueOsddJ36aYVpI3SN8YSusgRFLwzDJwRFVIYDKx/iJz0sQ5kBHVgdDwg==", + "dependencies": { + "@nomicfoundation/ethereumjs-util": "9.0.2", + "crc-32": "^1.2.0" + } + }, + "node_modules/@nomicfoundation/ethereumjs-ethash": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.2.tgz", + "integrity": "sha512-8PfoOQCcIcO9Pylq0Buijuq/O73tmMVURK0OqdjhwqcGHYC2PwhbajDh7GZ55ekB0Px197ajK3PQhpKoiI/UPg==", + "dependencies": { + "@nomicfoundation/ethereumjs-block": "5.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "abstract-level": "^1.0.3", + "bigint-crypto-utils": "^3.0.23", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-ethash/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@nomicfoundation/ethereumjs-evm": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.2.tgz", + "integrity": "sha512-rBLcUaUfANJxyOx9HIdMX6uXGin6lANCulIm/pjMgRqfiCRMZie3WKYxTSd8ZE/d+qT+zTedBF4+VHTdTSePmQ==", + "dependencies": { + "@ethersproject/providers": "^5.7.1", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "mcl-wasm": "^0.7.1", + "rustbn.js": "~0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-evm/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.2.tgz", + "integrity": "sha512-QwmemBc+MMsHJ1P1QvPl8R8p2aPvvVcKBbvHnQOKBpBztEo0omN0eaob6FeZS/e3y9NSe+mfu3nNFBHszqkjTA==", + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-statemanager": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.2.tgz", + "integrity": "sha512-dlKy5dIXLuDubx8Z74sipciZnJTRSV/uHG48RSijhgm1V7eXYFC567xgKtsKiVZB1ViTP9iFL4B6Je0xD6X2OA==", + "dependencies": { + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "ethers": "^5.7.1", + "js-sdsl": "^4.1.4" + } + }, + "node_modules/@nomicfoundation/ethereumjs-statemanager/node_modules/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-trie": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.2.tgz", + "integrity": "sha512-yw8vg9hBeLYk4YNg5MrSJ5H55TLOv2FSWUTROtDtTMMmDGROsAu+0tBjiNGTnKRi400M6cEzoFfa89Fc5k8NTQ==", + "dependencies": { + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "@types/readable-stream": "^2.3.13", + "ethereum-cryptography": "0.1.3", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-trie/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@nomicfoundation/ethereumjs-tx": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.2.tgz", + "integrity": "sha512-T+l4/MmTp7VhJeNloMkM+lPU3YMUaXdcXgTGCf8+ZFvV9NYZTRLFekRwlG6/JMmVfIfbrW+dRRJ9A6H5Q/Z64g==", + "dependencies": { + "@chainsafe/ssz": "^0.9.2", + "@ethersproject/providers": "^5.7.2", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-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.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.2.tgz", + "integrity": "sha512-4Wu9D3LykbSBWZo8nJCnzVIYGvGCuyiYLIJa9XXNVt1q1jUzHdB+sJvx95VGCpPkCT+IbLecW6yfzy3E1bQrwQ==", + "dependencies": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-util/node_modules/@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "node_modules/@nomicfoundation/ethereumjs-util/node_modules/@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + }, + "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/ethereumjs-vm": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.2.tgz", + "integrity": "sha512-Bj3KZT64j54Tcwr7Qm/0jkeZXJMfdcAtRBedou+Hx0dPOSIgqaIr0vvLwP65TpHbak2DmAq+KJbW2KNtIoFwvA==", + "dependencies": { + "@nomicfoundation/ethereumjs-block": "5.0.2", + "@nomicfoundation/ethereumjs-blockchain": "7.0.2", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-evm": "2.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-statemanager": "2.0.2", + "@nomicfoundation/ethereumjs-trie": "6.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "mcl-wasm": "^0.7.1", + "rustbn.js": "~0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-vm/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "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.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.1.tgz", + "integrity": "sha512-1LMtXj1puAxyFusBgUIy5pZk3073cNXYnXUpuNKFghHbIit/xZgbk0AokpUADbNm3gyD6bFWl3LRFh3dhVdREg==", + "engines": { + "node": ">= 12" + }, + "optionalDependencies": { + "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.1", + "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.1", + "@nomicfoundation/solidity-analyzer-freebsd-x64": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-arm64-msvc": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-ia32-msvc": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.1" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-arm64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.1.tgz", + "integrity": "sha512-KcTodaQw8ivDZyF+D76FokN/HdpgGpfjc/gFCImdLUyqB6eSWVaZPazMbeAjmfhx3R0zm/NYVzxwAokFKgrc0w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.1.tgz", + "integrity": "sha512-XhQG4BaJE6cIbjAVtzGOGbK3sn1BO9W29uhk9J8y8fZF1DYz0Doj8QDMfpMu+A6TjPDs61lbsmeYodIDnfveSA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-freebsd-x64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-freebsd-x64/-/solidity-analyzer-freebsd-x64-0.1.1.tgz", + "integrity": "sha512-GHF1VKRdHW3G8CndkwdaeLkVBi5A9u2jwtlS7SLhBc8b5U/GcoL39Q+1CSO3hYqePNP+eV5YI7Zgm0ea6kMHoA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.1.tgz", + "integrity": "sha512-g4Cv2fO37ZsUENQ2vwPnZc2zRenHyAxHcyBjKcjaSmmkKrFr64yvzeNO8S3GBFCo90rfochLs99wFVGT/0owpg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.1.tgz", + "integrity": "sha512-WJ3CE5Oek25OGE3WwzK7oaopY8xMw9Lhb0mlYuJl/maZVo+WtP36XoQTb7bW/i8aAdHW5Z+BqrHMux23pvxG3w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.1.tgz", + "integrity": "sha512-5WN7leSr5fkUBBjE4f3wKENUy9HQStu7HmWqbtknfXkkil+eNWiBV275IOlpXku7v3uLsXTOKpnnGHJYI2qsdA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.1.tgz", + "integrity": "sha512-KdYMkJOq0SYPQMmErv/63CwGwMm5XHenEna9X9aB8mQmhDBrYrlAOSsIPgFCUSL0hjxE3xHP65/EPXR/InD2+w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-arm64-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.1.tgz", + "integrity": "sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-ia32-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.1.tgz", + "integrity": "sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.1.tgz", + "integrity": "sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@scure/base": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.3.tgz", + "integrity": "sha512-/+SgoRjLq7Xlf0CWuLHq2LUZeL/w65kfzAPG5NH9pcmBhs+nunQTn4gvdwgMTIXnt9b2C/1SeL2XiysZEyIC9Q==", + "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/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==" + }, + "node_modules/@types/bn.js": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.2.tgz", + "integrity": "sha512-dkpZu0szUtn9UXTmw+e0AJFd4D2XAxDnsCLdc05SfqpqzPEBft8eQr8uaFitfo/dUUOZERaLec2hHMG87A4Dxg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.7.tgz", + "integrity": "sha512-MhzcwU8aUygZroVwL2jeYk6JisJrPl/oov/gsgGCue9mkgl9wjGbzReYQClxiUgFDnib9FuHqTndccKeZKxTRw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "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": "20.7.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.7.0.tgz", + "integrity": "sha512-zI22/pJW2wUZOVyguFaUL1HABdmSVxpXrzIqkjsHmyUjNhPoWM1CKfvVuXfetHhIok4RY573cqS0mZ1SJEnoTg==" + }, + "node_modules/@types/pbkdf2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", + "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/readable-stream": { + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.15.tgz", + "integrity": "sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ==", + "dependencies": { + "@types/node": "*", + "safe-buffer": "~5.1.1" + } + }, + "node_modules/@types/secp256k1": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.4.tgz", + "integrity": "sha512-oN0PFsYxDZnX/qSJ5S5OwaEDTYfekhvaM5vqui2bu1AA39pKofmgL104Q29KiOXizXS2yLjSzc5YdTyMKdcy4A==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.25", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.25.tgz", + "integrity": "sha512-gy7iPgwnzNvxgAEi2bXOHWCVOG6f7xsprVJH4MjlAWeBmJ7vh/Y1kwMtUrs64ztf24zVIRCpr3n/z6gm9QIkgg==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.1.tgz", + "integrity": "sha512-axdPBuLuEJt0c4yI5OZssC19K2Mq1uKdrfZBzuxLvaztgqUtFYZUNw7lETExPYJR9jdEoIg4mb7RQKRQzOkeGQ==" + }, + "node_modules/abstract-level": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-1.0.3.tgz", + "integrity": "sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA==", + "dependencies": { + "buffer": "^6.0.3", + "catering": "^2.1.0", + "is-buffer": "^2.0.5", + "level-supports": "^4.0.0", + "level-transcoder": "^1.0.1", + "module-error": "^1.0.1", + "queue-microtask": "^1.2.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "engines": { + "node": ">=0.3.0" + } + }, + "node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==" + }, + "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-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": "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/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.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "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/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" + }, + "node_modules/bigint-crypto-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/bigint-crypto-utils/-/bigint-crypto-utils-3.3.0.tgz", + "integrity": "sha512-jOTSb+drvEDxEq6OuUybOAv/xxoh3cuYRUIPyu8sSHQNKM303UQ2R1DAo45o1AkcIXw6fzbaFI1+xGGdaXs2lg==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" + }, + "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/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.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, + "node_modules/browser-level": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browser-level/-/browser-level-1.0.1.tgz", + "integrity": "sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ==", + "dependencies": { + "abstract-level": "^1.0.2", + "catering": "^2.1.1", + "module-error": "^1.0.2", + "run-parallel-limit": "^1.1.0" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" + }, + "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/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "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/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "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/case": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/case/-/case-1.6.3.tgz", + "integrity": "sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/catering": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", + "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", + "engines": { + "node": ">=6" + } + }, + "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/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "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/classic-level": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/classic-level/-/classic-level-1.3.0.tgz", + "integrity": "sha512-iwFAJQYtqRTRM0F6L8h4JCt00ZSGdOyqh7yVrhhjrOpFhmBjNlRUey64MCiyo6UmQHMJ+No3c81nujPv+n9yrg==", + "hasInstallScript": true, + "dependencies": { + "abstract-level": "^1.0.2", + "catering": "^2.1.0", + "module-error": "^1.0.1", + "napi-macros": "^2.2.2", + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "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": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==" + }, + "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/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "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.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "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.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "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.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/ethers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" + } + }, + "node_modules/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/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "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.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "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/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==" + }, + "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/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "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.17.3", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.17.3.tgz", + "integrity": "sha512-SFZoYVXW1bWJZrIIKXOA+IgcctfuKXDwENywiYNT2dM3YQc4fXNaTbuk/vpPzHIF50upByx4zW5EqczKYQubsA==", + "dependencies": { + "@ethersproject/abi": "^5.1.2", + "@metamask/eth-sig-util": "^4.0.0", + "@nomicfoundation/ethereumjs-block": "5.0.2", + "@nomicfoundation/ethereumjs-blockchain": "7.0.2", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-evm": "2.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-statemanager": "2.0.2", + "@nomicfoundation/ethereumjs-trie": "6.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "@nomicfoundation/ethereumjs-vm": "7.0.2", + "@nomicfoundation/solidity-analyzer": "^0.1.0", + "@sentry/node": "^5.18.1", + "@types/bn.js": "^5.1.0", + "@types/lru-cache": "^5.1.0", + "adm-zip": "^0.4.16", + "aggregate-error": "^3.0.0", + "ansi-escapes": "^4.3.0", + "chalk": "^2.4.2", + "chokidar": "^3.4.0", + "ci-info": "^2.0.0", + "debug": "^4.1.1", + "enquirer": "^2.3.0", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^1.0.3", + "ethereumjs-abi": "^0.6.8", + "find-up": "^2.1.0", + "fp-ts": "1.19.3", + "fs-extra": "^7.0.1", + "glob": "7.2.0", + "immutable": "^4.0.0-rc.12", + "io-ts": "1.10.4", + "keccak": "^3.0.2", + "lodash": "^4.17.11", + "mnemonist": "^0.38.0", + "mocha": "^10.0.0", + "p-map": "^4.0.0", + "raw-body": "^2.4.1", + "resolve": "1.17.0", + "semver": "^6.3.0", + "solc": "0.7.3", + "source-map-support": "^0.5.13", + "stacktrace-parser": "^0.1.10", + "tsort": "0.0.1", + "undici": "^5.14.0", + "uuid": "^8.3.2", + "ws": "^7.4.6" + }, + "bin": { + "hardhat": "internal/cli/bootstrap.js" + }, + "peerDependencies": { + "ts-node": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/hardhat/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/hardhat/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/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/hardhat/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/hardhat/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/hardhat/node_modules/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/hardhat/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/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/hardhat/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "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/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-base/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/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/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/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/immutable": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==" + }, + "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==", + "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-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/is-core-module": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "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/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/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/js-sdsl": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.2.tgz", + "integrity": "sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + }, + "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/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/klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", + "optionalDependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/level": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/level/-/level-8.0.0.tgz", + "integrity": "sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ==", + "dependencies": { + "browser-level": "^1.0.1", + "classic-level": "^1.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/level" + } + }, + "node_modules/level-supports": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-4.0.1.tgz", + "integrity": "sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/level-transcoder": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/level-transcoder/-/level-transcoder-1.0.1.tgz", + "integrity": "sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==", + "dependencies": { + "buffer": "^6.0.3", + "module-error": "^1.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "engines": { + "node": ">=6" + } + }, + "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/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/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/mcl-wasm": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz", + "integrity": "sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ==", + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/memory-level": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/memory-level/-/memory-level-1.0.0.tgz", + "integrity": "sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og==", + "dependencies": { + "abstract-level": "^1.0.0", + "functional-red-black-tree": "^1.0.1", + "module-error": "^1.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "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.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "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/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.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "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/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/module-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/module-error/-/module-error-1.0.2.tgz", + "integrity": "sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-macros": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.2.2.tgz", + "integrity": "sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g==" + }, + "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.6.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.1.tgz", + "integrity": "sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" + }, + "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/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/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "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/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "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": "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/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/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.6", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", + "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "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/run-parallel-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", + "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rustbn.js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz", + "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==" + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "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.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "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/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/solc": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", + "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", + "dependencies": { + "command-exists": "^1.2.8", + "commander": "3.0.2", + "follow-redirects": "^1.12.1", + "fs-extra": "^0.30.0", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "require-from-string": "^2.0.0", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "bin": { + "solcjs": "solcjs" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/solc/node_modules/fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "node_modules/solc/node_modules/jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "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/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder/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/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": "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/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" + }, + "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/ts-jest-resolver": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ts-jest-resolver/-/ts-jest-resolver-2.0.1.tgz", + "integrity": "sha512-FolE73BqVZCs8/RbLKxC67iaAtKpBWx7PeLKFW2zJQlOf9j851I7JRxSDenri2NFvVH3QP7v3S8q1AmL24Zb9Q==", + "dependencies": { + "jest-resolve": "^29.5.0" + } + }, + "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.25.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.25.2.tgz", + "integrity": "sha512-tch8RbCfn1UUH1PeVCXva4V8gDpGAud/w0WubD6sHC46vYQ3KDxL+xv1A2UxK0N6jrVedutuPHxe1XIoqerwMw==", + "dependencies": { + "busboy": "^1.6.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "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/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==" + }, + "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/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.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "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/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "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.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "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/packages/integration-tests/src/playbook/package.json b/packages/integration-tests/src/playbook/package.json new file mode 100644 index 0000000000..a4cbf2fda3 --- /dev/null +++ b/packages/integration-tests/src/playbook/package.json @@ -0,0 +1,32 @@ +{ + "name": "playbook", + "version": "0.0.0", + "description": "The test solution for transaction processing`", + "repository": "https://github.com/matter-labs/block-explorer", + "private": true, + "author": "Matter Labs", + "license": "MIT", + "scripts": { + "compile": "hardhat compile", + "clean": "hardhat clean", + "deploy:greeter": "hardhat deploy-zksync --script deploy-greeter.ts", + "deploy:use:greeter": "hardhat deploy-zksync --script use-greeter.ts", + "deployNFTtoL1": "npx hardhat run --network localhost deploy/nftToL1.ts", + "deployNFTtoL2": "hardhat deploy-zksync --script nftToL2.ts", + "deployToL2": "hardhat deploy-zksync --script erc20toL2.ts", + "deployToL1": "npx hardhat run --network localhost deploy/erc20toL1.ts", + "deploy:paymaster": "hardhat deploy-zksync --script deploy-paymaster.ts", + "deploy:use:paymaster": "hardhat deploy-zksync --script use-paymaster.ts", + "merge:multitransfer": "npx hardhat flatten ./contracts/InitialMultiTransfer.sol > ./contracts/MultiTransfer.sol ; sed -i.bak -e 's/\\/\\/ SPDX-License-Identifier: MIT//g' ./contracts/MultiTransfer.sol ; rm ./contracts/MultiTransfer.sol.bak\n", + "deploy:multitransfer": "hardhat deploy-zksync --script multiTransferETH.ts", + "deploy:use:multitransfer": "npx hardhat deploy-zksync --script use-multitransferETH.ts", + "deploy:multicall:root": "hardhat deploy-zksync --script multicallRoot.ts", + "deploy:multicall:middle": "hardhat deploy-zksync --script multicallMiddle.ts", + "deploy:multicall:caller": "hardhat deploy-zksync --script multicallCaller.ts", + "deploy:use:multicall": "hardhat deploy-zksync --script use-multiCall.ts" + }, + "dependencies": { + "hardhat": "^2.17.3", + "ts-jest-resolver": "^2.0.0" + } +} diff --git a/packages/integration-tests/src/playbook/playbook.ts b/packages/integration-tests/src/playbook/playbook.ts new file mode 100644 index 0000000000..d23a58929f --- /dev/null +++ b/packages/integration-tests/src/playbook/playbook.ts @@ -0,0 +1,107 @@ +import { deployERC20toL1 } from "./scenarios/deploy/deployERC20toL1"; +import { deployERC20toL2 } from "./scenarios/deploy/deployERC20toL2"; +import { deployGreeterToL2 } from "./scenarios/deploy/deployGreeterToL2"; +import { deployMulticallContracts } from "./scenarios/deploy/deployMulticallContracts"; +import { deployMultitransferETH } from "./scenarios/deploy/deployMultitransferETH"; +import { deployNFTtoL1 } from "./scenarios/deploy/deployNFTtoL1"; +import { deployNFTtoL2 } from "./scenarios/deploy/deployNFTtoL2"; +import { deployViaPaymaster } from "./scenarios/deploy/deployViaPaymaster"; +import { depositERC20 } from "./scenarios/deposit/depositERC20"; +import { depositEth } from "./scenarios/deposit/depositETH"; +import { transferERC20 } from "./scenarios/transfers/transferERC20"; +import { transferEth } from "./scenarios/transfers/transferETH"; +import { transferFailedState } from "./scenarios/transfers/transferFailedState"; +import { useGreeter } from "./scenarios/transfers/useGreeter"; +import { useMultiCallContracts } from "./scenarios/transfers/useMultiCall"; +import { useMultitransferETH } from "./scenarios/transfers/useMultitransferETH"; +import { usePaymaster } from "./scenarios/transfers/usePaymaster"; +import { withdrawERC20 } from "./scenarios/withdrawal/withdrawERC20"; +import { withdrawERC20toOtherAddress } from "./scenarios/withdrawal/withdrawERC20toOtherAddress"; +import { withdrawETH } from "./scenarios/withdrawal/withdrawETH"; +import { withdrawETHtoOtherAddress } from "./scenarios/withdrawal/withdrawETHtoOtherAddress"; + +export class Playbook { + public async deployGreeterToL2() { + return await deployGreeterToL2(); + } + + public async useGreeter() { + return await useGreeter(); + } + + public async deployNFTtoL1() { + return await deployNFTtoL1(); + } + + public async deployNFTtoL2() { + return await deployNFTtoL2(); + } + + public async deployERC20toL2() { + return await deployERC20toL2(); + } + + public async deployERC20toL1() { + return await deployERC20toL1(); + } + + public async depositERC20(sum: string, tokenAddress: string, units?: number) { + return await depositERC20(sum, tokenAddress, units); + } + + public async depositETH(sum: string) { + return await depositEth(sum); + } + + public async transferETH(sum: string, address?: string) { + return await transferEth(sum, address); + } + + public async transferERC20(sum: string, tokenAddress, tokenName) { + return await transferERC20(sum, tokenAddress, tokenName); + } + + public async transferFailedState(tokenAddress: string, tokenName?: string) { + return await transferFailedState(tokenAddress, tokenName); + } + + public async deployViaPaymaster() { + return await deployViaPaymaster(); + } + + public async usePaymaster() { + return await usePaymaster(); + } + + public async withdrawETH() { + return await withdrawETH(); + } + + public async withdrawERC20(address: string) { + return await withdrawERC20(address); + } + + public async withdrawETHtoOtherAddress() { + return await withdrawETHtoOtherAddress(); + } + + public async withdrawERC20toOtherAddress(address: string) { + return await withdrawERC20toOtherAddress(address); + } + + public async deployMultiTransferETH() { + return await deployMultitransferETH(); + } + + public async useMultiTransferETH() { + return await useMultitransferETH(); + } + + public async deployMultiCallContracts() { + return await deployMulticallContracts(); + } + + public async useMultiCallContracts() { + return await useMultiCallContracts(); + } +} diff --git a/packages/integration-tests/src/playbook/scenarios/deploy/deployERC20toL1.ts b/packages/integration-tests/src/playbook/scenarios/deploy/deployERC20toL1.ts new file mode 100644 index 0000000000..5860c7bc50 --- /dev/null +++ b/packages/integration-tests/src/playbook/scenarios/deploy/deployERC20toL1.ts @@ -0,0 +1,16 @@ +import { Buffer, Logger } from "../../../entities"; +import { Helper } from "../../../helper"; + +export const deployERC20toL1 = async function () { + const helper = new Helper(); + const playbookRoot = "src/playbook"; + const bufferFile = playbookRoot + "/" + Buffer.L1; + + await helper.executeScript(`cd ${playbookRoot} && npm run compile`); + await helper.executeScript(`cd ${playbookRoot} && npm run deployToL1`); + + const deployedToken = await helper.getStringFromFile(bufferFile); + console.log("The custom ERC20 token has been deployed to L1: ", Logger.textSeparator, deployedToken); + + return deployedToken; +}; diff --git a/packages/integration-tests/src/playbook/scenarios/deploy/deployERC20toL2.ts b/packages/integration-tests/src/playbook/scenarios/deploy/deployERC20toL2.ts new file mode 100644 index 0000000000..469ae20867 --- /dev/null +++ b/packages/integration-tests/src/playbook/scenarios/deploy/deployERC20toL2.ts @@ -0,0 +1,16 @@ +import { Buffer, Logger } from "../../../entities"; +import { Helper } from "../../../helper"; + +export const deployERC20toL2 = async function () { + const helper = new Helper(); + const playbookRoot = "src/playbook"; + const bufferFile = playbookRoot + "/" + Buffer.L2; + + await helper.executeScript(`cd ${playbookRoot} && npm run compile`); + await helper.executeScript(`cd ${playbookRoot} && npm run deployToL2`); + + const deployedToken = await helper.getStringFromFile(bufferFile); + console.log("The custom ERC20 token has been deployed to L2: ", Logger.textSeparator, deployedToken); + + return deployedToken; +}; diff --git a/packages/integration-tests/src/playbook/scenarios/deploy/deployGreeterToL2.ts b/packages/integration-tests/src/playbook/scenarios/deploy/deployGreeterToL2.ts new file mode 100644 index 0000000000..934b175849 --- /dev/null +++ b/packages/integration-tests/src/playbook/scenarios/deploy/deployGreeterToL2.ts @@ -0,0 +1,18 @@ +import { Buffer, Logger } from "../../../entities"; +import { Helper } from "../../../helper"; + +let deployedContract: string; + +export const deployGreeterToL2 = async function () { + const helper = new Helper(); + const playbookRoot = "src/playbook"; + const bufferFile = playbookRoot + "/" + Buffer.greeterL2; + + await helper.executeScript(`cd ${playbookRoot} && npm run compile`); + await helper.executeScript(`cd ${playbookRoot} && npm run deploy:greeter`); + + deployedContract = await helper.getStringFromFile(bufferFile); + console.log("The Greeter contract has been deployed to L2: ", Logger.textSeparator, deployedContract); + + return deployedContract; +}; diff --git a/packages/integration-tests/src/playbook/scenarios/deploy/deployMulticallContracts.ts b/packages/integration-tests/src/playbook/scenarios/deploy/deployMulticallContracts.ts new file mode 100644 index 0000000000..bded14535f --- /dev/null +++ b/packages/integration-tests/src/playbook/scenarios/deploy/deployMulticallContracts.ts @@ -0,0 +1,28 @@ +import { Buffer } from "../../../entities"; +import { Helper } from "../../../helper"; + +export const deployMulticallContracts = async function () { + const helper = new Helper(); + const playbookRoot = "src/playbook"; + const bufferFileRoot = playbookRoot + "/" + Buffer.addressMultiCallRoot; + const bufferFileMiddle = playbookRoot + "/" + Buffer.addressMultiCallMiddle; + const bufferFileCaller = playbookRoot + "/" + Buffer.addressMultiCallCaller; + + await helper.executeScript(`cd ${playbookRoot} && npm run compile`); + await helper.executeScript(`cd ${playbookRoot} && npm run deploy:multicall:root`); + await helper.executeScript(`cd ${playbookRoot} && npm run deploy:multicall:middle`); + await helper.executeScript(`cd ${playbookRoot} && npm run deploy:multicall:caller`); + + const multiCallRoot = await helper.getStringFromFile(bufferFileRoot); + const multiCallMiddle = await helper.getStringFromFile(bufferFileMiddle); + const multiCallCaller = await helper.getStringFromFile(bufferFileCaller); + + console.log( + "Multicall contracts (Root, Middle and Caller) have been deployed to the address: ", + multiCallRoot, + multiCallMiddle, + multiCallCaller + ); + + return [multiCallRoot, multiCallMiddle, multiCallCaller]; +}; diff --git a/packages/integration-tests/src/playbook/scenarios/deploy/deployMultitransferETH.ts b/packages/integration-tests/src/playbook/scenarios/deploy/deployMultitransferETH.ts new file mode 100644 index 0000000000..f86b1a1e73 --- /dev/null +++ b/packages/integration-tests/src/playbook/scenarios/deploy/deployMultitransferETH.ts @@ -0,0 +1,17 @@ +import { Buffer } from "../../../entities"; +import { Helper } from "../../../helper"; + +export const deployMultitransferETH = async function () { + const helper = new Helper(); + const playbookRoot = "src/playbook"; + const bufferFile = playbookRoot + "/" + Buffer.addressMultiTransferETH; + + await helper.executeScript(`cd ${playbookRoot} && npm run compile`); + await helper.executeScript(`cd ${playbookRoot} && npm run deploy:multitransfer`); + + const multiTransferContractETH = await helper.getStringFromFile(bufferFile); + + console.log("The custom multitransfer contract ETH has been deployed to the address: ", multiTransferContractETH); + + return multiTransferContractETH; +}; diff --git a/packages/integration-tests/src/playbook/scenarios/deploy/deployNFTtoL1.ts b/packages/integration-tests/src/playbook/scenarios/deploy/deployNFTtoL1.ts new file mode 100644 index 0000000000..ad59eb971a --- /dev/null +++ b/packages/integration-tests/src/playbook/scenarios/deploy/deployNFTtoL1.ts @@ -0,0 +1,16 @@ +import { Buffer, Logger } from "../../../entities"; +import { Helper } from "../../../helper"; + +export const deployNFTtoL1 = async function () { + const helper = new Helper(); + const playbookRoot = "src/playbook"; + const bufferFile = playbookRoot + "/" + Buffer.NFTtoL1; + + await helper.executeScript(`cd ${playbookRoot} && npm run compile`); + await helper.executeScript(`cd ${playbookRoot} && npm run deployNFTtoL1`); + + const deployedNFT = await helper.getStringFromFile(bufferFile); + console.log("The NFT has been deployed to L1: ", Logger.textSeparator, deployedNFT); + + return deployedNFT; +}; diff --git a/packages/integration-tests/src/playbook/scenarios/deploy/deployNFTtoL2.ts b/packages/integration-tests/src/playbook/scenarios/deploy/deployNFTtoL2.ts new file mode 100644 index 0000000000..25925e28b0 --- /dev/null +++ b/packages/integration-tests/src/playbook/scenarios/deploy/deployNFTtoL2.ts @@ -0,0 +1,16 @@ +import { Buffer, Logger } from "../../../entities"; +import { Helper } from "../../../helper"; + +export const deployNFTtoL2 = async function () { + const helper = new Helper(); + const playbookRoot = "src/playbook"; + const bufferFile = playbookRoot + "/" + Buffer.NFTtoL2; + + await helper.executeScript(`cd ${playbookRoot} && npm run compile`); + await helper.executeScript(`cd ${playbookRoot} && npm run deployNFTtoL2`); + + const deployedNFT = await helper.getStringFromFile(bufferFile); + console.log("The NFT has been deployed to L2: ", Logger.textSeparator, deployedNFT); + + return deployedNFT; +}; diff --git a/packages/integration-tests/src/playbook/scenarios/deploy/deployViaPaymaster.ts b/packages/integration-tests/src/playbook/scenarios/deploy/deployViaPaymaster.ts new file mode 100644 index 0000000000..d047685687 --- /dev/null +++ b/packages/integration-tests/src/playbook/scenarios/deploy/deployViaPaymaster.ts @@ -0,0 +1,20 @@ +import { Buffer } from "../../../entities"; +import { Helper } from "../../../helper"; + +export const deployViaPaymaster = async function () { + const helper = new Helper(); + const playbookRoot = "src/playbook/"; + const bufferPaymaster = playbookRoot + Buffer.paymaster; + const bufferCustomToken = playbookRoot + Buffer.paymaster; + + await helper.executeScript(`cd ${playbookRoot} && npm run compile`); + await helper.executeScript(`cd ${playbookRoot} && npm run deploy:paymaster`); + + const paymasterAddress = await helper.getStringFromFile(bufferPaymaster); + const deployedToken = await helper.getStringFromFile(bufferCustomToken); + + console.log("The custom token has been deployed via Paymaster: ", deployedToken); + console.log("The Paymaster transaction: ", paymasterAddress); + + return [deployedToken, paymasterAddress]; +}; diff --git a/packages/integration-tests/src/playbook/scenarios/deposit/depositERC20.ts b/packages/integration-tests/src/playbook/scenarios/deposit/depositERC20.ts new file mode 100644 index 0000000000..f18724a450 --- /dev/null +++ b/packages/integration-tests/src/playbook/scenarios/deposit/depositERC20.ts @@ -0,0 +1,37 @@ +import * as ethers from "ethers"; +import { promises as fs } from "fs"; +import * as zksync from "zksync-web3"; + +import { localConfig } from "../../../config"; +import { Buffer, Logger, Wallets } from "../../../entities"; +import { Helper } from "../../../helper"; + +const helper = new Helper(); +const syncProvider = new zksync.Provider(localConfig.L2Network); +const ethProvider = ethers.getDefaultProvider(localConfig.L1Network); +const syncWallet = new zksync.Wallet(localConfig.privateKey, syncProvider, ethProvider); +const playbookRoot = "src/playbook"; +const bufferFile = playbookRoot + "/" + Buffer.L2deposited; + +export const depositERC20 = async function (sum = "0.5", tokenAddress: string, units = 18) { + const deposit = await syncWallet.deposit({ + to: Wallets.richWalletAddress, + token: tokenAddress, + amount: ethers.utils.parseUnits(sum, units), + approveERC20: true, + l2GasLimit: localConfig.l2GasLimit, + overrides: localConfig.gasLimit, + }); + + const txHash = deposit.hash; + + await deposit.wait(1); + await deposit.waitL1Commit(1); + + const l2TokenAddress = await syncProvider.l2TokenAddress(tokenAddress); + console.log("L2 token address ", l2TokenAddress); + await fs.writeFile(bufferFile, l2TokenAddress); + await helper.txHashLogger(Logger.deposit, txHash, "ERC20 token"); + + return txHash; +}; diff --git a/packages/integration-tests/src/playbook/scenarios/deposit/depositETH.ts b/packages/integration-tests/src/playbook/scenarios/deposit/depositETH.ts new file mode 100644 index 0000000000..e35e6b6259 --- /dev/null +++ b/packages/integration-tests/src/playbook/scenarios/deposit/depositETH.ts @@ -0,0 +1,26 @@ +import * as ethers from "ethers"; +import * as zksync from "zksync-web3"; + +import { localConfig } from "../../../config"; +import { Logger } from "../../../entities"; +import { Helper } from "../../../helper"; + +export const depositEth = async function (sum = "0.000009") { + const helper = new Helper(); + const syncProvider = new zksync.Provider(localConfig.L2Network); + const ethProvider = ethers.getDefaultProvider(localConfig.L1Network); + const syncWallet = new zksync.Wallet(localConfig.privateKey, syncProvider, ethProvider); + + const deposit = await syncWallet.deposit({ + token: zksync.utils.ETH_ADDRESS, + amount: ethers.utils.parseEther(sum), + l2GasLimit: localConfig.l2GasLimit, + }); + + const txHash = deposit.hash; + + await deposit.wait(1); + await helper.txHashLogger(Logger.deposit, txHash, "ETH"); + + return txHash; +}; diff --git a/packages/integration-tests/src/playbook/scenarios/transfers/transferERC20.ts b/packages/integration-tests/src/playbook/scenarios/transfers/transferERC20.ts new file mode 100644 index 0000000000..44316badf4 --- /dev/null +++ b/packages/integration-tests/src/playbook/scenarios/transfers/transferERC20.ts @@ -0,0 +1,26 @@ +import * as ethers from "ethers"; +import * as zksync from "zksync-web3"; + +import { localConfig } from "../../../config"; +import { Logger, Wallets } from "../../../entities"; +import { Helper } from "../../../helper"; + +export const transferERC20 = async function (sum: string, tokenAddress: string, tokenName?: string /*, units = 18*/) { + const helper = new Helper(); + const syncProvider = new zksync.Provider(localConfig.L2Network); + const ethProvider = ethers.getDefaultProvider(localConfig.L1Network); + const syncWallet = new zksync.Wallet(localConfig.privateKey, syncProvider, ethProvider); + const syncWallet2 = new zksync.Wallet(Wallets.secondWalletPrivateKey, syncProvider, ethProvider); + + const transfer = await syncWallet.transfer({ + to: syncWallet2.address, + token: tokenAddress, + amount: ethers.utils.parseEther(sum), + overrides: localConfig.gasLimit, + }); + + const txHash = transfer.hash; + await helper.txHashLogger(Logger.transfer, txHash, tokenName); + + return txHash; +}; diff --git a/packages/integration-tests/src/playbook/scenarios/transfers/transferETH.ts b/packages/integration-tests/src/playbook/scenarios/transfers/transferETH.ts new file mode 100644 index 0000000000..b6d801eb97 --- /dev/null +++ b/packages/integration-tests/src/playbook/scenarios/transfers/transferETH.ts @@ -0,0 +1,25 @@ +import * as ethers from "ethers"; +import * as zksync from "zksync-web3"; + +import { localConfig } from "../../../config"; +import { Logger, Wallets } from "../../../entities"; +import { Helper } from "../../../helper"; + +export const transferEth = async function (sum = "0.000009", address: string = Wallets.mainWalletPrivateKey) { + const helper = new Helper(); + const syncProvider = new zksync.Provider(localConfig.L2Network); + const ethProvider = ethers.getDefaultProvider(localConfig.L1Network); + const syncWallet = new zksync.Wallet(localConfig.privateKey, syncProvider, ethProvider); + const syncWallet2 = new zksync.Wallet(address, syncProvider, ethProvider); + + const transfer = await syncWallet.transfer({ + to: syncWallet2.address, + token: zksync.utils.ETH_ADDRESS, + amount: ethers.utils.parseEther(sum), + }); + + const txHash = transfer.hash; + await helper.txHashLogger(Logger.transfer, txHash, "ETH"); + + return txHash; +}; diff --git a/packages/integration-tests/src/playbook/scenarios/transfers/transferFailedState.ts b/packages/integration-tests/src/playbook/scenarios/transfers/transferFailedState.ts new file mode 100644 index 0000000000..77bf391107 --- /dev/null +++ b/packages/integration-tests/src/playbook/scenarios/transfers/transferFailedState.ts @@ -0,0 +1,26 @@ +import * as ethers from "ethers"; +import * as zksync from "zksync-web3"; + +import { localConfig } from "../../../config"; +import { Logger } from "../../../entities"; +import { Helper } from "../../../helper"; + +export const transferFailedState = async function (tokenAddress: string, tokenName?: string) { + const helper = new Helper(); + const syncProvider = new zksync.Provider(localConfig.L2Network); + const ethProvider = ethers.getDefaultProvider(localConfig.L1Network); + const syncWallet = new zksync.Wallet(localConfig.privateKey, syncProvider, ethProvider); + const amount = ethers.utils.parseEther("1.0"); + + const transfer = await syncWallet.transfer({ + to: "0x0000000000000000000000000000000000000000", + token: tokenAddress, + amount, + overrides: localConfig.gasLimit, + }); + + const txHash = transfer.hash; + await helper.txHashLogger(Logger.txFailedState, txHash, tokenName); + + return txHash; +}; diff --git a/packages/integration-tests/src/playbook/scenarios/transfers/useGreeter.ts b/packages/integration-tests/src/playbook/scenarios/transfers/useGreeter.ts new file mode 100644 index 0000000000..f9f77d2e36 --- /dev/null +++ b/packages/integration-tests/src/playbook/scenarios/transfers/useGreeter.ts @@ -0,0 +1,17 @@ +import { Buffer } from "../../../entities"; +import { Helper } from "../../../helper"; + +export const useGreeter = async function () { + const helper = new Helper(); + const playbookRoot = "src/playbook/"; + const txBuffer = playbookRoot + Buffer.executeGreeterTx; + + await helper.executeScript(`cd ${playbookRoot} && npm run compile`); + await helper.executeScript(`cd ${playbookRoot} && npm run deploy:use:greeter`); + + const txGreeting = await helper.getStringFromFile(txBuffer); + + console.log("Execute the SetGreeting transaction: ", txGreeting); + + return txGreeting; +}; diff --git a/packages/integration-tests/src/playbook/scenarios/transfers/useMultiCall.ts b/packages/integration-tests/src/playbook/scenarios/transfers/useMultiCall.ts new file mode 100644 index 0000000000..6abde94494 --- /dev/null +++ b/packages/integration-tests/src/playbook/scenarios/transfers/useMultiCall.ts @@ -0,0 +1,15 @@ +import { Buffer } from "../../../entities"; +import { Helper } from "../../../helper"; + +export const useMultiCallContracts = async function () { + const helper = new Helper(); + const playbookRoot = "src/playbook/"; + const txBufferUseMultiCall = playbookRoot + Buffer.txUseMultiCallContracts; + + await helper.executeScript(`cd ${playbookRoot} && npm run compile`); + await helper.executeScript(`cd ${playbookRoot} && npm run deploy:use:multicall`); + + const txUseMultiCallContracts = await helper.getStringFromFile(txBufferUseMultiCall); + + return txUseMultiCallContracts; +}; diff --git a/packages/integration-tests/src/playbook/scenarios/transfers/useMultitransferETH.ts b/packages/integration-tests/src/playbook/scenarios/transfers/useMultitransferETH.ts new file mode 100644 index 0000000000..40ed959414 --- /dev/null +++ b/packages/integration-tests/src/playbook/scenarios/transfers/useMultitransferETH.ts @@ -0,0 +1,23 @@ +import { Buffer } from "../../../entities"; +import { Helper } from "../../../helper"; + +export const useMultitransferETH = async function () { + const helper = new Helper(); + const playbookRoot = "src/playbook/"; + const txBufferETH = playbookRoot + Buffer.txMultiTransferETH; + const txBufferCustomTokenI = playbookRoot + Buffer.txMultiTransferCustomTokenI; + const txBufferCustomTokenII = playbookRoot + Buffer.txMultiTransferCustomTokenII; + + await helper.executeScript(`cd ${playbookRoot} && npm run compile`); + await helper.executeScript(`cd ${playbookRoot} && npm run deploy:use:multitransfer`); + + const txMultiTransferETH = await helper.getStringFromFile(txBufferETH); + const txMultiTransferCustomTokenI = await helper.getStringFromFile(txBufferCustomTokenI); + const txMultiTransferCustomTokenII = await helper.getStringFromFile(txBufferCustomTokenII); + + console.log("The multi transfer transaction for ETH: ", txMultiTransferETH); + console.log("The multi transfer transaction for the Custom token I: ", txMultiTransferCustomTokenI); + console.log("The multi transfer transaction for the Custom token II: ", txMultiTransferCustomTokenII); + + return [txMultiTransferETH, txMultiTransferCustomTokenI, txMultiTransferCustomTokenII]; +}; diff --git a/packages/integration-tests/src/playbook/scenarios/transfers/usePaymaster.ts b/packages/integration-tests/src/playbook/scenarios/transfers/usePaymaster.ts new file mode 100644 index 0000000000..8c667be1c5 --- /dev/null +++ b/packages/integration-tests/src/playbook/scenarios/transfers/usePaymaster.ts @@ -0,0 +1,17 @@ +import { Buffer } from "../../../entities"; +import { Helper } from "../../../helper"; + +export const usePaymaster = async function () { + const helper = new Helper(); + const playbookRoot = "src/playbook/"; + const txBuffer = playbookRoot + Buffer.paymasterTx; + + await helper.executeScript(`cd ${playbookRoot} && npm run compile`); + await helper.executeScript(`cd ${playbookRoot} && npm run deploy:use:paymaster`); + + const txPaymaster = await helper.getStringFromFile(txBuffer); + + console.log("The Paymaster transaction: ", txPaymaster); + + return txPaymaster; +}; diff --git a/packages/integration-tests/src/playbook/scenarios/withdrawal/withdrawERC20.ts b/packages/integration-tests/src/playbook/scenarios/withdrawal/withdrawERC20.ts new file mode 100644 index 0000000000..27d498dda3 --- /dev/null +++ b/packages/integration-tests/src/playbook/scenarios/withdrawal/withdrawERC20.ts @@ -0,0 +1,39 @@ +import * as ethers from "ethers"; +import * as zksync from "zksync-web3"; + +import { localConfig } from "../../../config"; +import { Logger, Wallets } from "../../../entities"; +import { Helper } from "../../../helper"; + +export const withdrawERC20 = async function (tokenAddress: string, sum = "0.2") { + const helper = new Helper(); + const syncProvider = new zksync.Provider(localConfig.L2Network); + const ethProvider = ethers.getDefaultProvider(localConfig.L1Network); + const syncWallet = new zksync.Wallet(localConfig.privateKey, syncProvider, ethProvider); + const bridges = await syncProvider.getDefaultBridgeAddresses(); + + const balance = await syncWallet.getBalance(tokenAddress); + + console.log(`Your balance is ${balance.toString()}`); + + const withdrawL2 = await syncWallet.withdraw({ + to: Wallets.richWalletAddress, + amount: ethers.utils.parseEther(sum), + token: tokenAddress, + bridgeAddress: bridges.erc20L2, + overrides: localConfig.gasLimit, + }); + + const txHash = withdrawL2.hash; + + await withdrawL2.wait(1); + await withdrawL2.waitFinalize(); + + const balanceAfter = await syncWallet.getBalance(tokenAddress); + + console.log(`Your balance is ${balanceAfter.toString()}`); + + await helper.txHashLogger(Logger.withdraw, txHash, "Custom token"); + + return txHash; +}; diff --git a/packages/integration-tests/src/playbook/scenarios/withdrawal/withdrawERC20toOtherAddress.ts b/packages/integration-tests/src/playbook/scenarios/withdrawal/withdrawERC20toOtherAddress.ts new file mode 100644 index 0000000000..ab92a9c326 --- /dev/null +++ b/packages/integration-tests/src/playbook/scenarios/withdrawal/withdrawERC20toOtherAddress.ts @@ -0,0 +1,39 @@ +import * as ethers from "ethers"; +import * as zksync from "zksync-web3"; + +import { localConfig } from "../../../config"; +import { Logger, Wallets } from "../../../entities"; +import { Helper } from "../../../helper"; + +export const withdrawERC20toOtherAddress = async function (tokenAddress: string, sum = "0.2") { + const helper = new Helper(); + const syncProvider = new zksync.Provider(localConfig.L2Network); + const ethProvider = ethers.getDefaultProvider(localConfig.L1Network); + const syncWallet = new zksync.Wallet(localConfig.privateKey, syncProvider, ethProvider); + const bridges = await syncProvider.getDefaultBridgeAddresses(); + + const balance = await syncWallet.getBalance(tokenAddress); + + console.log(`Your balance is ${balance.toString()}`); + + const withdrawL2 = await syncWallet.withdraw({ + to: Wallets.mainWalletAddress, + amount: ethers.utils.parseEther(sum), + token: tokenAddress, + bridgeAddress: bridges.erc20L2, + overrides: localConfig.gasLimit, + }); + + const txHash = withdrawL2.hash; + + await withdrawL2.wait(1); + await withdrawL2.waitFinalize(); + + const balanceAfter = await syncWallet.getBalance(tokenAddress); + + console.log(`Your balance is ${balanceAfter.toString()}`); + + await helper.txHashLogger(Logger.withdraw, txHash, "Custom token"); + + return txHash; +}; diff --git a/packages/integration-tests/src/playbook/scenarios/withdrawal/withdrawETH.ts b/packages/integration-tests/src/playbook/scenarios/withdrawal/withdrawETH.ts new file mode 100644 index 0000000000..b5daeaa52f --- /dev/null +++ b/packages/integration-tests/src/playbook/scenarios/withdrawal/withdrawETH.ts @@ -0,0 +1,25 @@ +import * as ethers from "ethers"; +import * as zksync from "zksync-web3"; + +import { localConfig } from "../../../config"; +import { Logger } from "../../../entities"; +import { Helper } from "../../../helper"; + +export const withdrawETH = async function (sum = "0.000009") { + const helper = new Helper(); + const syncProvider = new zksync.Provider(localConfig.L2Network); + const ethProvider = ethers.getDefaultProvider(localConfig.L1Network); + const syncWallet = new zksync.Wallet(localConfig.privateKey, syncProvider, ethProvider); + + const withdrawL2 = await syncWallet.withdraw({ + token: zksync.utils.ETH_ADDRESS, + amount: ethers.utils.parseEther(sum), + }); + + const txHash = withdrawL2.hash; + + await withdrawL2.waitFinalize(); + await helper.txHashLogger(Logger.withdraw, txHash, "ETH"); + + return txHash; +}; diff --git a/packages/integration-tests/src/playbook/scenarios/withdrawal/withdrawETHtoOtherAddress.ts b/packages/integration-tests/src/playbook/scenarios/withdrawal/withdrawETHtoOtherAddress.ts new file mode 100644 index 0000000000..53c217110c --- /dev/null +++ b/packages/integration-tests/src/playbook/scenarios/withdrawal/withdrawETHtoOtherAddress.ts @@ -0,0 +1,26 @@ +import * as ethers from "ethers"; +import * as zksync from "zksync-web3"; + +import { localConfig } from "../../../config"; +import { Logger, Wallets } from "../../../entities"; +import { Helper } from "../../../helper"; + +export const withdrawETHtoOtherAddress = async function (sum = "0.000009") { + const helper = new Helper(); + const syncProvider = new zksync.Provider(localConfig.L2Network); + const ethProvider = ethers.getDefaultProvider(localConfig.L1Network); + const syncWallet = new zksync.Wallet(localConfig.privateKey, syncProvider, ethProvider); + + const withdrawL2 = await syncWallet.withdraw({ + token: zksync.utils.ETH_ADDRESS, + amount: ethers.utils.parseEther(sum), + to: Wallets.mainWalletAddress, + }); + + const txHash = withdrawL2.hash; + + await withdrawL2.waitFinalize(); + await helper.txHashLogger(Logger.withdraw, txHash, "ETH"); + + return txHash; +}; diff --git a/packages/integration-tests/src/playbook/utils/displayVerificationInfo.ts b/packages/integration-tests/src/playbook/utils/displayVerificationInfo.ts new file mode 100644 index 0000000000..2f60f6377f --- /dev/null +++ b/packages/integration-tests/src/playbook/utils/displayVerificationInfo.ts @@ -0,0 +1,32 @@ +import { utils } from "ethers"; +import * as path from "path"; + +import type { ZkSyncArtifact } from "@matterlabs/hardhat-zksync-deploy/dist/types"; +import type { Contract } from "ethers"; +import type { SolcUserConfig } from "hardhat/types"; + +export default function ({ + hre, + contract, + contractConstructorArguments, + artifact, +}: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + hre: any; + contract: Contract; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + contractConstructorArguments: any[]; + artifact: ZkSyncArtifact; +}) { + console.log( + `\nVerify the contract: https://explorer.zksync.io/contracts/verify?address=${contract.address}&network=${hre.config.networks.zkSyncLocal.ethNetwork}` + ); + console.log(`Contract name: ${artifact.contractName}`); + console.log(`zkSolc Version: v${hre.userConfig.zksolc.version}`); + console.log(`Solc Version: ${(hre.userConfig.solidity as SolcUserConfig).version}`); + console.log(`Source code file path: ${path.join(__dirname, "../", artifact.sourceName)}`); + // Get constructor arguments + const contractInterface = new utils.Interface(artifact.abi); + const constructorArgs = contractInterface.encodeDeploy(contractConstructorArguments); + console.log(`Constructor arguments: ${constructorArgs}`); +} diff --git a/packages/integration-tests/src/playbook/utils/getWallet.ts b/packages/integration-tests/src/playbook/utils/getWallet.ts new file mode 100644 index 0000000000..5d2dec285e --- /dev/null +++ b/packages/integration-tests/src/playbook/utils/getWallet.ts @@ -0,0 +1,22 @@ +import { getDefaultProvider, utils } from "ethers"; +import { Provider, Wallet } from "zksync-web3"; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export default async function (hre: any) { + const syncProvider = new Provider(hre.config.networks.zkSyncLocal.url); + const ethProvider = getDefaultProvider(hre.config.networks.zkSyncLocal.ethNetwork); + + if (!process.env.WALLET_PRIVATE_KEY) { + throw new Error("WALLET_PRIVATE_KEY env variable is not set"); + } + + // Initialize the wallet. + const wallet = new Wallet(process.env.WALLET_PRIVATE_KEY as string, syncProvider, ethProvider); + console.log(`Deploying using wallet: ${wallet.address}`); + + // Wallet ETH balance + const ethBalance = await wallet.getBalance(); + console.log(`Wallet ETH balance: ${utils.formatUnits(ethBalance)} ETH\n`); + + return wallet; +} diff --git a/packages/integration-tests/tests/api/before-all/deposit.test.ts b/packages/integration-tests/tests/api/before-all/deposit.test.ts new file mode 100644 index 0000000000..daaf5367f6 --- /dev/null +++ b/packages/integration-tests/tests/api/before-all/deposit.test.ts @@ -0,0 +1,31 @@ +import { localConfig } from "../../../src/config"; +import { Buffer } from "../../../src/entities"; +import { Logger } from "../../../src/entities"; +import { Helper } from "../../../src/helper"; +import { Playbook } from "../../../src/playbook/playbook"; + +describe("Deposit", () => { + const playbook = new Playbook(); + const helper = new Helper(); + const bufferRoute = "src/playbook/"; + + let result: string; + let token: string; + jest.setTimeout(localConfig.extendedTimeout); + + //@id633 + it("Make a deposit with 0.0000001 ETH ", async () => { + result = await playbook.depositETH("0.0000001"); + await expect(result).not.toBeUndefined(); + await expect(result.includes(Logger.txHashStartsWith)).toBe(true); + }); + + //@id638 + it("Make a deposit with the Custom token ", async () => { + const bufferFile = bufferRoute + Buffer.L1; + token = await helper.getStringFromFile(bufferFile); + result = await playbook.depositERC20("100", token, 18); + await expect(result).not.toBeUndefined(); + await expect(result.includes(Logger.txHashStartsWith)).toBe(true); + }); +}); diff --git a/packages/integration-tests/tests/api/before-all/tokens.test.ts b/packages/integration-tests/tests/api/before-all/tokens.test.ts new file mode 100644 index 0000000000..9f2aee8dca --- /dev/null +++ b/packages/integration-tests/tests/api/before-all/tokens.test.ts @@ -0,0 +1,48 @@ +import * as request from "supertest"; +import { setTimeout } from "timers/promises"; + +import { environment } from "../../../src/config"; +import { localConfig } from "../../../src/config"; +import { Logger, Token } from "../../../src/entities"; +import { Playbook } from "../../../src/playbook/playbook"; + +describe("Tokens", () => { + jest.setTimeout(localConfig.standardTimeout); + + let deployedToken: string; + + describe("Deploy/check the custom ERC20 tokens", () => { + const playbook = new Playbook(); + + //@id603 + it("Deploy custom ERC20 token to L2", async () => { + deployedToken = await playbook.deployERC20toL2(); + expect(deployedToken).toContain(Logger.txHashStartsWith); + }); + + //@id1456 + it("Verify deployed to L2 custom token via /tokens/{tokenAddress}", async () => { + await setTimeout(localConfig.extendedPause); //works unstable without timeout + const apiRoute = `/tokens/${deployedToken}`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => + expect(res.body).toStrictEqual({ + l2Address: deployedToken, + l1Address: null, + symbol: Token.customL2TokenSymbol, + name: Token.customL2TokenName, + decimals: Token.customL2TokenDecimals, + }) + ); + }); + + //@id657 + it("Deploy custom ERC20 token to L1", async () => { + deployedToken = await playbook.deployERC20toL1(); + expect(deployedToken).toContain(Logger.txHashStartsWith); + }); + }); +}); diff --git a/packages/integration-tests/tests/api/common/endpoints.test.ts b/packages/integration-tests/tests/api/common/endpoints.test.ts new file mode 100644 index 0000000000..187d0418ce --- /dev/null +++ b/packages/integration-tests/tests/api/common/endpoints.test.ts @@ -0,0 +1,185 @@ +import * as request from "supertest"; +import { setTimeout } from "timers/promises"; + +import { environment, localConfig } from "../../../src/config"; +import { Buffer } from "../../../src/entities"; +import { Helper } from "../../../src/helper"; + +describe("Endpoints", () => { + const helper = new Helper(); + const bufferRoute = "src/playbook/"; + + jest.setTimeout(localConfig.extendedTimeout); + + describe("/stats", () => { + //@id1515 + it("Verify the response via /stats", async () => { + const apiRoute = `/stats`; + + await setTimeout(localConfig.standardPause); //works unstable without timeout + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(typeof res.body.lastSealedBatch).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.lastVerifiedBatch).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.lastSealedBlock).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.lastVerifiedBlock).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.totalTransactions).toStrictEqual("number")); + }); + }); + + describe("/tokens", () => { + //@id1508 + it("Verify the response via /tokens", async () => { + const l2DepositedToken = await helper.getStringFromFile(bufferRoute + Buffer.L2deposited); + const l1Token = await helper.getStringFromFile(bufferRoute + Buffer.L1); + const l2Token = await helper.getStringFromFile(bufferRoute + Buffer.L2); + + const apiRoute = `/tokens`; + + await setTimeout(localConfig.standardPause); //works unstable without timeout + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(Array.isArray(res.body.items)).toStrictEqual(true)) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ l2Address: l2DepositedToken })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ l1Address: l1Token }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ symbol: "L1" }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ name: "L1 ERC20 token" }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ decimals: 18 }))) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ l2Address: l2Token }))) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ l1Address: null }))) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ symbol: "L2" }))) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ name: "L2 ERC20 token" }))) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ decimals: 18 }))) + .expect((res) => expect(typeof res.body.meta.totalItems).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.meta.itemCount).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.meta.itemsPerPage).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.meta.totalPages).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.meta.currentPage).toStrictEqual("number")) + .expect((res) => expect(res.body.links.first).toStrictEqual("tokens?limit=10")) + .expect((res) => expect(res.body.links.previous).toStrictEqual("")) + .expect((res) => expect(typeof res.body.links.next).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.links.last).toStrictEqual("string")); + }); + }); + + describe("/batches", () => { + //@id1513 + it("Verify the response via /batches", async () => { + const apiRoute = `/batches`; + + await setTimeout(localConfig.standardPause); //works unstable without timeout + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(Array.isArray(res.body.items)).toStrictEqual(true)) + .expect((res) => expect(res.body.items.length).toBeGreaterThanOrEqual(1)) + .expect((res) => expect(typeof res.body.meta.totalItems).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.meta.itemCount).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.meta.itemsPerPage).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.meta.totalPages).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.meta.currentPage).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.links.first).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.links.previous).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.links.next).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.links.last).toStrictEqual("string")); + }); + + //@id1514 + it("Verify the response via /batches/{batchNumber}", async () => { + const batches = await request(environment.blockExplorerAPI).get("/batches"); + + const batchNumber = batches.body.items[0].number; + + const apiRoute = `/batches/${batchNumber}`; + + await setTimeout(localConfig.standardPause); //works unstable without timeout + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body.number).toStrictEqual(batchNumber)) + .expect((res) => expect(typeof res.body.timestamp).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.rootHash).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.executedAt).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.l1TxCount).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.l2TxCount).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.commitTxHash).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.committedAt).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.proveTxHash).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.provenAt).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.executeTxHash).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.l1GasPrice).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.l2FairGasPrice).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.size).toStrictEqual("number")) + .expect((res) => expect(res.body.status).toStrictEqual("verified")); + }); + }); + + describe("/blocks", () => { + //@id1511 + it("Verify the response via /blocks", async () => { + const apiRoute = `/blocks`; + + await setTimeout(localConfig.extendedPause); //works unstable without timeout + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(Array.isArray(res.body.items)).toStrictEqual(true)) + .expect((res) => expect(res.body.items.length).toBeGreaterThan(1)) + .expect((res) => expect(typeof res.body.meta.totalItems).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.meta.itemCount).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.meta.itemsPerPage).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.meta.totalPages).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.meta.currentPage).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.links.first).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.links.previous).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.links.next).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.links.last).toStrictEqual("string")); + }); + + //@id1512 + it("Verify the response via /blocks/{/blockNumber}", async () => { + const blocks = await request(environment.blockExplorerAPI).get("/blocks"); + + const blockNumber = blocks.body.items[0].number; + + const apiRoute = `/blocks/${blockNumber}`; + + await setTimeout(localConfig.extendedPause); //works unstable without timeout + + return ( + request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body.number).toStrictEqual(blockNumber)) + .expect((res) => expect(typeof res.body.hash).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.timestamp).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.gasUsed).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.l1BatchNumber).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.l1TxCount).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.l2TxCount).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.parentHash).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.gasLimit).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.baseFeePerGas).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.extraData).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.size).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.status).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.isL1BatchSealed).toStrictEqual("boolean")) + .expect((res) => expect(typeof res.body.commitTxHash).toStrictEqual("string")) + // .expect((res) => expect(typeof res.body.commitTxHash).toStrictEqual("string")) //unstable on a CI + .expect((res) => expect(typeof res.body.proveTxHash).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.committedAt).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.executedAt).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.provenAt).toStrictEqual("string")) + ); + }); + }); +}); diff --git a/packages/integration-tests/tests/api/common/nft.test.ts b/packages/integration-tests/tests/api/common/nft.test.ts new file mode 100644 index 0000000000..ed6271a478 --- /dev/null +++ b/packages/integration-tests/tests/api/common/nft.test.ts @@ -0,0 +1,54 @@ +import * as request from "supertest"; +import { setTimeout } from "timers/promises"; + +import { environment } from "../../../src/config"; +import { localConfig } from "../../../src/config"; +import { Logger } from "../../../src/entities"; +import { Playbook } from "../../../src/playbook/playbook"; + +describe("NFTs", () => { + jest.setTimeout(localConfig.standardTimeout); + + let deployedToken: string; + + describe("Deploy/check the NFT", () => { + jest.setTimeout(localConfig.standardTimeout); + const playbook = new Playbook(); + + //@id672 + it("Deploy the NFT to L1", async () => { + deployedToken = await playbook.deployNFTtoL1(); + expect(deployedToken).toContain(Logger.txHashStartsWith); + }); + + //@id671 + it("Deploy the NFT to L2", async () => { + deployedToken = await playbook.deployNFTtoL2(); + expect(deployedToken).toContain(Logger.txHashStartsWith); + }); + + //@id1457 + it("Verify deployed to L2 NFT via /address/{address}", async () => { + await setTimeout(localConfig.extendedPause); + const apiRoute = `/address/${deployedToken}`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => + expect(res.body).toEqual( + expect.objectContaining({ + type: "contract", + address: deployedToken, + balances: { + [`${deployedToken}`]: { + balance: "1", + token: null, + }, + }, + }) + ) + ); + }); + }); +}); diff --git a/packages/integration-tests/tests/api/common/transfers.test.ts b/packages/integration-tests/tests/api/common/transfers.test.ts new file mode 100644 index 0000000000..2f4bb9b1d0 --- /dev/null +++ b/packages/integration-tests/tests/api/common/transfers.test.ts @@ -0,0 +1,59 @@ +import * as request from "supertest"; +import { setTimeout } from "timers/promises"; + +import { environment } from "../../../src/config"; +import { localConfig } from "../../../src/config"; +import { Buffer, Wallets } from "../../../src/entities"; +import { Helper } from "../../../src/helper"; +import { Playbook } from "../../../src/playbook/playbook"; + +describe("Transfer", () => { + jest.setTimeout(localConfig.standardTimeout); + const helper = new Helper(); + const playbook = new Playbook(); + const bufferFile = "src/playbook/" + Buffer.L2; + let txHashEth: string; + let txHashCust: string; + let token: string; + + beforeAll(async () => { + token = await helper.getStringFromFile(bufferFile); + txHashEth = await playbook.transferETH("0.000001"); + txHashCust = await playbook.transferERC20("0.01", token, "L2"); + + return [txHashCust, txHashEth]; + }); + + //@id1447 + it("Verify transfer ETH L2-L2 via /transactions/{transactionHash}/transfers", async () => { + const apiRoute = `/transactions/${txHashEth}/transfers`; + await setTimeout(localConfig.standardPause); + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body.items[1].from).toBe(Wallets.richWalletAddress)) + .expect((res) => expect(res.body.items[1].to).toBe(Wallets.mainWalletAddress)) + .expect((res) => expect(res.body.items[1].transactionHash).toBe(txHashEth)) + .expect((res) => expect(res.body.items[1].amount).toBe("1000000000000")) + .expect((res) => expect(res.body.items[1].type).toBe("transfer")); + }); + + //@id1448 + it("Verify the custom ERC20 token transfer via /tokens/{address}/transfers", async () => { + const apiRoute = `/tokens/${token}/transfers?page=1&limit=10`; + token = await helper.getStringFromFile(bufferFile); + + await setTimeout(localConfig.standardPause); //works unstable without timeout + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body.items[0].amount).toBe("10000000000000000")) + .expect((res) => expect(res.body.items[0].from).toBe(Wallets.richWalletAddress)) + .expect((res) => expect(res.body.items[0].to).toBe(Wallets.secondWalletAddress)) + .expect((res) => expect(res.body.items[0].token).toEqual(expect.objectContaining({ l2Address: token }))) + .expect((res) => expect(res.body.items[0]).toEqual(expect.objectContaining({ transactionHash: txHashCust }))) + .expect((res) => expect(res.body.items[0]).toEqual(expect.objectContaining({ type: "transfer" }))); + }); +}); diff --git a/packages/integration-tests/tests/api/common/withdrawal.test.ts b/packages/integration-tests/tests/api/common/withdrawal.test.ts new file mode 100644 index 0000000000..68e716b0ee --- /dev/null +++ b/packages/integration-tests/tests/api/common/withdrawal.test.ts @@ -0,0 +1,345 @@ +import * as request from "supertest"; +import { setTimeout } from "timers/promises"; + +import { environment, localConfig } from "../../../src/config"; +import { Buffer, Token, Wallets } from "../../../src/entities"; +import { Logger } from "../../../src/entities"; +import { Helper } from "../../../src/helper"; +import { Playbook } from "../../../src/playbook/playbook"; + +describe("Withdrawal", () => { + const playbook = new Playbook(); + const helper = new Helper(); + const playbookRoot = "src/playbook"; + const l2Token = playbookRoot + "/" + Buffer.L2deposited; + const l1Token = playbookRoot + "/" + Buffer.L1; + + let result: string; + jest.setTimeout(localConfig.extendedTimeout); + + describe("Withdrawal ETH to the own address", () => { + //@id639 + it("Make a withdrawal to the own address with 0.0000001 ETH ", async () => { + result = await playbook.withdrawETH(); + await expect(result).not.toBeUndefined(); + await expect(result.includes(Logger.txHashStartsWith)).toBe(true); + }); + + //@id1458 + it("Verify the ETH withdrawal via /transactions/{transactionHash}", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + const apiRoute = `/transactions/${result}`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body.hash).toBe(result)) + .expect((res) => expect(res.body.to).toBe("0x000000000000000000000000000000000000800A")) + .expect((res) => expect(res.body.from).toBe(Wallets.richWalletAddress)) + .expect((res) => expect(res.body.value).toBe("9000000000000")); + }); + + //@id1459 + it("Verify the ETH withdrawal via /transactions/{transactionHash}/transfers", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + const apiRoute = `/transactions/${result}/transfers`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ to: Token.ETHER_PULL_Address })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ transactionHash: result }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ type: "fee" }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ to: Token.ETHER_ERC20_Address })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ transactionHash: result }))) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ amount: "9000000000000" }))) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ type: "transfer" }))) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ to: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ transactionHash: result }))) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ amount: "9000000000000" }))) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ type: "withdrawal" }))) + .expect((res) => + expect(res.body.items[3]).toStrictEqual(expect.objectContaining({ from: Token.ETHER_PULL_Address })) + ) + .expect((res) => + expect(res.body.items[3]).toStrictEqual(expect.objectContaining({ to: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body.items[3]).toStrictEqual(expect.objectContaining({ transactionHash: result }))) + .expect((res) => expect(res.body.items[3]).toStrictEqual(expect.objectContaining({ type: "refund" }))); + }); + }); + + describe("Withdrawal ETH to the other address", () => { + //@id640 + it("Make a withdrawal to the other address with 0.0000001 ETH ", async () => { + result = await playbook.withdrawETHtoOtherAddress(); + await expect(result).not.toBeUndefined(); + await expect(result.includes(Logger.txHashStartsWith)).toBe(true); + }); + + //@id1460 + it("Verify the ETH withdrawal to the other address via /transactions/{transactionHash}", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + const apiRoute = `/transactions/${result}`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body.hash).toBe(result)) + .expect((res) => expect(res.body.to).toBe("0x000000000000000000000000000000000000800A")) + .expect((res) => expect(res.body.from).toBe(Wallets.richWalletAddress)) + .expect((res) => expect(res.body.value).toBe("9000000000000")); + }); + + //@id1461 + it("Verify the ETH withdrawal to the other address via /transactions/{transactionHash}/transfers", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + const apiRoute = `/transactions/${result}/transfers`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ to: Token.ETHER_PULL_Address })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ transactionHash: result }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ type: "fee" }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ to: Token.ETHER_ERC20_Address })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ transactionHash: result }))) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ amount: "9000000000000" }))) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ type: "transfer" }))) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ to: Wallets.mainWalletAddress })) + ) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ transactionHash: result }))) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ amount: "9000000000000" }))) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ type: "withdrawal" }))) + .expect((res) => + expect(res.body.items[3]).toStrictEqual(expect.objectContaining({ from: Token.ETHER_PULL_Address })) + ) + .expect((res) => + expect(res.body.items[3]).toStrictEqual(expect.objectContaining({ to: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body.items[3]).toStrictEqual(expect.objectContaining({ transactionHash: result }))) + .expect((res) => expect(res.body.items[3]).toStrictEqual(expect.objectContaining({ type: "refund" }))); + }); + }); + + describe("Withdrawal the custom token to the own address", () => { + //@id641 + it("Make the custom token withdrawal to the own address", async () => { + const customToken = await helper.getStringFromFile(l2Token); + result = await playbook.withdrawERC20(customToken); + await expect(result).not.toBeUndefined(); + await expect(result.includes(Logger.txHashStartsWith)).toBe(true); + }); + + //@id1462 + it("Verify the custom token withdrawal via /transactions/{transactionHash}", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + const apiRoute = `/transactions/${result}`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body.hash).toBe(result)) + .expect((res) => expect(res.body.from).toBe(Wallets.richWalletAddress)); + }); + + //@id1463 + it("Verify the custom token withdrawal via /transactions/{transactionHash}/transfers", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + const customTokenL2 = await helper.getStringFromFile(l2Token); + const customTokenL1 = await helper.getStringFromFile(l1Token); + const apiRoute = `/transactions/${result}/transfers`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ to: Token.ETHER_PULL_Address })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ transactionHash: result }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ type: "fee" }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ to: Token.ETHER_Address }))) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ transactionHash: result }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ amount: "200000000000000000" })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ type: "transfer" }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual( + expect.objectContaining({ + token: { + l2Address: customTokenL2, + l1Address: customTokenL1, + symbol: "L1", + name: "L1 ERC20 token", + decimals: 18, + }, + }) + ) + ) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ to: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ transactionHash: result }))) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ amount: "200000000000000000" })) + ) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ type: "withdrawal" }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual( + expect.objectContaining({ + token: { + l2Address: customTokenL2, + l1Address: customTokenL1, + symbol: "L1", + name: "L1 ERC20 token", + decimals: 18, + }, + }) + ) + ) + .expect((res) => + expect(res.body.items[3]).toStrictEqual(expect.objectContaining({ from: Token.ETHER_PULL_Address })) + ) + .expect((res) => + expect(res.body.items[3]).toStrictEqual(expect.objectContaining({ to: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body.items[3]).toStrictEqual(expect.objectContaining({ transactionHash: result }))) + .expect((res) => expect(res.body.items[3]).toStrictEqual(expect.objectContaining({ type: "refund" }))); + }); + }); + + describe("Withdrawal the custom token to the other address", () => { + //@id643 + it("Make the custom token withdrawal to the other address", async () => { + const customToken = await helper.getStringFromFile(l2Token); + result = await playbook.withdrawERC20toOtherAddress(customToken); + await expect(result).not.toBeUndefined(); + await expect(result.includes(Logger.txHashStartsWith)).toBe(true); + }); + + //@id1462 + it("Verify the custom token withdrawal via /transactions/{transactionHash}", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + const apiRoute = `/transactions/${result}`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body.hash).toBe(result)) + .expect((res) => expect(res.body.from).toBe(Wallets.richWalletAddress)); + }); + + //@id1463 + it("Verify the custom token withdrawal via /transactions/{transactionHash}/transfers", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + const customTokenL2 = await helper.getStringFromFile(l2Token); + const customTokenL1 = await helper.getStringFromFile(l1Token); + const apiRoute = `/transactions/${result}/transfers`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ to: Token.ETHER_PULL_Address })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ transactionHash: result }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ type: "fee" }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ to: Token.ETHER_Address }))) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ transactionHash: result }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ amount: "200000000000000000" })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ type: "transfer" }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual( + expect.objectContaining({ + token: { + l2Address: customTokenL2, + l1Address: customTokenL1, + symbol: "L1", + name: "L1 ERC20 token", + decimals: 18, + }, + }) + ) + ) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ to: Wallets.mainWalletAddress })) + ) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ transactionHash: result }))) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ amount: "200000000000000000" })) + ) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ type: "withdrawal" }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual( + expect.objectContaining({ + token: { + l2Address: customTokenL2, + l1Address: customTokenL1, + symbol: "L1", + name: "L1 ERC20 token", + decimals: 18, + }, + }) + ) + ) + .expect((res) => + expect(res.body.items[3]).toStrictEqual(expect.objectContaining({ from: Token.ETHER_PULL_Address })) + ) + .expect((res) => + expect(res.body.items[3]).toStrictEqual(expect.objectContaining({ to: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body.items[3]).toStrictEqual(expect.objectContaining({ transactionHash: result }))) + .expect((res) => expect(res.body.items[3]).toStrictEqual(expect.objectContaining({ type: "refund" }))); + }); + }); +}); diff --git a/packages/integration-tests/tests/api/transactions/multiCall.test.ts b/packages/integration-tests/tests/api/transactions/multiCall.test.ts new file mode 100644 index 0000000000..310a5fea9b --- /dev/null +++ b/packages/integration-tests/tests/api/transactions/multiCall.test.ts @@ -0,0 +1,333 @@ +import * as request from "supertest"; +import { setTimeout } from "timers/promises"; + +import { environment, localConfig } from "../../../src/config"; +import { Buffer, Logger, Token, TransactionsType, Wallets } from "../../../src/entities"; +import { Helper } from "../../../src/helper"; +import { Playbook } from "../../../src/playbook/playbook"; + +describe("Multicall transactions", () => { + jest.setTimeout(localConfig.extendedTimeout); + const playbook = new Playbook(); + const helper = new Helper(); + const bufferRoute = "src/playbook/"; + let txHash: string; + let txMulticall: string; + let contract: string; + + //@id689 + it("Deploy the Multicall contracts", async () => { + const contract: string[] = await playbook.deployMultiCallContracts(); + expect(contract[0]).toContain(Logger.txHashStartsWith); + expect(contract[1]).toContain(Logger.txHashStartsWith); + expect(contract[2]).toContain(Logger.txHashStartsWith); + }); + + //@id1464 + it("Verify the deployed Root contract via /address/{address}", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + contract = await helper.getStringFromFile(bufferRoute + Buffer.addressMultiCallRoot); + txHash = await helper.getStringFromFile(bufferRoute + Buffer.txMultiCallRoot); + + const apiRoute = `/address/${contract}`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ type: "contract" }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ address: contract }))) + .expect((res) => + expect(res.body).toStrictEqual(expect.objectContaining({ creatorAddress: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ creatorTxHash: txHash }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ balances: {} }))); + }); + + //@id1465 + it("Verify the deployed Middle contract via /address/{address}", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + contract = await helper.getStringFromFile(bufferRoute + Buffer.addressMultiCallMiddle); + txHash = await helper.getStringFromFile(bufferRoute + Buffer.txMultiCallMiddle); + + const apiRoute = `/address/${contract}`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ type: "contract" }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ address: contract }))) + .expect((res) => + expect(res.body).toStrictEqual(expect.objectContaining({ creatorAddress: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ creatorTxHash: txHash }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ balances: {} }))); + }); + + //@id1466 + it("Verify the deployed Caller contract via /address/{address}", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + contract = await helper.getStringFromFile(bufferRoute + Buffer.addressMultiCallCaller); + txHash = await helper.getStringFromFile(bufferRoute + Buffer.txMultiCallCaller); + + const apiRoute = `/address/${contract}`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ type: "contract" }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ address: contract }))) + .expect((res) => + expect(res.body).toStrictEqual(expect.objectContaining({ creatorAddress: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ creatorTxHash: txHash }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ balances: {} }))); + }); + + //@id690:I --> @id1467 + it("Use the multicall contracts", async () => { + txMulticall = await playbook.useMultiCallContracts(); + expect(txMulticall).toContain(Logger.txHashStartsWith); + }); + + describe("Verify the multicall transactions via /transactions/${txHash}", () => { + //@id1464:I --> @id1468 + it("Verify transaction for the Root contract via /transactions/${txHash}", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + + txHash = await helper.getStringFromFile(bufferRoute + Buffer.txMultiCallRoot); + const apiRoute = `/transactions/${txHash}`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ hash: txHash }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ value: "0" }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ isL1Originated: false }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ transactionIndex: 0 }))); + }); + + //@id1465:I --> @id1469 + it("Verify transaction for the Middle contract via /transactions/${txHash}", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + + txHash = await helper.getStringFromFile(bufferRoute + Buffer.txMultiCallMiddle); + const apiRoute = `/transactions/${txHash}`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ hash: txHash }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ value: "0" }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ isL1Originated: false }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ transactionIndex: 0 }))); + }); + + //@id1466:I --> @id1470 + it("Verify transaction for the Caller contract via /transactions/${txHash}", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + + txHash = await helper.getStringFromFile(bufferRoute + Buffer.txMultiCallCaller); + const apiRoute = `/transactions/${txHash}`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ hash: txHash }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ value: "0" }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ isL1Originated: false }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ transactionIndex: 0 }))); + }); + + //@id1471 + it("Verify transaction for the use multicall contract via /transactions/${txHash}", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + + txHash = await helper.getStringFromFile(bufferRoute + Buffer.txUseMultiCallContracts); + const apiRoute = `/transactions/${txHash}`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ hash: txHash }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ value: "0" }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ isL1Originated: false }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ transactionIndex: 0 }))); + }); + }); + + describe("Verify the multicall transactions via /transactions/${txHash}/transfers", () => { + //@id1472 + it("Verify transaction for the Root contract via /transactions/${txHash}/transfers", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + + txHash = await helper.getStringFromFile(bufferRoute + Buffer.txMultiCallRoot); + const apiRoute = `/transactions/${txHash}/transfers?page=1&limit=10`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ to: Token.ETHER_PULL_Address })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ tokenAddress: Token.ETHER_ERC20_Address })) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ type: TransactionsType.fee })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ token: null }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ from: Token.ETHER_PULL_Address })) + ) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ to: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ tokenAddress: Token.ETHER_ERC20_Address })) + ) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ type: TransactionsType.refund })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ token: null }))); + }); + + //@id1473 + it("Verify transaction for the Middle contract via /transactions/${txHash}/transfers", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + + txHash = await helper.getStringFromFile(bufferRoute + Buffer.txMultiCallMiddle); + const apiRoute = `/transactions/${txHash}/transfers?page=1&limit=10`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ to: Token.ETHER_PULL_Address })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ tokenAddress: Token.ETHER_ERC20_Address })) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ type: TransactionsType.fee })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ token: null }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ from: Token.ETHER_PULL_Address })) + ) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ to: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ tokenAddress: Token.ETHER_ERC20_Address })) + ) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ type: TransactionsType.refund })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ token: null }))); + }); + + //@id1474 + it("Verify transaction for the Caller contract via /transactions/${txHash}/transfers", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + + txHash = await helper.getStringFromFile(bufferRoute + Buffer.txMultiCallCaller); + const apiRoute = `/transactions/${txHash}/transfers?page=1&limit=10`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ to: Token.ETHER_PULL_Address })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ tokenAddress: Token.ETHER_ERC20_Address })) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ type: TransactionsType.fee })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ token: null }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ from: Token.ETHER_PULL_Address })) + ) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ to: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ tokenAddress: Token.ETHER_ERC20_Address })) + ) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ type: TransactionsType.refund })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ token: null }))); + }); + + //@id1475 + it("Verify transaction for the use multicall contract via /transactions/${txHash}/transfers", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + + txHash = await helper.getStringFromFile(bufferRoute + Buffer.txUseMultiCallContracts); + + const apiRoute = `/transactions/${txHash}/transfers?page=1&limit=10`; + await setTimeout(localConfig.standardPause); //works unstable without timeout + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ to: Token.ETHER_PULL_Address })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ tokenAddress: Token.ETHER_ERC20_Address })) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ type: TransactionsType.fee })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ token: null }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ from: Token.ETHER_PULL_Address })) + ) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ to: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ tokenAddress: Token.ETHER_ERC20_Address })) + ) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ type: TransactionsType.refund })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ token: null }))); + }); + }); +}); diff --git a/packages/integration-tests/tests/api/transactions/multiTransfer.test.ts b/packages/integration-tests/tests/api/transactions/multiTransfer.test.ts new file mode 100644 index 0000000000..7bdde1c14f --- /dev/null +++ b/packages/integration-tests/tests/api/transactions/multiTransfer.test.ts @@ -0,0 +1,306 @@ +import * as request from "supertest"; +import { setTimeout } from "timers/promises"; + +import { environment, localConfig } from "../../../src/config"; +import { Buffer, Logger, Token, TransactionsType, Wallets } from "../../../src/entities"; +import { Helper } from "../../../src/helper"; +import { Playbook } from "../../../src/playbook/playbook"; + +describe("Mulitransfer ETH", () => { + jest.setTimeout(localConfig.extendedTimeout); + const playbook = new Playbook(); + const helper = new Helper(); + const bufferRoute = "src/playbook/"; + let txHash: string; + let txMultiTransfer: string[]; + let token: string; + let contract: string; + + beforeEach(async () => { + contract = await helper.getStringFromFile(bufferRoute + Buffer.addressMultiTransferETH); + }); + + //@id690 + it("Deploy the multitransfer ETH contract to the L2", async () => { + contract = await playbook.deployMultiTransferETH(); + expect(contract).toContain(Logger.txHashStartsWith); + }); + + //@id1476 + it("Verify the deployed multitransfer contract via /address/{address}", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + + const apiRoute = `/address/${contract}`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ address: contract }))) + .expect((res) => + expect(res.body).toStrictEqual(expect.objectContaining({ creatorAddress: Wallets.richWalletAddress })) + ); + }); + + //@id690 --> //@id1477 + it("Call the multitransfer contract to the L2", async () => { + txMultiTransfer = await playbook.useMultiTransferETH(); + expect(txMultiTransfer[0]).toContain(Logger.txHashStartsWith); + expect(txMultiTransfer[1]).toContain(Logger.txHashStartsWith); + expect(txMultiTransfer[2]).toContain(Logger.txHashStartsWith); + }); + + describe("Verify the multitransfer transactions via /transactions/${txHash}", () => { + //@id1478 + it("Verify transaction for the ETH via /transactions/${txHash}", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + + txHash = await helper.getStringFromFile(bufferRoute + Buffer.txMultiTransferETH); + const apiRoute = `/transactions/${txHash}`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ hash: txHash }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ to: contract }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ isL1Originated: false }))); + }); + + //@id1479 + it("Verify transaction for the Custom Token I via /transactions/${txHash}", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + + txHash = await helper.getStringFromFile(bufferRoute + Buffer.txMultiTransferCustomTokenI); + contract = await helper.getStringFromFile(bufferRoute + Buffer.L2); + const apiRoute = `/transactions/${txHash}`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ hash: txHash }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ to: contract }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ isL1Originated: false }))); + }); + + //@id1480 + it("Verify transaction for the Custom Token II via /transactions/${txHash}", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + + txHash = await helper.getStringFromFile(bufferRoute + Buffer.txMultiTransferCustomTokenII); + contract = await helper.getStringFromFile(bufferRoute + Buffer.L2deposited); + const apiRoute = `/transactions/${txHash}`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ hash: txHash }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ to: contract }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ isL1Originated: false }))); + }); + }); + + describe("Verify the multitransfer transactions via /transactions/${txHash}/transfer", () => { + beforeAll(async () => { + token = await helper.getStringFromFile(bufferRoute + Buffer.L2); + }); + + //@id1481 + it("Verify transaction for the ETH via /transactions/${txHash}/transfers", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + + txHash = await helper.getStringFromFile(bufferRoute + Buffer.txMultiTransferETH); + const apiRoute = `/transactions/${txHash}/transfers?page=1&limit=10`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ to: Token.ETHER_PULL_Address })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ tokenAddress: Token.ETHER_ERC20_Address })) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ type: TransactionsType.fee })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ token: null }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ to: contract }))) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ tokenAddress: Token.ETHER_ERC20_Address })) + ) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ type: TransactionsType.transfer })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ token: null }))) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ from: Token.ETHER_PULL_Address })) + ) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ to: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ tokenAddress: Token.ETHER_ERC20_Address })) + ) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ type: TransactionsType.refund })) + ) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ token: null }))); + }); + + //@id1482 + it("Verify transaction for the Custom tokenI via /transactions/${txHash}/transfers", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + contract = await helper.getStringFromFile(bufferRoute + Buffer.addressMultiTransferETH); + txHash = await helper.getStringFromFile(bufferRoute + Buffer.txMultiTransferCustomTokenI); + const apiRoute = `/transactions/${txHash}/transfers?page=1&limit=10`; + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ to: Token.ETHER_PULL_Address })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ tokenAddress: Token.ETHER_ERC20_Address })) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ type: TransactionsType.fee })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ to: contract }))) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ tokenAddress: token }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ type: TransactionsType.transfer })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual( + expect.objectContaining({ + token: { + l2Address: token, + l1Address: null, + symbol: "L2", + name: "L2 ERC20 token", + decimals: 18, + }, + }) + ) + ) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ from: Token.ETHER_PULL_Address })) + ) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ to: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ tokenAddress: Token.ETHER_ERC20_Address })) + ) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ type: TransactionsType.refund })) + ) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ token: null }))); + }); + + //@id1483 + it("Verify transaction for the Custom tokenII via /transactions/${txHash}/transfers", async () => { + await setTimeout(localConfig.standardPause); //works unstable without timeout + + const tokenL1 = await helper.getStringFromFile(bufferRoute + Buffer.L1); + token = await helper.getStringFromFile(bufferRoute + Buffer.L2deposited); + txHash = await helper.getStringFromFile(bufferRoute + Buffer.txMultiTransferCustomTokenII); + const apiRoute = `/transactions/${txHash}/transfers?page=1&limit=10`; + + return ( + request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ to: Token.ETHER_PULL_Address })) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ transactionHash: txHash })) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual( + expect.objectContaining({ tokenAddress: Token.ETHER_ERC20_Address }) + ) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ type: TransactionsType.fee })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ to: contract }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ transactionHash: txHash })) + ) + // .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ tokenAddress: Token.ETHER_ERC20_Address }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ type: TransactionsType.transfer })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual( + expect.objectContaining({ + token: { + l2Address: token, + l1Address: tokenL1, + symbol: "L1", + name: "L1 ERC20 token", + decimals: 18, + }, + }) + ) + ) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ from: Token.ETHER_PULL_Address })) + ) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ to: Wallets.richWalletAddress })) + ) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ transactionHash: txHash })) + ) + .expect((res) => + expect(res.body.items[2]).toStrictEqual( + expect.objectContaining({ tokenAddress: Token.ETHER_ERC20_Address }) + ) + ) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ type: TransactionsType.refund })) + ) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ token: null }))) + ); + }); + }); +}); diff --git a/packages/integration-tests/tests/api/transactions/transaction.test.ts b/packages/integration-tests/tests/api/transactions/transaction.test.ts new file mode 100644 index 0000000000..c8431a49b7 --- /dev/null +++ b/packages/integration-tests/tests/api/transactions/transaction.test.ts @@ -0,0 +1,422 @@ +import * as request from "supertest"; +import { setTimeout } from "timers/promises"; + +import { environment, localConfig } from "../../../src/config"; +import { Buffer, Logger, Token, TransactionsStatus, TransactionsType, Wallets } from "../../../src/entities"; +import { Helper } from "../../../src/helper"; +import { Playbook } from "../../../src/playbook/playbook"; + +describe("Transactions", () => { + jest.setTimeout(localConfig.standardTimeout); + const playbook = new Playbook(); + const helper = new Helper(); + const bufferRoute = "src/playbook/"; + let txHash: string; + let token: string; + let contract: string; + let emptyWallet: string; + + describe("Paymaster", () => { + jest.setTimeout(localConfig.extendedTimeout); + + beforeEach(async () => { + token = await helper.getStringFromFile(bufferRoute + Buffer.customToken); + txHash = await helper.getStringFromFile(bufferRoute + Buffer.paymasterTx); + emptyWallet = await helper.getStringFromFile(bufferRoute + Buffer.emptyWalletAddress); + }); + + //@id1450 + it("Deploy contract via Paymaster", async () => { + const result = await playbook.deployViaPaymaster(); + expect(result[0]).toContain(Logger.txHashStartsWith); + }); + + //@id644 + it("Transaction via Paymaster usage", async () => { + const result = await playbook.usePaymaster(); + expect(result).toContain(Logger.txHashStartsWith); + }); + + //@id1451 + it("Verify the custom token includes paymaster transaction", async () => { + const paymaster = await helper.getStringFromFile(bufferRoute + Buffer.paymaster); + const apiRoute = `/tokens/${token}/transfers?page=1&limit=10`; + + await setTimeout(localConfig.standardPause); //works unstable without timeout + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ from: emptyWallet }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ to: paymaster }))) + .expect((res) => expect(res.body.items[0].token).toStrictEqual(expect.objectContaining({ l2Address: token }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ type: TransactionsType.transfer })) + ); + }); + + //@id1452 + it("Verify transaction through Paymaster", async () => { + const apiRoute = `/transactions/${txHash}/transfers?page=1&limit=10`; + const paymasterAddress = await helper.getStringFromFile(bufferRoute + Buffer.paymaster); + + await setTimeout(localConfig.standardPause); //works unstable without timeout + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ from: emptyWallet }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ to: paymasterAddress }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ tokenAddress: token }))) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ type: TransactionsType.transfer })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => + expect(res.body.items[0]).toStrictEqual( + expect.objectContaining({ + token: { + l2Address: token, + l1Address: null, + symbol: "MyToken", + name: "MyToken", + decimals: 18, + }, + }) + ) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ from: paymasterAddress }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ to: Token.ETHER_PULL_Address })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ tokenAddress: Token.ETHER_ERC20_Address })) + ) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ type: TransactionsType.fee })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ token: null }))) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ from: Token.ETHER_PULL_Address })) + ) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ to: paymasterAddress }))) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ tokenAddress: Token.ETHER_ERC20_Address })) + ) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ type: TransactionsType.refund })) + ) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ token: null }))); + }); + }); + + describe("Transaction with failed state", () => { + beforeAll(async () => { + const bufferFile = bufferRoute + Buffer.L2; + token = await helper.getStringFromFile(bufferFile); + txHash = await playbook.transferFailedState(token); + return [txHash, token]; + }); + + //@id645 + it("Verify the transactions with failed state", async () => { + const apiRoute = `/transactions/${txHash}?page=1&limit=10`; + + await setTimeout(localConfig.standardPause); //works unstable without timeout + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body.from).toStrictEqual(Wallets.richWalletAddress)) + .expect((res) => expect(res.body.to).toStrictEqual(token)) + .expect((res) => expect(res.body.hash).toStrictEqual(txHash)) + .expect((res) => expect(res.body.status).toStrictEqual(TransactionsStatus.failed)); + }); + }); + + describe("Greeter", () => { + jest.setTimeout(localConfig.extendedTimeout); + + beforeEach(async () => { + contract = await helper.getStringFromFile(bufferRoute + Buffer.greeterL2); + txHash = await helper.getStringFromFile(bufferRoute + Buffer.executeGreeterTx); + }); + + //@id597 + it("Deploy the Greeter contract to the L2", async () => { + contract = await playbook.deployGreeterToL2(); + expect(contract).toContain(Logger.txHashStartsWith); + }); + + //@id1449 + it("Verify the deployed Greeter contract via /address/{address}", async () => { + const apiRoute = `/address/${contract}`; + + await setTimeout(localConfig.standardPause); //works unstable without timeout + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ address: contract }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ balances: {} }))); + }); + + //@id604 + it("Use the Greeter contract - execute SetGreeting", async () => { + const executedContract = await playbook.useGreeter(); + expect(executedContract).toContain(Logger.txHashStartsWith); + }); + + //@id1454 + it("Verify the transaction after SetGreeting execution via transactions/{transactionHash}", async () => { + const apiRoute = `/transactions/${txHash}?page=1&limit=10`; + + await setTimeout(localConfig.standardPause); //works unstable without timeout + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ hash: txHash }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ to: contract }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ value: "0" }))) + .expect((res) => expect(res.body).toStrictEqual(expect.objectContaining({ isL1Originated: false }))); + }); + + //@id1455 + it("Verify the transaction after SetGreeting execution via transactions/{transactionHash}/transfers", async () => { + const apiRoute = `/transactions/${txHash}/transfers?page=1&limit=10`; + await setTimeout(localConfig.standardPause); //works unstable without timeout + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ to: Token.ETHER_PULL_Address })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ tokenAddress: Token.ETHER_ERC20_Address })) + ) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ type: TransactionsType.fee })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ token: null }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ from: Token.ETHER_PULL_Address })) + ) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ to: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ tokenAddress: Token.ETHER_ERC20_Address })) + ) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ type: TransactionsType.refund })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ token: null }))); + }); + }); + + describe("Transactions for the /address/{address} endpoints", () => { + jest.setTimeout(localConfig.extendedTimeout); + + //@id1510 + it("Verify the transaction via /address/{address}/logs", async () => { + contract = await helper.getStringFromFile(bufferRoute + Buffer.greeterL2); + txHash = await helper.getStringFromFile(bufferRoute + Buffer.executeGreeterTx); + + const apiRoute = `/address/${contract}/logs`; + const decapitalizedAddress = apiRoute.slice(1).toLowerCase(); + + await setTimeout(localConfig.standardPause); //works unstable without timeout + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ address: contract }))) + .expect((res) => expect(Array.isArray(res.body.items[0].topics)).toStrictEqual(true)) + .expect((res) => expect(typeof res.body.items[0].data).toStrictEqual("string")) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => expect(typeof res.body.items[0].transactionIndex).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.items[0].logIndex).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.items[0].timestamp).toStrictEqual("string")) + .expect((res) => expect(res.body.meta).toStrictEqual(expect.objectContaining({ totalItems: 1 }))) + .expect((res) => expect(res.body.meta).toStrictEqual(expect.objectContaining({ itemCount: 1 }))) + .expect((res) => expect(res.body.meta).toStrictEqual(expect.objectContaining({ itemsPerPage: 10 }))) + .expect((res) => expect(res.body.meta).toStrictEqual(expect.objectContaining({ totalPages: 1 }))) + .expect((res) => expect(res.body.meta).toStrictEqual(expect.objectContaining({ currentPage: 1 }))) + .expect((res) => + expect(res.body.links).toStrictEqual(expect.objectContaining({ first: `${decapitalizedAddress}?limit=10` })) + ) + .expect((res) => expect(res.body.links).toStrictEqual(expect.objectContaining({ previous: "" }))) + .expect((res) => expect(res.body.links).toStrictEqual(expect.objectContaining({ next: "" }))) + .expect((res) => + expect(res.body.links).toStrictEqual( + expect.objectContaining({ last: `${decapitalizedAddress}?page=1&limit=10` }) + ) + ); + }); + + //@id1509 + it("Verify the transaction via /address/{address}/transfers", async () => { + contract = await helper.getStringFromFile(bufferRoute + Buffer.paymaster); + emptyWallet = await helper.getStringFromFile(bufferRoute + Buffer.emptyWalletAddress); + txHash = await helper.getStringFromFile(bufferRoute + Buffer.paymasterTx); + + const customTokenAddress = await helper.getStringFromFile(bufferRoute + Buffer.customToken); + const apiRoute = `/address/${contract}/transfers`; + const decapitalizedAddress = apiRoute.slice(1).toLowerCase(); + + await setTimeout(localConfig.standardPause); //works unstable without timeout + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ from: emptyWallet }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ to: contract }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => expect(typeof res.body.items[0].timestamp).toStrictEqual("string")) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ amount: "1" }))) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ tokenAddress: customTokenAddress })) + ) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ type: "transfer" }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => + expect(res.body.items[0].token).toStrictEqual(expect.objectContaining({ l2Address: customTokenAddress })) + ) + .expect((res) => expect(res.body.items[0].token).toStrictEqual(expect.objectContaining({ l1Address: null }))) + .expect((res) => expect(res.body.items[0].token).toStrictEqual(expect.objectContaining({ symbol: "MyToken" }))) + .expect((res) => expect(res.body.items[0].token).toStrictEqual(expect.objectContaining({ name: "MyToken" }))) + .expect((res) => expect(res.body.items[0].token).toStrictEqual(expect.objectContaining({ decimals: 18 }))) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ from: Wallets.richWalletAddress })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ to: contract }))) + .expect((res) => expect(typeof res.body.items[1].timestamp).toStrictEqual("string")) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ amount: "30000000000000000" })) + ) + .expect((res) => + expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ tokenAddress: Token.ETHER_ERC20_Address })) + ) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ type: "transfer" }))) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ fields: null }))) + .expect((res) => expect(res.body.meta).toStrictEqual(expect.objectContaining({ totalItems: 2 }))) + .expect((res) => expect(res.body.meta).toStrictEqual(expect.objectContaining({ itemCount: 2 }))) + .expect((res) => expect(res.body.meta).toStrictEqual(expect.objectContaining({ itemsPerPage: 10 }))) + .expect((res) => expect(res.body.meta).toStrictEqual(expect.objectContaining({ totalPages: 1 }))) + .expect((res) => expect(res.body.meta).toStrictEqual(expect.objectContaining({ currentPage: 1 }))) + .expect((res) => + expect(res.body.links).toStrictEqual(expect.objectContaining({ first: `${decapitalizedAddress}?limit=10` })) + ) + .expect((res) => expect(res.body.links).toStrictEqual(expect.objectContaining({ previous: "" }))) + .expect((res) => expect(res.body.links).toStrictEqual(expect.objectContaining({ next: "" }))) + .expect((res) => + expect(res.body.links).toStrictEqual( + expect.objectContaining({ last: `${decapitalizedAddress}?page=1&limit=10` }) + ) + ); + }); + }); + describe("Transactions for the /transactions endpoint", () => { + jest.setTimeout(localConfig.extendedTimeout); + + //@id1506 + it("Verify the transaction via /transactions", async () => { + contract = await helper.getStringFromFile(bufferRoute + Buffer.greeterL2); + txHash = await helper.getStringFromFile(bufferRoute + Buffer.executeGreeterTx); + + const apiRoute = `/transactions`; + + await setTimeout(localConfig.standardPause); //works unstable without timeout + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => expect(Array.isArray(res.body.items)).toStrictEqual(true)) + .expect((res) => expect(res.body.items.length).toBe(10)) + .expect((res) => expect(typeof res.body.meta.totalItems).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.meta.itemCount).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.meta.itemsPerPage).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.meta.totalPages).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.meta.currentPage).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.links.first).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.links.previous).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.links.next).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.links.last).toStrictEqual("string")); + }); + + //@id1507 + it("Verify the transaction via /transactions/{transactionHash}/logs", async () => { + contract = await helper.getStringFromFile(bufferRoute + Buffer.greeterL2); + txHash = await helper.getStringFromFile(bufferRoute + Buffer.executeGreeterTx); + + const apiRoute = `/transactions/${txHash}/logs`; + const decapitalizedAddress = apiRoute.slice(1).toLowerCase(); + + await setTimeout(localConfig.standardPause); //works unstable without timeout + + return request(environment.blockExplorerAPI) + .get(apiRoute) + .expect(200) + .expect((res) => + expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ address: Token.ETHER_ERC20_Address })) + ) + .expect((res) => expect(Array.isArray(res.body.items[0].topics)).toStrictEqual(true)) + .expect((res) => expect(typeof res.body.items[0].data).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.items[0].blockNumber).toStrictEqual("number")) + .expect((res) => expect(res.body.items[0]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => expect(typeof res.body.items[0].transactionIndex).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.items[0].logIndex).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.items[0].timestamp).toStrictEqual("string")) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ address: contract }))) + .expect((res) => expect(Array.isArray(res.body.items[1].topics)).toStrictEqual(true)) + .expect((res) => expect(typeof res.body.items[1].data).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.items[1].blockNumber).toStrictEqual("number")) + .expect((res) => expect(res.body.items[1]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => expect(typeof res.body.items[1].transactionIndex).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.items[1].logIndex).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.items[1].timestamp).toStrictEqual("string")) + .expect((res) => + expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ address: Token.ETHER_ERC20_Address })) + ) + .expect((res) => expect(Array.isArray(res.body.items[2].topics)).toStrictEqual(true)) + .expect((res) => expect(typeof res.body.items[2].data).toStrictEqual("string")) + .expect((res) => expect(typeof res.body.items[2].blockNumber).toStrictEqual("number")) + .expect((res) => expect(res.body.items[2]).toStrictEqual(expect.objectContaining({ transactionHash: txHash }))) + .expect((res) => expect(typeof res.body.items[2].transactionIndex).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.items[2].logIndex).toStrictEqual("number")) + .expect((res) => expect(typeof res.body.items[2].timestamp).toStrictEqual("string")) + .expect((res) => expect(res.body.meta).toStrictEqual(expect.objectContaining({ totalItems: 3 }))) + .expect((res) => expect(res.body.meta).toStrictEqual(expect.objectContaining({ itemCount: 3 }))) + .expect((res) => expect(res.body.meta).toStrictEqual(expect.objectContaining({ itemsPerPage: 10 }))) + .expect((res) => expect(res.body.meta).toStrictEqual(expect.objectContaining({ totalPages: 1 }))) + .expect((res) => expect(res.body.meta).toStrictEqual(expect.objectContaining({ currentPage: 1 }))) + .expect((res) => + expect(res.body.links).toStrictEqual(expect.objectContaining({ first: `${decapitalizedAddress}?limit=10` })) + ) + .expect((res) => expect(res.body.links).toStrictEqual(expect.objectContaining({ previous: "" }))) + .expect((res) => expect(res.body.links).toStrictEqual(expect.objectContaining({ next: "" }))) + .expect((res) => + expect(res.body.links).toStrictEqual( + expect.objectContaining({ last: `${decapitalizedAddress}?page=1&limit=10` }) + ) + ); + }); + }); +}); diff --git a/packages/integration-tests/tests/ui/config.ts b/packages/integration-tests/tests/ui/config.ts new file mode 100644 index 0000000000..c07ccb220b --- /dev/null +++ b/packages/integration-tests/tests/ui/config.ts @@ -0,0 +1,8 @@ +export const config = { + mainWindowSize: { width: 1920, height: 1080 }, + headless: true, + slowMo: 10, + defaultTimeout: { timeout: 5000 }, + increasedTimeout: { timeout: 17000 }, + extraTimeout: { timeout: 60000 }, +}; diff --git a/packages/integration-tests/tests/ui/multiCall.spec.ts b/packages/integration-tests/tests/ui/multiCall.spec.ts new file mode 100644 index 0000000000..38e723834d --- /dev/null +++ b/packages/integration-tests/tests/ui/multiCall.spec.ts @@ -0,0 +1,63 @@ +import { expect, test } from "@playwright/test"; + +import { config } from "./config"; +import { BlockExplorer, Buffer } from "../../src/entities"; +import { Helper } from "../../src/helper"; + +import type { Locator } from "@playwright/test"; + +const bufferRoute = "src/playbook/"; +const helper = new Helper(); +let url: string; +let bufferFile; +let contract: string; +let element: Locator; +let selector: string; + +//@id1684 +test("Check Multicall - Caller contract address", async ({ page }) => { + bufferFile = bufferRoute + Buffer.addressMultiCallCaller; + contract = await helper.getStringFromFile(bufferFile); + url = BlockExplorer.baseUrl + BlockExplorer.localNetwork; + const targetUrl = BlockExplorer.baseUrl + `/address/${contract}`; + + await page.goto(url); + await page.goto(targetUrl); + + selector = `text=${contract}`; + element = await page.locator(selector).first(); + + await expect(element).toBeVisible(config.extraTimeout); +}); + +//@id1690 +test("Check Multicall - Middle contract address", async ({ page }) => { + bufferFile = bufferRoute + Buffer.addressMultiCallMiddle; + contract = await helper.getStringFromFile(bufferFile); + url = BlockExplorer.baseUrl + BlockExplorer.localNetwork; + const targetUrl = BlockExplorer.baseUrl + `/address/${contract}`; + + await page.goto(url); + await page.goto(targetUrl); + + selector = `text=${contract}`; + element = await page.locator(selector).first(); + + await expect(element).toBeVisible(); +}); + +//@id1691 +test("Check Multicall - Root contract address", async ({ page }) => { + bufferFile = bufferRoute + Buffer.addressMultiCallRoot; + contract = await helper.getStringFromFile(bufferFile); + url = BlockExplorer.baseUrl + BlockExplorer.localNetwork; + const targetUrl = BlockExplorer.baseUrl + `/address/${contract}`; + + await page.goto(url); + await page.goto(targetUrl); + + selector = `text=${contract}`; + element = await page.locator(selector).first(); + + await expect(element).toBeVisible(); +}); diff --git a/packages/integration-tests/tests/ui/nft.spec.ts b/packages/integration-tests/tests/ui/nft.spec.ts new file mode 100644 index 0000000000..2e301ed232 --- /dev/null +++ b/packages/integration-tests/tests/ui/nft.spec.ts @@ -0,0 +1,46 @@ +import { expect, test } from "@playwright/test"; + +import { config } from "./config"; +import { BlockExplorer, Buffer } from "../../src/entities"; +import { Helper } from "../../src/helper"; + +import type { Locator } from "@playwright/test"; + +const bufferRoute = "src/playbook/"; +const helper = new Helper(); +let url: string; +let bufferFile; +let contract: string; +let element: Locator; + +//@id1658 +test("Check the L2 NFT contract address", async ({ page }) => { + bufferFile = bufferRoute + Buffer.NFTtoL2; + contract = await helper.getStringFromFile(bufferFile); + url = BlockExplorer.baseUrl + BlockExplorer.localNetwork; + const targetUrl = BlockExplorer.baseUrl + `/address/${contract}`; + + await page.goto(url); + await page.goto(targetUrl); + + element = await page.locator(`text=${contract}`).first(); + + await expect(element).toBeVisible(config.extraTimeout); +}); + +//@id1657 +test("Check the L1 NFT contract address", async ({ page }) => { + bufferFile = bufferRoute + Buffer.NFTtoL1; + contract = await helper.getStringFromFile(bufferFile); + url = BlockExplorer.baseUrl + BlockExplorer.localNetwork; + const targetUrl = BlockExplorer.baseUrl + `/address/${contract}`; + + await page.goto(url); + await page.goto(targetUrl); + + element = await page.locator(`text=${contract}`).first(); + const noTransactionNotification = await page.locator(`text=This account doesn’t have any transactions`).first(); + + await expect(element).toBeVisible(config.extraTimeout); + await expect(noTransactionNotification).toBeVisible(config.extraTimeout); +}); diff --git a/packages/integration-tests/tsconfig.json b/packages/integration-tests/tsconfig.json new file mode 100644 index 0000000000..12cebf4b35 --- /dev/null +++ b/packages/integration-tests/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "module": "commonjs", + "declaration": true, + "removeComments": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "allowSyntheticDefaultImports": true, + "target": "es2017", + "sourceMap": true, + "outDir": "./dist", + "baseUrl": "./", + "incremental": true, + "skipLibCheck": true, + "strictNullChecks": false, + "noImplicitAny": false, + "strictBindCallApply": false, + "forceConsistentCasingInFileNames": false, + "noFallthroughCasesInSwitch": false + } +} \ No newline at end of file