diff --git a/core/lib/basic_types/src/protocol_version.rs b/core/lib/basic_types/src/protocol_version.rs index be1759d4f389..ad4f74418da1 100644 --- a/core/lib/basic_types/src/protocol_version.rs +++ b/core/lib/basic_types/src/protocol_version.rs @@ -176,7 +176,7 @@ impl ProtocolVersionId { } pub fn is_pre_medium_interop(&self) -> bool { - self < &Self::Version30 + self < &Self::Version31 } pub fn is_1_4_0(&self) -> bool { diff --git a/core/lib/multivm/src/pubdata_builders/tests.rs b/core/lib/multivm/src/pubdata_builders/tests.rs index 86a141af3140..01ca419adbe6 100644 --- a/core/lib/multivm/src/pubdata_builders/tests.rs +++ b/core/lib/multivm/src/pubdata_builders/tests.rs @@ -103,7 +103,7 @@ fn test_full_pubdata_building() { )); let actual = - full_pubdata_builder.settlement_layer_pubdata(&input, ProtocolVersionId::Version30); + full_pubdata_builder.settlement_layer_pubdata(&input, ProtocolVersionId::Version31); let expected = "00000001000000000000000000000000000000000000000000008001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000100000004deadbeef0000000100000060bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb0100002a040001000000000000000000000000000000000000000000000000000000000000007e090e0000000c0901"; assert_eq!( &hex::encode(actual), @@ -141,7 +141,7 @@ fn test_hashed_pubdata_building() { L2DACommitmentScheme::BlobsAndPubdataKeccak256, )); let actual = - hashed_pubdata_builder.settlement_layer_pubdata(&input, ProtocolVersionId::Version30); + hashed_pubdata_builder.settlement_layer_pubdata(&input, ProtocolVersionId::Version31); let expected = "fa96e2436e6fb4d668f5a06681a7c53fcb199b2747ee624ee52a13e85aac5f1e"; assert_eq!( &hex::encode(actual), diff --git a/core/tests/highlevel-test-tools/src/index.ts b/core/tests/highlevel-test-tools/src/index.ts index 3f9ed5d36956..6af25ea6a9b6 100644 --- a/core/tests/highlevel-test-tools/src/index.ts +++ b/core/tests/highlevel-test-tools/src/index.ts @@ -11,7 +11,8 @@ export { genesisRecoveryTest, snapshotsRecoveryTest, gatewayMigrationToGatewayTest, - gatewayMigrationFromGatewayTest + gatewayMigrationFromGatewayTest, + tokenBalanceMigrationTest } from './run-integration-tests'; export { generateLoad } from './generate-load'; export { getRpcUrl, queryJsonRpc, getL1BatchNumber, getL1BatchDetails } from './rpc-utils'; diff --git a/core/tests/highlevel-test-tools/src/run-integration-tests.ts b/core/tests/highlevel-test-tools/src/run-integration-tests.ts index 193ab6f20f75..90610baf39ab 100644 --- a/core/tests/highlevel-test-tools/src/run-integration-tests.ts +++ b/core/tests/highlevel-test-tools/src/run-integration-tests.ts @@ -137,3 +137,8 @@ export async function gatewayMigrationFromGatewayTest(chainName: string): Promis await initTestWallet(chainName); await runTest('gateway-migration', chainName, undefined, ['--from-gateway']); } + +export async function tokenBalanceMigrationTest(chainName: string): Promise { + await initTestWallet(chainName); + await runTest('token-balance-migration', chainName, undefined); +} diff --git a/core/tests/highlevel-test-tools/src/start-external-node.ts b/core/tests/highlevel-test-tools/src/start-external-node.ts index 66c9e993513c..7ba655d9b27d 100644 --- a/core/tests/highlevel-test-tools/src/start-external-node.ts +++ b/core/tests/highlevel-test-tools/src/start-external-node.ts @@ -28,7 +28,7 @@ export class TestExternalNode { markAsExpectingErrorCode(errorCode: number): void { this.expectedErrorCode = errorCode; console.log(`📝 Marked external node ${this.chainName} as expecting error code: ${errorCode}`); - removeErrorListeners(this.process); + removeErrorListeners(this.process!); if (!this.process) { throw new Error('External node process is not available!'); } diff --git a/core/tests/highlevel-test-tools/tests/token-balance-migration.test.ts b/core/tests/highlevel-test-tools/tests/token-balance-migration.test.ts new file mode 100644 index 000000000000..afbee47497a3 --- /dev/null +++ b/core/tests/highlevel-test-tools/tests/token-balance-migration.test.ts @@ -0,0 +1,23 @@ +import { describe, it } from 'vitest'; +import { createChainAndStartServer, TESTED_CHAIN_TYPE, tokenBalanceMigrationTest } from '../src'; + +const useGatewayChain = process.env.USE_GATEWAY_CHAIN; +const shouldSkip = useGatewayChain !== 'WITH_GATEWAY'; + +if (shouldSkip) { + console.log( + `⏭️ Skipping asset migration test for ${TESTED_CHAIN_TYPE} chain (USE_GATEWAY_CHAIN=${useGatewayChain})` + ); +} + +(shouldSkip ? describe.skip : describe)('Asset Migration Test', () => { + it(`for ${TESTED_CHAIN_TYPE} chain`, async () => { + const testChain = await createChainAndStartServer(TESTED_CHAIN_TYPE, 'Asset Migration Test'); + + await testChain.generateRealisticLoad(); + + await testChain.waitForAllBatchesToBeExecuted(); + + await tokenBalanceMigrationTest(testChain.chainName); + }); +}); diff --git a/core/tests/token-balance-migration-test/package.json b/core/tests/token-balance-migration-test/package.json new file mode 100644 index 000000000000..c23bde40218b --- /dev/null +++ b/core/tests/token-balance-migration-test/package.json @@ -0,0 +1,37 @@ +{ + "name": "asset-tracker-chain-migration-test", + "version": "1.0.0", + "license": "MIT", + "mocha": { + "timeout": 240000, + "exit": true, + "color": false, + "slow": 0, + "require": [ + "ts-node/register", + "mocha-steps" + ] + }, + "scripts": { + "migration-test": "mocha tests/migration.test.ts" + }, + "devDependencies": { + "@types/chai": "^4.2.21", + "@types/mocha": "^8.2.3", + "@types/mocha-steps": "^1.3.0", + "@types/node": "^18.19.15", + "@types/node-fetch": "^2.5.7", + "chai": "^4.3.4", + "chai-as-promised": "^7.1.1", + "ethers": "^6.13.5", + "mocha": "^9.0.2", + "mocha-steps": "^1.3.0", + "node-fetch": "^2.6.1", + "ts-node": "^10.1.0", + "typescript": "^4.3.5", + "zksync-ethers": "https://github.com/zksync-sdk/zksync-ethers#di/avoid-zks-estimate-fee-build" + }, + "dependencies": { + "prettier": "^2.3.2" + } +} diff --git a/core/tests/token-balance-migration-test/tests/migration.test.ts b/core/tests/token-balance-migration-test/tests/migration.test.ts new file mode 100644 index 000000000000..8005827bac5e --- /dev/null +++ b/core/tests/token-balance-migration-test/tests/migration.test.ts @@ -0,0 +1,254 @@ +import * as utils from 'utils'; +import { DEFAULT_LARGE_AMOUNT, L1ERC20Handler, L2ERC20Handler, Tester, WithdrawalHandler } from './tester'; +import * as zksync from 'zksync-ethers'; +import * as ethers from 'ethers'; +import { expect } from 'chai'; +import fs from 'node:fs/promises'; +import { existsSync, readFileSync } from 'node:fs'; +import { BytesLike } from '@ethersproject/bytes'; +import { BigNumberish } from 'ethers'; +import { loadConfig, shouldLoadConfigFromFile } from 'utils/build/file-configs'; +import path from 'path'; +import { CONTRACT_DEPLOYER, CONTRACT_DEPLOYER_ADDRESS, hashBytecode, ZKSYNC_MAIN_ABI } from 'zksync-ethers/build/utils'; +import { utils as zksync_utils } from 'zksync-ethers'; +import { logsTestPath } from 'utils/build/logs'; +import { waitForNewL1Batch } from 'utils'; +import { getMainWalletPk } from 'highlevel-test-tools/src/wallets'; + +import { ChainHandler } from './tester'; + +async function logsPath(name: string): Promise { + return await logsTestPath(fileConfig.chain, 'logs/upgrade/', name); +} + +const L2_BRIDGEHUB_ADDRESS = '0x0000000000000000000000000000000000010002'; +const pathToHome = path.join(__dirname, '../../../..'); +const fileConfig = shouldLoadConfigFromFile(); + +// const contracts: Contracts = initContracts(pathToHome, fileConfig.loadFromFile); + +const ZK_CHAIN_INTERFACE = JSON.parse( + readFileSync(pathToHome + '/contracts/l1-contracts/out/IZKChain.sol/IZKChain.json').toString() +).abi; + +const depositAmount = ethers.parseEther('0.001'); + +interface GatewayInfo { + gatewayChainId: string; + gatewayProvider: zksync.Provider; + gatewayCTM: string; + l2ChainAdmin: string; + l2DiamondProxyAddress: string; +} + +interface Call { + target: string; + value: BigNumberish; + data: BytesLike; +} + +// This test requires interop and so it requires Gateway chain. +// This is the name of the chain. +const GATEWAY_CHAIN_NAME = 'gateway'; + +// Returns a wallet that is both rich on L1 and on GW +async function prepareRichWallet(): Promise { + const generalConfig = loadConfig({ + pathToHome, + chain: GATEWAY_CHAIN_NAME, + config: 'general.yaml' + }); + const contractsConfig = loadConfig({ + pathToHome, + chain: GATEWAY_CHAIN_NAME, + config: 'contracts.yaml' + }); + const secretsConfig = loadConfig({ + pathToHome, + chain: GATEWAY_CHAIN_NAME, + config: 'secrets.yaml' + }); + const ethProviderAddress = secretsConfig.l1.l1_rpc_url; + const web3JsonRpc = generalConfig.api.web3_json_rpc.http_url; + + const richWallet = new zksync.Wallet( + getMainWalletPk('gateway'), + new zksync.Provider(web3JsonRpc), + new ethers.JsonRpcProvider(ethProviderAddress) + ); + + // We assume that Gateway has "ETH" as the base token. + // We deposit funds to ensure that the wallet is rich + await ( + await richWallet.deposit({ + token: zksync.utils.ETH_ADDRESS_IN_CONTRACTS, + amount: ethers.parseEther('10.0') + }) + ).wait(); + + return richWallet; +} + +/// There are the following kinds of tokens' states that we test: +/// At the moment of migration the token can be: +/// - Native to chain, already present on L1/other L2s. +/// - Native to chain, not present on L1 at all (can have unfinalized withdrawal). +/// - Native to L1, never been on the chain. +/// - Native to L1, already present on the chain. +/// - Native to another L2, never present on the chain. +/// - Native to another L2, already present on the chain. +/// After the chain migrates to GW, we can classify the states of the tokens the following way: +/// - Migrated the balance to GW. May be done after the token already received some deposits. +/// - Never migrated the balance to GW (but the token is known to the chain). May be done after the token. +/// - Never migrated the balance to GW (but the token is bridged for the first time). No migration should be needed at all. +/// After the chain migrates from GW, we need to test that all the tokens can be withdrawn in sufficient amounts to move +/// the entire balance to L1. It should not be possible to finalize all old interops. + +describe('Asset tracker migration test', function () { + let ethChainHandler: ChainHandler; + let erc20ChainHandler: ChainHandler; + + let l1RichWallet: ethers.Wallet; + let gwRichWallet: zksync.Wallet; + + let ethChainTokenPreBridged: L2ERC20Handler; + let ethChainTokenNotPreBridged: L2ERC20Handler; + let ethChainTokenUnfinalizedWithdrawalHandler: WithdrawalHandler; + let l1NativeToken: L1ERC20Handler; + let l1NativeTokenPreBridged: L1ERC20Handler; + let l1NativeToken2: L1ERC20Handler; + + let erc20ChainTokenPreBridged: L2ERC20Handler; + let erc20ChainTokenNotPreBridged: L2ERC20Handler; + + before('Setup the system', async function () { + console.log('Initializing rich wallet...'); + gwRichWallet = await prepareRichWallet(); + l1RichWallet = gwRichWallet.ethWallet(); + + console.log('Creating a new chain with ETH as the base token...'); + ethChainHandler = await ChainHandler.createNewChain('era'); + console.log('Creating a new chain with a custom token as the base token...'); + erc20ChainHandler = await ChainHandler.createNewChain('custom_token'); + }); + + step('TMP spawn tokens', async function () { + ethChainTokenPreBridged = await ethChainHandler.deployNativeToken(); + ethChainTokenNotPreBridged = await ethChainHandler.deployNativeToken(); + + l1NativeToken = await L1ERC20Handler.deployToken(l1RichWallet); + l1NativeTokenPreBridged = await L1ERC20Handler.deployToken(l1RichWallet); + l1NativeToken2 = await L1ERC20Handler.deployToken(l1RichWallet); + + erc20ChainTokenPreBridged = await erc20ChainHandler.deployNativeToken(); + erc20ChainTokenNotPreBridged = await erc20ChainHandler.deployNativeToken(); + }); + + step('Bridge tokens', async function () { + const withdrawalHandler1 = await ethChainTokenPreBridged.withdraw(); + + // For now it will be unfinalized, we'll use it later. + ethChainTokenUnfinalizedWithdrawalHandler = await ethChainTokenNotPreBridged.withdraw(); + + await l1NativeTokenPreBridged.deposit(ethChainHandler, DEFAULT_LARGE_AMOUNT); + await l1NativeTokenPreBridged.deposit(erc20ChainHandler, DEFAULT_LARGE_AMOUNT); + + await withdrawalHandler1.finalizeWithdrawal(l1RichWallet); + }); + + step('Migration of balances to GW', async function () { + await Promise.all([ + ethChainHandler.migrateToGateway() + // erc20ChainHandler.migrateToGateway() + ]); + + // const l2VersionTokenPreBridged = await l1NativeTokenPreBridged.atL2SameWallet(ethChainHandler); + + // const l1Native + + // Each of the below should Fail + ethChainTokenPreBridged.withdraw(); + ethChainTokenNotPreBridged.withdraw(); + + // // should fail + // l2VersionTokenPreBridged.withdraw(); + // // should also fail + // ethChainTokenUnfinalizedWithdrawalHandler.finalizeWithdrawal(l1RichWallet); + + // // We migrate the tokens two times. This is to + // // demonstrate that it is possible to call the migration again + // // and the handlers will still work. + // const migrationHandlers1 = [ + // await ethChainTokenPreBridged.migrateBalanceL2ToGW(), + // await ethChainTokenNotPreBridged.migrateBalanceL2ToGW(), + // await l2VersionTokenPreBridged.migrateBalanceL2ToGW() + // ]; + // const migrationHandlers2 = [ + // await ethChainTokenPreBridged.migrateBalanceL2ToGW(), + // await ethChainTokenNotPreBridged.migrateBalanceL2ToGW(), + // await l2VersionTokenPreBridged.migrateBalanceL2ToGW() + // ]; + + // // Sometimes we use migrationHandlers1, sometimes migrationHandlers 2, + // // these should be equivalent. + // // TODO: maybe check for actual equivalence of messages. + // await migrationHandlers1[0].finalizeMigration(l1RichWallet); + // await migrationHandlers2[1].finalizeMigration(l1RichWallet); + // await migrationHandlers1[0].finalizeMigration(l1RichWallet); + + // // Now all the below should succeed: + // // TODO: actually check that these withdrawals will finalize fine. + // // We should also spawn a withdrawal to be finalized after the chain has moved away from GW. + // await ethChainTokenPreBridged.withdraw(); + // await ethChainTokenNotPreBridged.withdraw(); + // await l2VersionTokenPreBridged.withdraw(); + // ethChainTokenUnfinalizedWithdrawalHandler.finalizeWithdrawal(l1RichWallet); + }); + + // step('Test receiving interop for migrated assets', async function () { + // // TODO + // }) + + // step('Test automatic registration', async function () { + // await l1NativeToken.deposit(ethChainHandler); + // // We dont withdraw it yet, we'll withdraw it after we migrate to L1. + // await l1NativeToken2.deposit(ethChainHandler); + // const l2Repr = await l1NativeToken.atL2SameWallet(ethChainHandler); + + // // should succeed + // const withdrawHandle = await l2Repr.withdraw(); + // await withdrawHandle.finalizeWithdrawal(l1RichWallet); + + // // TODO: dont forget to check asset migrtion number. + // }); + + // step('Migrate back to L1', async function () { + // await ethChainHandler.migrateFromGateway(); + + // const l2Token = await l1NativeToken2.atL2SameWallet(ethChainHandler); + // const withdrawHandler = await l2Token.withdraw(); + + // // should fail, since the chain has not balance. + // await withdrawHandler.finalizeWithdrawal(l1RichWallet); + + // await l2Token.migrateBalanceGWtoL1(gwRichWallet); + + // // Should succeed + // await withdrawHandler.finalizeWithdrawal(l1RichWallet); + + // // todo: test the ability to migrate all of the tokens' balances to the chain on L1. + + // // todo: test that all of the withdrawn tokens can be withdrawn and finalized. + // }) + + after('shutdown', async function () { + console.log('Tearing down chains...'); + if (ethChainHandler) { + await ethChainHandler.stopServer(); + } + if (erc20ChainHandler) { + await erc20ChainHandler.stopServer(); + } + console.log('Complete'); + }); +}); diff --git a/core/tests/token-balance-migration-test/tests/tester.ts b/core/tests/token-balance-migration-test/tests/tester.ts new file mode 100644 index 000000000000..89c9bc90e9be --- /dev/null +++ b/core/tests/token-balance-migration-test/tests/tester.ts @@ -0,0 +1,370 @@ +import * as ethers from 'ethers'; +import * as zksync from 'zksync-ethers'; +import { getMainWalletPk } from 'highlevel-test-tools/src/wallets'; +import { createChainAndStartServer, TestChain, ChainType } from 'highlevel-test-tools/src/create-chain'; +import path from 'path'; +import { loadConfig } from 'utils/build/file-configs'; +import { sleep } from 'zksync-ethers/build/utils'; +import { L2_NATIVE_TOKEN_VAULT_ADDRESS } from 'utils/src/constants'; +import * as fs from 'fs'; + +const RICH_WALLET_L1_BALANCE = ethers.parseEther('10.0'); +const RICH_WALLET_L2_BALANCE = RICH_WALLET_L1_BALANCE; +const TEST_SUIT_NAME = 'AT_CHAIN_MIGRATION_TEST'; +const pathToHome = path.join(__dirname, '../../../..'); + +function readArtifact(contractName: string, outFolder: string = 'out') { + return JSON.parse( + fs + .readFileSync( + path.join(pathToHome, `./contracts/l1-contracts/out/${contractName}.sol/${contractName}.json`) + ) + .toString() + ); +} + +const ERC20_EVM_ARTIFACT = readArtifact('TestnetERC20Token'); +const ERC20_EVM_BYTECODE = ERC20_EVM_ARTIFACT.bytecode.object; +const ERC20_ABI = ERC20_EVM_ARTIFACT.abi; + +const ERC20_ZKEVM_BYTECODE = readArtifact('TestnetERC20Token', 'zkout').bytecode.object; + +function randomTokenProps() { + const name = 'NAME-' + ethers.hexlify(ethers.randomBytes(4)); + const symbol = 'SYM-' + ethers.hexlify(ethers.randomBytes(4)); + const decimals = Math.min(Math.floor(Math.random() * 18) + 1, 18); + + return { name, symbol, decimals }; +} + +export const DEFAULT_SMALL_AMOUNT = 1n; +export const DEFAULT_LARGE_AMOUNT = ethers.parseEther('0.01'); + +// TODO: For now, only works with ETH chains +async function generateChainRichWallet(chainName: string): Promise { + const generalConfig = loadConfig({ + pathToHome, + chain: chainName, + config: 'general.yaml' + }); + const contractsConfig = loadConfig({ + pathToHome, + chain: chainName, + config: 'contracts.yaml' + }); + const secretsConfig = loadConfig({ + pathToHome, + chain: chainName, + config: 'secrets.yaml' + }); + const ethProviderAddress = secretsConfig.l1.l1_rpc_url; + const web3JsonRpc = generalConfig.api.web3_json_rpc.http_url; + + const richWallet = new zksync.Wallet( + getMainWalletPk('gateway'), + new zksync.Provider(web3JsonRpc), + new ethers.JsonRpcProvider(ethProviderAddress) + ); + + // We assume that Gateway has "ETH" as the base token. + // We deposit funds to ensure that the wallet is rich + await ( + await richWallet.deposit({ + token: zksync.utils.ETH_ADDRESS_IN_CONTRACTS, + amount: RICH_WALLET_L2_BALANCE + }) + ).wait(); + + return richWallet; +} + +function getL2Ntv(l2Wallet: zksync.Wallet) { + const abi = readArtifact('L2NativeTokenVault').abi; + return new zksync.Contract(L2_NATIVE_TOKEN_VAULT_ADDRESS, abi, l2Wallet); +} + +export class ChainHandler { + // public name: string; + public l2RichWallet: zksync.Wallet; + + public inner: TestChain; + + constructor(inner: TestChain, l2RichWallet: zksync.Wallet) { + this.inner = inner; + this.l2RichWallet = l2RichWallet; + } + + ethersWalletToZK(ethersWallet: ethers.Wallet) { + return new zksync.Wallet(ethersWallet.privateKey, this.l2RichWallet.provider, ethersWallet.provider!); + } + + async stopServer() { + await this.inner.mainNode.kill(); + } + + async migrateToGateway() {} + + async migrateFromGateway() {} + + static async createNewChain(chainType: ChainType): Promise { + const testChain = await createChainAndStartServer(chainType, TEST_SUIT_NAME); + + // Need to wait for a bit before the server works fully + await sleep(2000); + + const handler = new ChainHandler(testChain, await generateChainRichWallet(testChain.chainName)); + + return handler; + } + + async deployNativeToken() { + return await L2ERC20Handler.deployToken(this.l2RichWallet); + } +} + +export class L2ERC20Handler { + public address: string; + public l2Wallet: zksync.Wallet; + public contract: zksync.Contract; + _cachedAssetId: string | null = null; + + constructor(address: string, l2Wallet: zksync.Wallet) { + this.address = address; + this.l2Wallet = l2Wallet; + this.contract = new zksync.Contract(address, ERC20_ABI, l2Wallet); + } + + async assetId(assertNonNull: boolean = true): Promise { + if (this._cachedAssetId) { + return this._cachedAssetId; + } + const l2Ntv = getL2Ntv(this.l2Wallet); + + const l2AssetId = await l2Ntv.assetId(this.address); + if (l2AssetId == ethers.ZeroHash) { + if (assertNonNull) { + throw new Error('Expected to be non null'); + } else { + // We dont cache empty value. + return l2AssetId; + } + } + + this._cachedAssetId = l2AssetId; + return l2AssetId; + } + + async registerIfNeeded(): Promise { + const l2Ntv = getL2Ntv(this.l2Wallet); + const currentAssetId = await this.assetId(false); + if (currentAssetId == ethers.ZeroHash) { + // Registering the token + await (await l2Ntv.registerToken(this.address)).wait(); + } + + return await this.assetId(); + } + + async withdraw(amount: bigint = DEFAULT_SMALL_AMOUNT): Promise { + await this.registerIfNeeded(); + + if ((await this.contract.allowance(this.l2Wallet.address, L2_NATIVE_TOKEN_VAULT_ADDRESS)) < amount) { + await (await this.contract.approve(L2_NATIVE_TOKEN_VAULT_ADDRESS, 0)).wait(); + await (await this.contract.approve(L2_NATIVE_TOKEN_VAULT_ADDRESS, amount)).wait(); + } + + const withdrawTx = await this.l2Wallet.withdraw({ + token: this.address, + amount + }); + + return new WithdrawalHandler(withdrawTx.hash, this.l2Wallet.provider); + } + + async migrateBalanceL2ToGW(): Promise { + throw new Error(''); + } + + async migrateBalanceGWtoL1(gwRichWallet: zksync.Wallet): Promise { + throw new Error(''); + } + + static async deployToken(l2Wallet: zksync.Wallet) { + const factory = new zksync.ContractFactory(ERC20_ABI, ERC20_ZKEVM_BYTECODE, l2Wallet, 'create'); + + const props = randomTokenProps(); + const newToken = await factory.deploy(props.name, props.symbol, props.decimals); + await newToken.waitForDeployment(); + + const handler = new L2ERC20Handler(await newToken.getAddress(), l2Wallet); + await (await handler.contract.mint(l2Wallet.address, RICH_WALLET_L1_BALANCE)).wait(); + + return handler; + } +} + +export class L1ERC20Handler { + public address: string; + public l1Wallet: ethers.Wallet; + public contract: zksync.Contract; + + constructor(address: string, l1Wallet: ethers.Wallet) { + this.address = address; + this.l1Wallet = l1Wallet; + this.contract = new ethers.Contract(address, ERC20_ABI, l1Wallet); + } + + // We always wait for the deposit to be finalized. + async deposit(chain: ChainHandler, amount: ethers.BigNumberish = DEFAULT_SMALL_AMOUNT) { + const zksyncWallet = chain.ethersWalletToZK(this.l1Wallet); + const depositTx = await zksyncWallet.deposit({ + token: this.address, + amount, + approveERC20: true, + approveBaseERC20: true + }); + await depositTx.wait(); + } + + async atL2SameWallet(chainHandler: ChainHandler) { + // FIXME: actually obtain it + const addrL2 = ethers.ZeroAddress; + + return new L2ERC20Handler(addrL2, chainHandler.ethersWalletToZK(this.l1Wallet)); + } + + static async deployToken(l1Wallet: ethers.Wallet) { + const factory = new ethers.ContractFactory(ERC20_ABI, ERC20_EVM_BYTECODE, l1Wallet); + + const props = randomTokenProps(); + const newToken = await factory.deploy(props.name, props.symbol, props.decimals); + await newToken.waitForDeployment(); + + const handler = new L1ERC20Handler(await newToken.getAddress(), l1Wallet); + await (await handler.contract.mint(l1Wallet.address, RICH_WALLET_L1_BALANCE)).wait(); + + return handler; + } +} + +export class WithdrawalHandler { + public txHash: string; + public l2Provider: zksync.Provider; + + constructor(txHash: string, provider: zksync.Provider) { + this.txHash = txHash; + this.l2Provider = provider; + } + + async finalizeWithdrawal(l1RichWallet: ethers.Wallet) { + // Firstly, we've need to wait for the batch to be finalized. + + const l2Wallet = new zksync.Wallet(l1RichWallet.privateKey, this.l2Provider, l1RichWallet.provider!); + + const receipt = await l2Wallet.provider.getTransactionReceipt(this.txHash); + if (!receipt) { + throw new Error('Receipt'); + } + + await waitForL2ToL1LogProof(l2Wallet.provider, receipt.blockNumber, this.txHash); + + await (await l2Wallet.finalizeWithdrawal(this.txHash)).wait(); + } +} + +export class MigrationHandler { + public txHash: string; + + constructor(txHash: string, provider: zksync.Provider) { + this.txHash = txHash; + } + + async finalizeMigration(l1RichWallet: ethers.Wallet) {} +} + +async function newSpawnNewChainZKStack() {} + +export class Tester { + public runningFee: Map; + constructor( + public ethProvider: ethers.Provider, + public ethWallet: ethers.Wallet, + public syncWallet: zksync.Wallet, + public web3Provider: zksync.Provider + ) { + this.runningFee = new Map(); + } + + // prettier-ignore + static async init(ethProviderAddress: string, web3JsonRpc: string) { + const ethProvider = new ethers.JsonRpcProvider(ethProviderAddress); + + const chainName = process.env.CHAIN_NAME!!; + let ethWallet = new ethers.Wallet(getMainWalletPk(chainName)); + + ethWallet = ethWallet.connect(ethProvider); + const web3Provider = new zksync.Provider(web3JsonRpc); + web3Provider.pollingInterval = 100; // It's OK to keep it low even on stage. + const syncWallet = new zksync.Wallet(ethWallet.privateKey, web3Provider, ethProvider); + + + // Since some tx may be pending on stage, we don't want to get stuck because of it. + // In order to not get stuck transactions, we manually cancel all the pending txs. + const latestNonce = await ethWallet.getNonce('latest'); + const pendingNonce = await ethWallet.getNonce('pending'); + const cancellationTxs = []; + for (let nonce = latestNonce; nonce != pendingNonce; nonce++) { + // For each transaction to override it, we need to provide greater fee. + // We would manually provide a value high enough (for a testnet) to be both valid + // and higher than the previous one. It's OK as we'll only be charged for the bass fee + // anyways. We will also set the miner's tip to 5 gwei, which is also much higher than the normal one. + const maxFeePerGas = ethers.parseEther("0.00000025"); // 250 gwei + const maxPriorityFeePerGas = ethers.parseEther("0.000000005"); // 5 gwei + cancellationTxs.push(ethWallet.sendTransaction({ to: ethWallet.address, nonce, maxFeePerGas, maxPriorityFeePerGas }).then((tx) => tx.wait())); + } + if (cancellationTxs.length > 0) { + await Promise.all(cancellationTxs); + console.log(`Canceled ${cancellationTxs.length} pending transactions`); + } + + return new Tester(ethProvider, ethWallet, syncWallet, web3Provider); + } + + emptyWallet() { + const walletHD = zksync.Wallet.createRandom(); + return new zksync.Wallet(walletHD.privateKey, this.web3Provider, this.ethProvider); + } +} + +export async function waitUntilBlockFinalized(provider: zksync.Provider, blockNumber: number) { + console.log('Waiting for block to be finalized...', blockNumber); + let printedBlockNumber = 0; + while (true) { + const block = await provider.getBlock('finalized'); + if (blockNumber <= block.number) { + break; + } else { + if (printedBlockNumber < block.number) { + console.log('Waiting for block to be finalized...', blockNumber, block.number); + console.log('time', new Date().toISOString()); + printedBlockNumber = block.number; + } + await zksync.utils.sleep(provider.pollingInterval); + } + } +} + +export async function waitForL2ToL1LogProof(provider: zksync.Provider, blockNumber: number, txHash: string) { + console.log('waiting for block to be finalized'); + // First, we wait for block to be finalized. + await waitUntilBlockFinalized(provider, blockNumber); + + console.log('waiting for log proof'); + // Second, we wait for the log proof. + let i = 0; + while ((await provider.getLogProof(txHash)) == null) { + console.log(`Waiting for log proof... ${i}`); + await zksync.utils.sleep(provider.pollingInterval); + i++; + } +} diff --git a/core/tests/token-balance-migration-test/tsconfig.json b/core/tests/token-balance-migration-test/tsconfig.json new file mode 100644 index 000000000000..3de8e1a1c606 --- /dev/null +++ b/core/tests/token-balance-migration-test/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "target": "es2020", + "module": "commonjs", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true + } +} diff --git a/core/tests/token-balance-migration-test/yarn.lock b/core/tests/token-balance-migration-test/yarn.lock new file mode 100644 index 000000000000..18dcc1747c53 --- /dev/null +++ b/core/tests/token-balance-migration-test/yarn.lock @@ -0,0 +1,1008 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@adraffy/ens-normalize@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" + integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" + integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@noble/curves@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" + integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== + dependencies: + "@noble/hashes" "1.3.2" + +"@noble/hashes@1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" + integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== + +"@tsconfig/node10@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + +"@types/chai@^4.2.21": + version "4.3.20" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.20.tgz#cb291577ed342ca92600430841a00329ba05cecc" + integrity sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ== + +"@types/mocha-steps@^1.3.0": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@types/mocha-steps/-/mocha-steps-1.3.3.tgz#69e178d2e3ccdcba65bedda07f69a26c4f3bac98" + integrity sha512-9xRpcsshkEF3UeVZNmXuUumQ2+Acj1BkwzyywU+Q0DkpoW7dxFSN0e8OsyBngTjLiLGoJeI/Uz1t9zKdi6rUUg== + dependencies: + "@types/mocha" "*" + +"@types/mocha@*": + version "10.0.10" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.10.tgz#91f62905e8d23cbd66225312f239454a23bebfa0" + integrity sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q== + +"@types/mocha@^8.2.3": + version "8.2.3" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.2.3.tgz#bbeb55fbc73f28ea6de601fbfa4613f58d785323" + integrity sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw== + +"@types/node-fetch@^2.5.7": + version "2.6.13" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.13.tgz#e0c9b7b5edbdb1b50ce32c127e85e880872d56ee" + integrity sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw== + dependencies: + "@types/node" "*" + form-data "^4.0.4" + +"@types/node@*": + version "24.9.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-24.9.1.tgz#b7360b3c789089e57e192695a855aa4f6981a53c" + integrity sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg== + dependencies: + undici-types "~7.16.0" + +"@types/node@22.7.5": + version "22.7.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b" + integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ== + dependencies: + undici-types "~6.19.2" + +"@types/node@^18.19.15": + version "18.19.130" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.130.tgz#da4c6324793a79defb7a62cba3947ec5add00d59" + integrity sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg== + dependencies: + undici-types "~5.26.4" + +"@ungap/promise-all-settled@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" + integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== + +acorn-walk@^8.1.1: + version "8.3.4" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" + integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== + dependencies: + acorn "^8.11.0" + +acorn@^8.11.0, acorn@^8.4.1: + version "8.15.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" + integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== + +aes-js@4.0.0-beta.5: + version "4.0.0-beta.5" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" + integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== + +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + +brace-expansion@^1.1.7: + version "1.1.12" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843" + integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +chai-as-promised@^7.1.1: + version "7.1.2" + resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.2.tgz#70cd73b74afd519754161386421fb71832c6d041" + integrity sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw== + dependencies: + check-error "^1.0.2" + +chai@^4.3.4: + version "4.5.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.5.0.tgz#707e49923afdd9b13a8b0b47d33d732d13812fd8" + integrity sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" + pathval "^1.1.1" + type-detect "^4.1.0" + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +check-error@^1.0.2, check-error@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" + integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== + dependencies: + get-func-name "^2.0.2" + +chokidar@3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + 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" + optionalDependencies: + fsevents "~2.3.2" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +debug@4.3.3: + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + dependencies: + ms "2.1.2" + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +deep-eql@^4.1.3: + version "4.1.4" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.4.tgz#d0d3912865911bb8fac5afb4e3acfa6a28dc72b7" + integrity sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg== + dependencies: + type-detect "^4.0.0" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +diff@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +escalade@^3.1.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-string-regexp@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +ethers@^6.13.5: + version "6.15.0" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.15.0.tgz#2980f2a3baf0509749b7e21f8692fa8a8349c0e3" + integrity sha512-Kf/3ZW54L4UT0pZtsY/rf+EkBU7Qi5nnhonjUb8yTXcxH3cdcWrV2cRyk0Xk/4jK6OoHhxxZHriyhje20If2hQ== + dependencies: + "@adraffy/ens-normalize" "1.10.1" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@types/node" "22.7.5" + aes-js "4.0.0-beta.5" + tslib "2.7.0" + ws "8.17.1" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +find-up@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +form-data@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.4.tgz#784cdcce0669a9d68e94d11ac4eea98088edd2c4" + integrity sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + hasown "^2.0.2" + mime-types "^2.1.12" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-func-name@^2.0.1, get-func-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== + +get-intrinsic@^1.2.6: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + 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" + +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +growl@1.10.5: + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +js-yaml@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +log-symbols@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +loupe@^2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" + integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== + dependencies: + get-func-name "^2.0.1" + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +minimatch@4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.1.tgz#40d9d511a46bdc4e563c22c3080cde9c0d8299b4" + integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^3.0.4: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +mocha-steps@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/mocha-steps/-/mocha-steps-1.3.0.tgz#2449231ec45ec56810f65502cb22e2571862957f" + integrity sha512-KZvpMJTqzLZw3mOb+EEuYi4YZS41C9iTnb7skVFRxHjUd1OYbl64tCMSmpdIRM9LnwIrSOaRfPtNpF5msgv6Eg== + +mocha@^9.0.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.2.tgz#d70db46bdb93ca57402c809333e5a84977a88fb9" + integrity sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g== + dependencies: + "@ungap/promise-all-settled" "1.1.2" + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.3" + debug "4.3.3" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.2.0" + growl "1.10.5" + he "1.2.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "4.2.1" + ms "2.1.3" + nanoid "3.3.1" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + which "2.0.2" + workerpool "6.2.0" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" + integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== + +node-fetch@^2.6.1: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +pathval@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" + integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== + +picomatch@^2.0.4, picomatch@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +prettier@^2.3.2: + version "2.8.8" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" + integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +serialize-javascript@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + 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" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-json-comments@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +ts-node@^10.1.0: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + +tslib@2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== + +type-detect@^4.0.0, type-detect@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.1.0.tgz#deb2453e8f08dcae7ae98c626b13dddb0155906c" + integrity sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== + +typescript@^4.3.5: + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + +undici-types@~7.16.0: + version "7.16.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.16.0.tgz#ffccdff36aea4884cbfce9a750a0580224f58a46" + integrity sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw== + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +workerpool@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b" + integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" + integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + 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" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +"zksync-ethers@https://github.com/zksync-sdk/zksync-ethers#di/avoid-zks-estimate-fee-build": + version "6.18.0" + resolved "https://github.com/zksync-sdk/zksync-ethers#b64fd27144356938c8876185add4cfdd537c15ef" diff --git a/package.json b/package.json index bd5880e6a778..6c47d6488d4d 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "core/tests/gateway-migration-test/", "core/tests/ts-integration", "core/tests/highlevel-test-tools", + "core/tests/asset-tracker-chain-migration-test", "infrastructure/protocol-upgrade" ], "nohoist": [ diff --git a/yarn.lock b/yarn.lock index 617a6784f28f..6ea126ebfdec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3316,7 +3316,7 @@ resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.18.0.tgz#8e77a02a09ecce957255a2f48c9a7178ec191908" integrity sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA== -"@solidity-parser/parser@^0.20.0": +"@solidity-parser/parser@^0.20.0", "@solidity-parser/parser@^0.20.2": version "0.20.2" resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.20.2.tgz#e07053488ed60dae1b54f6fe37bb6d2c5fe146a7" integrity sha512-rbu0bzwNvMcwAjH86hiEAcOeRI2EeK8zCkHDrFykh/Al8mvJeFmjy3UrE7GYQjNwOgbGUUtCn5/k8CB8zIu7QA== @@ -11208,6 +11208,33 @@ solhint@^5.1.0: optionalDependencies: prettier "^2.8.3" +solhint@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/solhint/-/solhint-6.0.1.tgz#aecf21f114ad060674f6e761e8971c35fd140944" + integrity sha512-Lew5nhmkXqHPybzBzkMzvvWkpOJSSLTkfTZwRriWvfR2naS4YW2PsjVGaoX9tZFmHh7SuS+e2GEGo5FPYYmJ8g== + dependencies: + "@solidity-parser/parser" "^0.20.2" + ajv "^6.12.6" + ajv-errors "^1.0.1" + antlr4 "^4.13.1-patch-1" + ast-parents "^0.0.1" + better-ajv-errors "^2.0.2" + chalk "^4.1.2" + commander "^10.0.0" + cosmiconfig "^8.0.0" + fast-diff "^1.2.0" + glob "^8.0.3" + ignore "^5.2.4" + js-yaml "^4.1.0" + latest-version "^7.0.0" + lodash "^4.17.21" + pluralize "^8.0.0" + semver "^7.5.2" + table "^6.8.1" + text-table "^0.2.0" + optionalDependencies: + prettier "^2.8.3" + solidity-comments-extractor@^0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz#99d8f1361438f84019795d928b931f4e5c39ca19" diff --git a/zkstack_cli/crates/zkstack/src/commands/dev/commands/test/args/mod.rs b/zkstack_cli/crates/zkstack/src/commands/dev/commands/test/args/mod.rs index c8834fd6736a..ad10292004a5 100644 --- a/zkstack_cli/crates/zkstack/src/commands/dev/commands/test/args/mod.rs +++ b/zkstack_cli/crates/zkstack/src/commands/dev/commands/test/args/mod.rs @@ -4,4 +4,5 @@ pub mod integration; pub mod recovery; pub mod revert; pub mod rust; +pub mod token_balance_migration; pub mod upgrade; diff --git a/zkstack_cli/crates/zkstack/src/commands/dev/commands/test/args/token_balance_migration.rs b/zkstack_cli/crates/zkstack/src/commands/dev/commands/test/args/token_balance_migration.rs new file mode 100644 index 000000000000..15d7d0dce514 --- /dev/null +++ b/zkstack_cli/crates/zkstack/src/commands/dev/commands/test/args/token_balance_migration.rs @@ -0,0 +1,11 @@ +use clap::Parser; + +use crate::commands::dev::messages::MSG_NO_DEPS_HELP; + +#[derive(Debug, Parser)] +pub struct TokenBalanceMigrationArgs { + #[clap(short, long, help = MSG_NO_DEPS_HELP)] + pub no_deps: bool, + #[clap(short, long)] + pub gateway_chain: Option, +} diff --git a/zkstack_cli/crates/zkstack/src/commands/dev/commands/test/mod.rs b/zkstack_cli/crates/zkstack/src/commands/dev/commands/test/mod.rs index 00750c862a85..1ae4dd1b59b0 100644 --- a/zkstack_cli/crates/zkstack/src/commands/dev/commands/test/mod.rs +++ b/zkstack_cli/crates/zkstack/src/commands/dev/commands/test/mod.rs @@ -1,17 +1,16 @@ use args::{ - fees::FeesArgs, integration::IntegrationArgs, recovery::RecoveryArgs, revert::RevertArgs, - rust::RustArgs, upgrade::UpgradeArgs, + fees::FeesArgs, gateway_migration::GatewayMigrationArgs, integration::IntegrationArgs, + recovery::RecoveryArgs, revert::RevertArgs, rust::RustArgs, + token_balance_migration::TokenBalanceMigrationArgs, upgrade::UpgradeArgs, }; use clap::Subcommand; use xshell::Shell; -use crate::commands::dev::{ - commands::test::args::gateway_migration::GatewayMigrationArgs, - messages::{ - MSG_BUILD_ABOUT, MSG_GATEWAY_TEST_ABOUT, MSG_INTEGRATION_TESTS_ABOUT, - MSG_L1_CONTRACTS_ABOUT, MSG_LOADTEST_ABOUT, MSG_PROVER_TEST_ABOUT, MSG_RECOVERY_TEST_ABOUT, - MSG_REVERT_TEST_ABOUT, MSG_RUST_TEST_ABOUT, MSG_TEST_WALLETS_INFO, MSG_UPGRADE_TEST_ABOUT, - }, +use crate::commands::dev::messages::{ + MSG_BUILD_ABOUT, MSG_GATEWAY_TEST_ABOUT, MSG_INTEGRATION_TESTS_ABOUT, MSG_L1_CONTRACTS_ABOUT, + MSG_LOADTEST_ABOUT, MSG_PROVER_TEST_ABOUT, MSG_RECOVERY_TEST_ABOUT, MSG_REVERT_TEST_ABOUT, + MSG_RUST_TEST_ABOUT, MSG_TEST_WALLETS_INFO, MSG_TOKEN_BALANCE_MIGRATION_TEST_ABOUT, + MSG_UPGRADE_TEST_ABOUT, }; mod args; @@ -26,6 +25,7 @@ mod prover; mod recovery; mod revert; mod rust; +mod token_balance_migration; mod upgrade; pub mod utils; mod wallet; @@ -56,6 +56,8 @@ pub enum TestCommands { Loadtest, #[clap(about = MSG_GATEWAY_TEST_ABOUT, alias = "gm")] GatewayMigration(GatewayMigrationArgs), + #[clap(about = MSG_TOKEN_BALANCE_MIGRATION_TEST_ABOUT, alias = "tbm")] + TokenBalanceMigration(TokenBalanceMigrationArgs), } pub async fn run(shell: &Shell, args: TestCommands) -> anyhow::Result<()> { @@ -72,5 +74,6 @@ pub async fn run(shell: &Shell, args: TestCommands) -> anyhow::Result<()> { TestCommands::Wallet => wallet::run(shell), TestCommands::Loadtest => loadtest::run(shell).await, TestCommands::GatewayMigration(args) => gateway_migration::run(shell, args), + TestCommands::TokenBalanceMigration(args) => token_balance_migration::run(shell, args), } } diff --git a/zkstack_cli/crates/zkstack/src/commands/dev/commands/test/token_balance_migration.rs b/zkstack_cli/crates/zkstack/src/commands/dev/commands/test/token_balance_migration.rs new file mode 100644 index 000000000000..5418dbb4c9e7 --- /dev/null +++ b/zkstack_cli/crates/zkstack/src/commands/dev/commands/test/token_balance_migration.rs @@ -0,0 +1,49 @@ +use xshell::{cmd, Shell}; +use zkstack_cli_common::{cmd::Cmd, logger, spinner::Spinner}; +use zkstack_cli_config::{ChainConfig, ZkStackConfig, ZkStackConfigTrait}; + +use super::utils::install_and_build_dependencies; +use crate::commands::dev::{ + commands::test::args::token_balance_migration::TokenBalanceMigrationArgs, + messages::{ + MSG_TOKEN_BALANCE_MIGRATION_TEST_RUN_INFO, MSG_TOKEN_BALANCE_MIGRATION_TEST_RUN_SUCCESS, + }, +}; + +const TOKEN_BALANCE_MIGRATION_TEST_PATH: &str = "core/tests/token-balance-migration-test"; + +pub fn run(shell: &Shell, args: TokenBalanceMigrationArgs) -> anyhow::Result<()> { + let chain_config = ZkStackConfig::current_chain(shell)?; + + logger::info(MSG_TOKEN_BALANCE_MIGRATION_TEST_RUN_INFO); + + if !args.no_deps { + install_and_build_dependencies(shell, &chain_config.link_to_code())?; + } + + shell.change_dir( + chain_config + .link_to_code() + .join(TOKEN_BALANCE_MIGRATION_TEST_PATH), + ); + run_test(shell, &chain_config, args.gateway_chain)?; + logger::outro(MSG_TOKEN_BALANCE_MIGRATION_TEST_RUN_SUCCESS); + + Ok(()) +} + +fn run_test( + shell: &Shell, + chain_config: &ChainConfig, + gateway_chain: Option, +) -> anyhow::Result<()> { + Spinner::new(MSG_TOKEN_BALANCE_MIGRATION_TEST_RUN_INFO).freeze(); + let mut cmd = Cmd::new(cmd!(shell, "yarn mocha tests/migration.test.ts")) + .env("CHAIN_NAME", &chain_config.name); + if let Some(chain) = gateway_chain { + cmd = cmd.env("GATEWAY_CHAIN", chain); + } + cmd.with_force_run().run()?; + + Ok(()) +} diff --git a/zkstack_cli/crates/zkstack/src/commands/dev/messages.rs b/zkstack_cli/crates/zkstack/src/commands/dev/messages.rs index a45bebb965b5..c4ef6d9e2e17 100644 --- a/zkstack_cli/crates/zkstack/src/commands/dev/messages.rs +++ b/zkstack_cli/crates/zkstack/src/commands/dev/messages.rs @@ -100,6 +100,7 @@ pub(super) const MSG_REVERT_TEST_ABOUT: &str = "Run revert tests"; pub(super) const MSG_RECOVERY_TEST_ABOUT: &str = "Run recovery tests"; pub(super) const MSG_UPGRADE_TEST_ABOUT: &str = "Run upgrade tests"; pub(super) const MSG_GATEWAY_TEST_ABOUT: &str = "Run gateway tests"; +pub(super) const MSG_TOKEN_BALANCE_MIGRATION_TEST_ABOUT: &str = "Run token balance migration tests"; pub(super) const MSG_RUST_TEST_ABOUT: &str = "Run unit-tests, accepts optional cargo test flags"; pub(super) const MSG_TEST_RUST_OPTIONS_HELP: &str = "Cargo test flags"; pub(super) const MSG_BUILD_ABOUT: &str = "Build all test dependencies"; @@ -172,6 +173,12 @@ pub(super) const MSG_GATEWAY_UPGRADE_TEST_RUN_INFO: &str = "Running gateway migr pub(super) const MSG_GATEWAY_UPGRADE_TEST_RUN_SUCCESS: &str = "Gateway migration test ran successfully"; +// Asset migration test related messages +pub(super) const MSG_TOKEN_BALANCE_MIGRATION_TEST_RUN_INFO: &str = + "Running token balance migration test"; +pub(super) const MSG_TOKEN_BALANCE_MIGRATION_TEST_RUN_SUCCESS: &str = + "Token balance migration test ran successfully"; + // Upgrade tests related messages pub(super) const MSG_UPGRADE_TEST_RUN_INFO: &str = "Running upgrade test"; pub(super) const MSG_UPGRADE_TEST_RUN_SUCCESS: &str = "Upgrade test ran successfully";