diff --git a/foundry.toml b/foundry.toml index 43d9d0c..ec7629b 100644 --- a/foundry.toml +++ b/foundry.toml @@ -13,3 +13,33 @@ evm_version = 'paris' 43 = { key = "empty", url = "https://evmx.cloud.blockscout.com/api?" } 421614 = { key = "${ARBISCAN_API_KEY}", url = "https://api-sepolia.arbiscan.io/api?" } 11155420 = { key = "${OPTIMISM_API_KEY}", url = "https://optimism-sepolia.blockscout.com/api?" } + +[labels] +0x935b06902cA5C8bb4C76e18738561c294D377A93 = "AddressResolver" +0xD1586EaaA0d473E6655c11A927cE4FbED648F3BF = "AddressResolverImpl" +0xECa623A443F21B705714D4A0f810d0A5D135FF6F = "AsyncDeployer" +0x1B0ea1b79B526dD3d5889Bb33Dbd24f790C23102 = "AsyncDeployerImpl" +0xD044f27A9c5EE4f92EF0e38685276adFDF13E90E = "AuctionManager" +0xC72BE9e639DA23570fa1eF2fF2cb7901a081916F = "AuctionManagerImpl" +0x72f4C225B4B4f0F9608a50aEe17dA9e11dcb94b2 = "Configurations" +0x351De7e4275dA7f49F75363e4E7ea86Dfe050501 = "ConfigurationsImpl" +0x5E9d1072B60D6c752B1593F5937393413372E5eF = "DeployForwarder" +0x1b7752F0039E80Aa38f7CF8b5d18798dD2ac1597 = "DeployForwarderImpl" +0x526796AC60e45CBB9b17c654C9447Baf160C084d = "ERC1967Factory" +0xA07208F9e7aE243F922317ab6604DC9F86822406 = "FeesManager" +0xbD22EDD6559B28614f44D1c768EC26491CDE1cDD = "FeesManagerImpl" +0xe2054B575664dfDBD7a7FbAf2B12420ae88DE0FF = "FeesPool" +0x38e24A2F157817b830F36A35b862F24B1494d1aD = "PromiseResolver" +0x39b5D3FBBa1BC28438e25955aaB412C7576eCd61 = "ReadPrecompile" +0x2E928C000bdC1f90716B05cE2D7182C9FA081d31 = "RequestHandler" +0xD38ae1a6C410c7681ac464bd60009198406035Ed = "RequestHandlerImpl" +0xb14a7763f09eCbd47bC5230D6170547a22834a82 = "SchedulePrecompile" +0x4C846eCa55ad8cF19B9D5d906225da7b565174C1 = "Watcher" +0x2920F4FB50343EF2b33096650cE234E8aF9E8556 = "WatcherImpl" +0x393007B660a00970b25E34FEd6506CE96120f8e2 = "WritePrecompile" +0x0026c4736E57fE2817b53f6df1E0808c3a61984d = "WritePrecompileImpl" +0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d = "ContractFactoryPlug" +0xbDE0D2da12F703Ccd275d721214745BccDCAD124 = "FastSwitchboard" +0x5F77550E3072c913A20B2fbdAb14026fe0E8B450 = "FeesPlug" +0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a = "Socket" +0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38 = "SocketBatcher" diff --git a/package.json b/package.json index fe1a19d..0d1e888 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "upload": "tsx script/runIntegrationTests.ts -u", "scheduler": "tsx script/runIntegrationTests.ts -s", "insufficient": "tsx script/runIntegrationTests.ts -i", - "revert": "tsx script/runIntegrationTests.ts -v" + "revert": "tsx script/runIntegrationTests.ts -v", + "deployment": "tsx script/runIntegrationTests.ts -d" } } diff --git a/script/runIntegrationTests.ts b/script/runIntegrationTests.ts index 3fe86e0..5bd24e0 100644 --- a/script/runIntegrationTests.ts +++ b/script/runIntegrationTests.ts @@ -11,6 +11,7 @@ import { executeUploadTests } from './tests/upload_tests.js'; import { executeSchedulerTests } from './tests/scheduler_tests.js'; import { executeInsufficientFeesTests } from './tests/insufficient_tests.js'; import { executeRevertTests } from './tests/revert_tests.js'; +import { executeDeployTests } from './tests/deploy_tests.js'; // Help function function showHelp(): void { @@ -38,6 +39,7 @@ function parseFlags(args: string[]): TestFlags { scheduler: args.includes('-s') || args.includes('-a'), insufficient: args.includes('-i') || args.includes('-a'), revert: args.includes('-v') || args.includes('-a'), + deployment: args.includes('-d') || args.includes('-a'), all: args.includes('-a') }; } @@ -59,31 +61,35 @@ async function main(): Promise { // Execute tests based on flags if (flags.write) { - await executeWriteTests(chains.evmxChain, chains.arbChain); + await executeWriteTests(chains); } if (flags.read) { - await executeReadTests(chains.evmxChain, chains.arbChain); + await executeReadTests(chains); } if (flags.trigger) { - await executeTriggerTests(chains.evmxChain, chains.arbChain, chains.opChain); + await executeTriggerTests(chains); } if (flags.upload) { - await executeUploadTests(chains.evmxChain, chains.arbChain); + await executeUploadTests(chains); } if (flags.scheduler) { - await executeSchedulerTests(chains.evmxChain, chains.arbChain); + await executeSchedulerTests(chains); } if (flags.insufficient) { - await executeInsufficientFeesTests(chains.evmxChain, chains.arbChain); + await executeInsufficientFeesTests(chains); } if (flags.revert) { - await executeRevertTests(chains.evmxChain, chains.arbChain); + await executeRevertTests(chains); + } + + if (flags.deployment) { + await executeDeployTests(chains); } console.log(`${COLORS.GREEN}All selected tests completed successfully!${COLORS.NC}`); diff --git a/script/tests/deploy_tests.ts b/script/tests/deploy_tests.ts new file mode 100644 index 0000000..6d1e03e --- /dev/null +++ b/script/tests/deploy_tests.ts @@ -0,0 +1,115 @@ +import { parseAbi, type Address } from 'viem'; +import { deployAppGateway, deployOnchain, sendTransaction } from '../utils/deployer.js'; +import { depositFunds, withdrawFunds } from '../utils/fees-manager.js'; +import { fetchForwarderAndOnchainAddress, getTxDetails, selectRandomChains } from '../utils/helpers.js'; +import { ContractAddresses, ChainConfig } from '../utils/types.js'; +import { COLORS, URLS } from '../utils/constants.js'; + +// Deploy AppGateway from onchain tests +export async function runDeployAppGatewayTests( + addresses: ContractAddresses, + evmxChain: ChainConfig, + selectedChains: ChainConfig[] +): Promise { + console.log(`${COLORS.CYAN}Running all AppGateway onchain deployment tests...${COLORS.NC}`); + + if (!addresses.appGateway) { + throw new Error('Required addresses not found'); + } + + console.log(`${COLORS.CYAN}Validate all deployments from AppGateway${COLORS.NC}`); + + const appGatewayAbi = parseAbi([ + 'function contractValidation(uint32 chainSlug_) external' + ]); + + const hash = await sendTransaction( + addresses.appGateway, + 'contractValidation', + [selectedChains[0].chainId], + evmxChain, + appGatewayAbi + ); + + // Waiting for transaction finalized + console.log(`${COLORS.CYAN}Waiting for transaction finalized${COLORS.NC}`); + let attempt = 0; + let status = ''; + const interval = 1000; // 1 seconds + const maxAttempts = 60; // 60 seconds + const maxSeconds = interval * maxAttempts / 1000; + const endpoint = `${URLS.EVMX_API_BASE}/getDetailsByTxHash`; + + while (true) { + const response = await getTxDetails(endpoint, hash); + status = response?.response?.[0]?.status; + + if (status === 'COMPLETED') { + console.log(`Transaction completed as expected.`); + if (attempt > 0) process.stdout.write('\r\x1b[2K'); + break; + } + + if (attempt >= maxAttempts) { + console.log(); + throw new Error(`Could not validate transaction completion after ${maxSeconds} seconds. Current status: ${status}`); + } + + const elapsed = attempt * interval / 1000; + process.stdout.write(`\r${COLORS.YELLOW}Waiting for transaction completion:${COLORS.NC} ${elapsed}s / ${maxSeconds}s`); + + await new Promise(resolve => setTimeout(resolve, interval)); + attempt++; + } + + console.log(`${COLORS.GREEN}All trigger tests completed successfully!${COLORS.NC}`); +} + +export async function executeDeployTests( + chains: Record, +): Promise { + console.log(`${COLORS.GREEN}=== Running Deployment Tests ===${COLORS.NC}`); + + const addresses: ContractAddresses = { + appGateway: await deployAppGateway('DeploymentAppGateway', chains.evmxChain), + deployForwarders: [] as Address[], + deployOnchain: [] as Address[], + }; + + await depositFunds(addresses.appGateway, chains.arbMainnetChain, chains.evmxChain); + + // Selects two random chains out of the available ones + const randomChains = selectRandomChains(chains, 1); + + try { + await deployOnchain(randomChains[0].chainId, addresses.appGateway, chains.evmxChain); + + let chainAddresses = await fetchForwarderAndOnchainAddress('noPlugNoInititialize', randomChains[0].chainId, addresses.appGateway, chains.evmxChain); + addresses.deployForwarders!.push(chainAddresses.forwarder); + addresses.deployOnchain!.push(chainAddresses.onchain); + + chainAddresses = await fetchForwarderAndOnchainAddress('noPlugInitialize', randomChains[0].chainId, addresses.appGateway, chains.evmxChain); + addresses.deployForwarders!.push(chainAddresses.forwarder); + addresses.deployOnchain!.push(chainAddresses.onchain); + + chainAddresses = await fetchForwarderAndOnchainAddress('plugNoInitialize', randomChains[0].chainId, addresses.appGateway, chains.evmxChain); + addresses.deployForwarders!.push(chainAddresses.forwarder); + addresses.deployOnchain!.push(chainAddresses.onchain); + + chainAddresses = await fetchForwarderAndOnchainAddress('plugInitialize', randomChains[0].chainId, addresses.appGateway, chains.evmxChain); + addresses.deployForwarders!.push(chainAddresses.forwarder); + addresses.deployOnchain!.push(chainAddresses.onchain); + + chainAddresses = await fetchForwarderAndOnchainAddress('plugInitializeTwice', randomChains[0].chainId, addresses.appGateway, chains.evmxChain); + addresses.deployForwarders!.push(chainAddresses.forwarder); + addresses.deployOnchain!.push(chainAddresses.onchain); + + chainAddresses = await fetchForwarderAndOnchainAddress('plugNoInitInitialize', randomChains[0].chainId, addresses.appGateway, chains.evmxChain); + addresses.deployForwarders!.push(chainAddresses.forwarder); + addresses.deployOnchain!.push(chainAddresses.onchain); + + await runDeployAppGatewayTests(addresses, chains.evmxChain, randomChains); + } finally { + await withdrawFunds(addresses.appGateway, chains.arbMainnetChain, chains.evmxChain); + } +} diff --git a/script/tests/insufficient_tests.ts b/script/tests/insufficient_tests.ts index 6520f70..fc82ac9 100644 --- a/script/tests/insufficient_tests.ts +++ b/script/tests/insufficient_tests.ts @@ -1,8 +1,9 @@ import { parseAbi, type Address, type Hash } from 'viem'; import { deployAppGateway, deployOnchain, sendTransaction } from '../utils/deployer.js'; import { depositFunds, withdrawFunds } from '../utils/fees-manager.js'; +import { selectRandomChains } from '../utils/helpers.js'; import { ChainConfig } from '../utils/types.js'; -import { COLORS, CHAIN_IDS, AMOUNTS } from '../utils/constants.js'; +import { COLORS, AMOUNTS } from '../utils/constants.js'; // Insufficient fees tests export async function runInsufficientFeesTests( @@ -104,15 +105,22 @@ export async function runInsufficientFeesTests( } export async function executeInsufficientFeesTests( - evmxChain: ChainConfig, - arbChain: ChainConfig + chains: Record, ): Promise { console.log(`${COLORS.GREEN}=== Running Insufficient fees Tests ===${COLORS.NC}`); - const appGateway = await deployAppGateway('ReadAppGateway', evmxChain, 0n); + const appGateway = await deployAppGateway('ReadAppGateway', chains.evmxChain, 0n); - await depositFunds(appGateway, arbChain, evmxChain); - await deployOnchain(CHAIN_IDS.OP_SEP, appGateway, evmxChain); - await runInsufficientFeesTests('multichain', CHAIN_IDS.OP_SEP, appGateway, evmxChain); - await withdrawFunds(appGateway, arbChain, evmxChain); + await depositFunds(appGateway, chains.arbMainnetChain, chains.evmxChain); + + // Select one random chain for insufficient fees tests + const randomChains = selectRandomChains(chains, 1); + const selectedChain = randomChains[0]; + + try { + await deployOnchain(selectedChain.chainId, appGateway, chains.evmxChain); + await runInsufficientFeesTests('multichain', selectedChain.chainId, appGateway, chains.evmxChain); + } finally { + await withdrawFunds(appGateway, chains.arbMainnetChain, chains.evmxChain); + } } diff --git a/script/tests/read_tests.ts b/script/tests/read_tests.ts index d164f0e..c6fdfc7 100644 --- a/script/tests/read_tests.ts +++ b/script/tests/read_tests.ts @@ -1,9 +1,9 @@ -import { parseAbi, type Address } from 'viem'; +import { parseAbi } from 'viem'; import { deployAppGateway, deployOnchain, sendTransaction } from '../utils/deployer.js'; import { depositFunds, withdrawFunds } from '../utils/fees-manager.js'; -import { awaitEvents, fetchForwarderAndOnchainAddress } from '../utils/helpers.js'; +import { awaitEvents, fetchForwarderAndOnchainAddress, selectRandomChains } from '../utils/helpers.js'; import { ContractAddresses, ChainConfig } from '../utils/types.js'; -import { COLORS, CHAIN_IDS } from '../utils/constants.js'; +import { COLORS } from '../utils/constants.js'; // Read tests export async function runReadTests( @@ -18,7 +18,7 @@ export async function runReadTests( 'function triggerAltRead(address forwarder1, address forwarder2) external' ]); - if (!addresses.appGateway || !addresses.opForwarder || !addresses.arbForwarder) { + if (!addresses.appGateway || !addresses.chain2Forwarder || !addresses.chain1Forwarder) { throw new Error('Required addresses not found'); } @@ -32,7 +32,7 @@ export async function runReadTests( await sendTransaction( addresses.appGateway, 'triggerParallelRead', - [addresses.arbForwarder], + [addresses.chain1Forwarder], evmxChain, abi ); @@ -42,35 +42,41 @@ export async function runReadTests( await sendTransaction( addresses.appGateway, 'triggerAltRead', - [addresses.opForwarder, addresses.arbForwarder], + [addresses.chain2Forwarder, addresses.chain1Forwarder], evmxChain, abi ); - await awaitEvents(numberOfRequests * 2n, 'ValueRead(address,uint256,uint256)', addresses.appGateway, evmxChain); + await awaitEvents(numberOfRequests, 'ValueRead(address,uint256,uint256)', addresses.appGateway, evmxChain); } export async function executeReadTests( - evmxChain: ChainConfig, - arbChain: ChainConfig + chains: Record, ): Promise { console.log(`${COLORS.GREEN}=== Running Read Tests ===${COLORS.NC}`); const addresses: ContractAddresses = { - appGateway: await deployAppGateway('ReadAppGateway', evmxChain) + appGateway: await deployAppGateway('ReadAppGateway', chains.evmxChain) }; - await depositFunds(addresses.appGateway, arbChain, evmxChain); - await deployOnchain(CHAIN_IDS.ARB_SEP, addresses.appGateway, evmxChain); - await deployOnchain(CHAIN_IDS.OP_SEP, addresses.appGateway, evmxChain); + await depositFunds(addresses.appGateway, chains.arbMainnetChain, chains.evmxChain); + + // Selects two random chains out of the available ones + const randomChains = selectRandomChains(chains, 2); - const arbAddresses = await fetchForwarderAndOnchainAddress('multichain', CHAIN_IDS.ARB_SEP, addresses.appGateway, evmxChain); - addresses.arbForwarder = arbAddresses.forwarder; - addresses.arbOnchain = arbAddresses.onchain; + try { + await deployOnchain(randomChains[0].chainId, addresses.appGateway, chains.evmxChain); + await deployOnchain(randomChains[1].chainId, addresses.appGateway, chains.evmxChain); - const opAddresses = await fetchForwarderAndOnchainAddress('multichain', CHAIN_IDS.OP_SEP, addresses.appGateway, evmxChain); - addresses.opForwarder = opAddresses.forwarder; - addresses.opOnchain = opAddresses.onchain; + const chain1Addresses = await fetchForwarderAndOnchainAddress('multichain', randomChains[0].chainId, addresses.appGateway, chains.evmxChain); + addresses.chain1Forwarder = chain1Addresses.forwarder; + addresses.chain1Onchain = chain1Addresses.onchain; - await runReadTests(addresses, evmxChain); - await withdrawFunds(addresses.appGateway, arbChain, evmxChain); + const chain2Addresses = await fetchForwarderAndOnchainAddress('multichain', randomChains[1].chainId, addresses.appGateway, chains.evmxChain); + addresses.chain2Forwarder = chain2Addresses.forwarder; + addresses.chain2Onchain = chain2Addresses.onchain; + + await runReadTests(addresses, chains.evmxChain); + } finally { + await withdrawFunds(addresses.appGateway, chains.arbMainnetChain, chains.evmxChain); + } } diff --git a/script/tests/revert_tests.ts b/script/tests/revert_tests.ts index 7537839..ddc3df4 100644 --- a/script/tests/revert_tests.ts +++ b/script/tests/revert_tests.ts @@ -1,14 +1,15 @@ -import { parseAbi, type Address } from 'viem'; +import { parseAbi } from 'viem'; import { deployAppGateway, deployOnchain, sendTransaction } from '../utils/deployer.js'; import { depositFunds, withdrawFunds } from '../utils/fees-manager.js'; -import { fetchForwarderAndOnchainAddress, getTxDetails } from '../utils/helpers.js'; +import { fetchForwarderAndOnchainAddress, getTxDetails, selectRandomChains } from '../utils/helpers.js'; import { ContractAddresses, ChainConfig } from '../utils/types.js'; -import { COLORS, CHAIN_IDS, URLS } from '../utils/constants.js'; +import { COLORS, URLS } from '../utils/constants.js'; // Revert tests export async function runRevertTests( addresses: ContractAddresses, - evmxChain: ChainConfig + evmxChain: ChainConfig, + randomChainId: number ): Promise { const interval = 1000; // 1 seconds const maxAttempts = 60; // 60 seconds @@ -30,7 +31,7 @@ export async function runRevertTests( const hash1 = await sendTransaction( addresses.appGateway, 'testOnChainRevert', - [CHAIN_IDS.OP_SEP], + [randomChainId], evmxChain, abi ); @@ -71,7 +72,7 @@ export async function runRevertTests( const hash2 = await sendTransaction( addresses.appGateway, 'testCallbackRevertWrongInputArgs', - [CHAIN_IDS.OP_SEP], + [randomChainId], evmxChain, abi ); @@ -104,22 +105,29 @@ export async function runRevertTests( } export async function executeRevertTests( - evmxChain: ChainConfig, - arbChain: ChainConfig + chains: Record, ): Promise { console.log(`${COLORS.GREEN}=== Running Revert Tests ===${COLORS.NC}`); const addresses: ContractAddresses = { - appGateway: await deployAppGateway('RevertAppGateway', evmxChain) + appGateway: await deployAppGateway('RevertAppGateway', chains.evmxChain) }; - await depositFunds(addresses.appGateway, arbChain, evmxChain); - await deployOnchain(CHAIN_IDS.OP_SEP, addresses.appGateway, evmxChain); + await depositFunds(addresses.appGateway, chains.arbMainnetChain, chains.evmxChain); + + // Select one random chain for revert tests + const randomChains = selectRandomChains(chains, 1); + const selectedChain = randomChains[0]; - const opAddresses = await fetchForwarderAndOnchainAddress('counter', CHAIN_IDS.OP_SEP, addresses.appGateway, evmxChain); - addresses.opForwarder = opAddresses.forwarder; - addresses.opOnchain = opAddresses.onchain; + try { + await deployOnchain(selectedChain.chainId, addresses.appGateway, chains.evmxChain); - await runRevertTests(addresses, evmxChain); - await withdrawFunds(addresses.appGateway, arbChain, evmxChain); + const chainAddresses = await fetchForwarderAndOnchainAddress('counter', selectedChain.chainId, addresses.appGateway, chains.evmxChain); + addresses.chain2Forwarder = chainAddresses.forwarder; + addresses.chain2Onchain = chainAddresses.onchain; + + await runRevertTests(addresses, chains.evmxChain, selectedChain.chainId); + } finally { + await withdrawFunds(addresses.appGateway, chains.arbMainnetChain, chains.evmxChain); + } } diff --git a/script/tests/scheduler_tests.ts b/script/tests/scheduler_tests.ts index 58bf855..c16750b 100644 --- a/script/tests/scheduler_tests.ts +++ b/script/tests/scheduler_tests.ts @@ -78,14 +78,16 @@ export async function runSchedulerTests( } export async function executeSchedulerTests( - evmxChain: ChainConfig, - arbChain: ChainConfig + chains: Record, ): Promise { console.log(`${COLORS.GREEN}=== Running Scheduler Tests ===${COLORS.NC}`); - const appGateway = await deployAppGateway('ScheduleAppGateway', evmxChain); + const appGateway = await deployAppGateway('ScheduleAppGateway', chains.evmxChain); - await depositFunds(appGateway, arbChain, evmxChain); - await runSchedulerTests(appGateway, evmxChain); - await withdrawFunds(appGateway, arbChain, evmxChain); + await depositFunds(appGateway, chains.arbMainnetChain, chains.evmxChain); + try { + await runSchedulerTests(appGateway, chains.evmxChain); + } finally { + await withdrawFunds(appGateway, chains.arbMainnetChain, chains.evmxChain); + } } diff --git a/script/tests/trigger_tests.ts b/script/tests/trigger_tests.ts index 9dd219a..1f61f1e 100644 --- a/script/tests/trigger_tests.ts +++ b/script/tests/trigger_tests.ts @@ -1,37 +1,38 @@ -import { parseAbi, type Address } from 'viem'; +import { parseAbi } from 'viem'; import { deployAppGateway, deployOnchain, sendTransaction } from '../utils/deployer.js'; import { depositFunds, withdrawFunds } from '../utils/fees-manager.js'; -import { fetchForwarderAndOnchainAddress } from '../utils/helpers.js'; +import { fetchForwarderAndOnchainAddress, selectRandomChains } from '../utils/helpers.js'; import { ContractAddresses, ChainConfig } from '../utils/types.js'; -import { COLORS, CHAIN_IDS } from '../utils/constants.js'; +import { COLORS } from '../utils/constants.js'; // Trigger AppGateway from onchain tests export async function runTriggerAppGatewayOnchainTests( addresses: ContractAddresses, evmxChain: ChainConfig, - arbChain: ChainConfig, - opChain: ChainConfig + selectedChains: ChainConfig[] ): Promise { console.log(`${COLORS.CYAN}Running all trigger the AppGateway from onchain tests functions...${COLORS.NC}`); - if (!addresses.appGateway || !addresses.arbOnchain || !addresses.opOnchain) { + if (!addresses.appGateway || !addresses.chain1Onchain || !addresses.chain2Onchain) { throw new Error('Required addresses not found'); } const valueIncrease = BigInt(5); + const chain1 = selectedChains[0]; + const chain2 = selectedChains[1]; - // 1. Increase on AppGateway from Arbitrum Sepolia - console.log(`${COLORS.CYAN}Increase on AppGateway from Arbitrum Sepolia${COLORS.NC}`); + // 1. Increase on AppGateway from first selected chain + console.log(`${COLORS.CYAN}Increase on AppGateway from ${chain1.chainId}${COLORS.NC}`); const onchainAbi = parseAbi([ 'function increaseOnGateway(uint256) external' ]); await sendTransaction( - addresses.arbOnchain, + addresses.chain1Onchain, 'increaseOnGateway', [valueIncrease], - arbChain, + chain1, onchainAbi ); @@ -53,18 +54,18 @@ export async function runTriggerAppGatewayOnchainTests( throw new Error(`Got ${valueOnGateway} but expected at least ${valueIncrease}`); } - // 2. Update on Optimism Sepolia from AppGateway - console.log(`${COLORS.CYAN}Update on Optimism Sepolia from AppGateway${COLORS.NC}`); + // 2. Update on second selected chain from AppGateway + console.log(`${COLORS.CYAN}Update on ${chain2.chainId} from AppGateway${COLORS.NC}`); await sendTransaction( addresses.appGateway, 'updateOnchain', - [CHAIN_IDS.OP_SEP], + [chain2.chainId], evmxChain, appGatewayAbi ); - // Wait and verify value on Optimism + // Wait and verify value on second chain await new Promise(resolve => setTimeout(resolve, 10000)); // 10 second delay const onchainReadAbi = parseAbi([ @@ -72,66 +73,71 @@ export async function runTriggerAppGatewayOnchainTests( 'function propagateToAnother(uint32) external' ]); - const valueOnOp = await opChain.client.readContract({ - address: addresses.opOnchain, + const valueOnChain2 = await chain2.client.readContract({ + address: addresses.chain2Onchain, abi: onchainReadAbi, functionName: 'value' }) as bigint; - if (valueOnOp !== valueOnGateway) { - throw new Error(`Got ${valueOnOp} but expected ${valueOnGateway}`); + if (valueOnChain2 !== valueOnGateway) { + throw new Error(`Got ${valueOnChain2} but expected ${valueOnGateway}`); } - // 3. Propagate update from Optimism Sepolia to Arbitrum Sepolia - console.log(`${COLORS.CYAN}Propagate update to Optimism Sepolia to Arbitrum Sepolia from AppGateway${COLORS.NC}`); + // 3. Propagate update from second chain to first chain + console.log(`${COLORS.CYAN}Propagate update from ${chain2.chainId} to ${chain1.chainId} via AppGateway${COLORS.NC}`); await sendTransaction( - addresses.opOnchain, + addresses.chain2Onchain, 'propagateToAnother', - [CHAIN_IDS.ARB_SEP], - opChain, + [chain1.chainId], + chain2, onchainReadAbi ); - // Wait and verify value on Arbitrum + // Wait and verify value on first chain await new Promise(resolve => setTimeout(resolve, 10000)); // 10 second delay - const valueOnArb = await arbChain.client.readContract({ - address: addresses.arbOnchain, + const valueOnChain1 = await chain1.client.readContract({ + address: addresses.chain1Onchain, abi: onchainReadAbi, functionName: 'value' }) as bigint; - if (valueOnArb !== valueOnOp) { - throw new Error(`Got ${valueOnArb} but expected ${valueOnOp}`); + if (valueOnChain1 !== valueOnChain2) { + throw new Error(`Got ${valueOnChain1} but expected ${valueOnChain2}`); } console.log(`${COLORS.GREEN}All trigger tests completed successfully!${COLORS.NC}`); } export async function executeTriggerTests( - evmxChain: ChainConfig, - arbChain: ChainConfig, - opChain: ChainConfig + chains: Record, ): Promise { console.log(`${COLORS.GREEN}=== Running Trigger from onchain Tests ===${COLORS.NC}`); const addresses: ContractAddresses = { - appGateway: await deployAppGateway('OnchainTriggerAppGateway', evmxChain) + appGateway: await deployAppGateway('OnchainTriggerAppGateway', chains.evmxChain) }; - await depositFunds(addresses.appGateway, arbChain, evmxChain); - await deployOnchain(CHAIN_IDS.ARB_SEP, addresses.appGateway, evmxChain); - await deployOnchain(CHAIN_IDS.OP_SEP, addresses.appGateway, evmxChain); + await depositFunds(addresses.appGateway, chains.arbMainnetChain, chains.evmxChain); + + // Selects two random chains out of the available ones + const randomChains = selectRandomChains(chains, 2); - const arbAddresses = await fetchForwarderAndOnchainAddress('onchainToEVMx', CHAIN_IDS.ARB_SEP, addresses.appGateway, evmxChain); - addresses.arbForwarder = arbAddresses.forwarder; - addresses.arbOnchain = arbAddresses.onchain; + try { + await deployOnchain(randomChains[0].chainId, addresses.appGateway, chains.evmxChain); + await deployOnchain(randomChains[1].chainId, addresses.appGateway, chains.evmxChain); - const opAddresses = await fetchForwarderAndOnchainAddress('onchainToEVMx', CHAIN_IDS.OP_SEP, addresses.appGateway, evmxChain); - addresses.opForwarder = opAddresses.forwarder; - addresses.opOnchain = opAddresses.onchain; + const chain1Addresses = await fetchForwarderAndOnchainAddress('onchainToEVMx', randomChains[0].chainId, addresses.appGateway, chains.evmxChain); + addresses.chain1Forwarder = chain1Addresses.forwarder; + addresses.chain1Onchain = chain1Addresses.onchain; - await runTriggerAppGatewayOnchainTests(addresses, evmxChain, arbChain, opChain); - await withdrawFunds(addresses.appGateway, arbChain, evmxChain); + const chain2Addresses = await fetchForwarderAndOnchainAddress('onchainToEVMx', randomChains[1].chainId, addresses.appGateway, chains.evmxChain); + addresses.chain2Forwarder = chain2Addresses.forwarder; + addresses.chain2Onchain = chain2Addresses.onchain; + + await runTriggerAppGatewayOnchainTests(addresses, chains.evmxChain, randomChains); + } finally { + await withdrawFunds(addresses.appGateway, chains.arbMainnetChain, chains.evmxChain); + } } diff --git a/script/tests/upload_tests.ts b/script/tests/upload_tests.ts index 002450e..9f3210e 100644 --- a/script/tests/upload_tests.ts +++ b/script/tests/upload_tests.ts @@ -1,22 +1,22 @@ import { parseAbi, type Address } from 'viem'; import { deployAppGateway, deployContract, sendTransaction } from '../utils/deployer.js'; import { depositFunds, withdrawFunds } from '../utils/fees-manager.js'; -import { awaitEvents } from '../utils/helpers.js'; +import { awaitEvents, selectRandomChains } from '../utils/helpers.js'; import { ChainConfig } from '../utils/types.js'; -import { COLORS, CHAIN_IDS } from '../utils/constants.js'; +import { COLORS } from '../utils/constants.js'; // Upload to EVMx tests export async function runUploadTests( fileName: string, appGateway: Address, evmxChain: ChainConfig, - arbChain: ChainConfig + selectedChain: ChainConfig ): Promise { - // Deploy counter contract on Arbitrum Sepolia - const counterAddress = await deployContract(fileName, [], arbChain); + // Deploy counter contract on selected chain + const counterAddress = await deployContract(fileName, [], selectedChain); - // Increment counter on Arbitrum Sepolia - console.log(`${COLORS.CYAN}Increment counter on Arbitrum Sepolia${COLORS.NC}`); + // Increment counter on selected chain + console.log(`${COLORS.CYAN}Increment counter on ${selectedChain.chainId}${COLORS.NC}`); const counterAbi = parseAbi([ 'function increment() external' ]); @@ -25,7 +25,7 @@ export async function runUploadTests( counterAddress, 'increment', [], - arbChain, + selectedChain, counterAbi ); @@ -39,7 +39,7 @@ export async function runUploadTests( await sendTransaction( appGateway, 'uploadToEVMx', - [counterAddress, CHAIN_IDS.ARB_SEP], + [counterAddress, selectedChain.chainId], evmxChain, uploadAbi ); @@ -58,14 +58,21 @@ export async function runUploadTests( } export async function executeUploadTests( - evmxChain: ChainConfig, - arbChain: ChainConfig + chains: Record, ): Promise { console.log(`${COLORS.GREEN}=== Running Upload to EVMx Tests ===${COLORS.NC}`); - const appGateway = await deployAppGateway('UploadAppGateway', evmxChain); + const appGateway = await deployAppGateway('UploadAppGateway', chains.evmxChain); + + await depositFunds(appGateway, chains.arbMainnetChain, chains.evmxChain); + + // Select one random chain for upload tests + const randomChains = selectRandomChains(chains, 1); + const selectedChain = randomChains[0]; - await depositFunds(appGateway, arbChain, evmxChain); - await runUploadTests("Counter", appGateway, evmxChain, arbChain); - await withdrawFunds(appGateway, arbChain, evmxChain); + try { + await runUploadTests("Counter", appGateway, chains.evmxChain, selectedChain); + } finally { + await withdrawFunds(appGateway, chains.arbMainnetChain, chains.evmxChain); + } } diff --git a/script/tests/write_tests.ts b/script/tests/write_tests.ts index 68a5c29..c17478d 100644 --- a/script/tests/write_tests.ts +++ b/script/tests/write_tests.ts @@ -1,14 +1,15 @@ -import { parseAbi, type Address } from 'viem'; +import { parseAbi } from 'viem'; import { deployAppGateway, deployOnchain, sendTransaction } from '../utils/deployer.js'; import { depositFunds, withdrawFunds } from '../utils/fees-manager.js'; -import { awaitEvents, fetchForwarderAndOnchainAddress } from '../utils/helpers.js'; +import { awaitEvents, fetchForwarderAndOnchainAddress, selectRandomChains } from '../utils/helpers.js'; import { ContractAddresses, ChainConfig } from '../utils/types.js'; -import { COLORS, CHAIN_IDS } from '../utils/constants.js'; +import { COLORS } from '../utils/constants.js'; // Write tests export async function runWriteTests( addresses: ContractAddresses, - evmxChain: ChainConfig + evmxChain: ChainConfig, + randomChains: ChainConfig[] ): Promise { console.log(`${COLORS.CYAN}Running all write tests functions...${COLORS.NC}`); @@ -19,7 +20,7 @@ export async function runWriteTests( 'function triggerAltWrite(address forwarder1, address forwarder2) external' ]); - if (!addresses.appGateway || !addresses.opForwarder || !addresses.arbForwarder) { + if (!addresses.appGateway || !addresses.chain2Forwarder || !addresses.chain2Onchain || !addresses.chain1Forwarder || !addresses.chain1Onchain) { throw new Error('Required addresses not found'); } @@ -34,55 +35,68 @@ export async function runWriteTests( await sendTransaction( addresses.appGateway, 'triggerSequentialWrite', - [addresses.opForwarder], + [addresses.chain2Forwarder], evmxChain, abi ); - await awaitEvents(numberOfRequests, 'CounterIncreased(address,uint256,uint256)', addresses.appGateway, evmxChain); + await Promise.all([ + awaitEvents(numberOfRequests, 'CounterIncreasedTo(uint256)', addresses.chain2Onchain, randomChains[1]), + awaitEvents(numberOfRequests, 'CounterIncreased(address,uint256,uint256)', addresses.appGateway, evmxChain), + ]); // 2. Trigger Parallel Write await sendTransaction( addresses.appGateway, 'triggerParallelWrite', - [addresses.arbForwarder], + [addresses.chain1Forwarder], evmxChain, abi ); - await awaitEvents(numberOfRequests * 2n, 'CounterIncreased(address,uint256,uint256)', addresses.appGateway, evmxChain); + await Promise.all([ + awaitEvents(numberOfRequests, 'CounterIncreasedTo(uint256)', addresses.chain1Onchain, randomChains[0]), + awaitEvents(numberOfRequests, 'CounterIncreased(address,uint256,uint256)', addresses.appGateway, evmxChain), + ]); // 3. Trigger Alternating Write await sendTransaction( addresses.appGateway, 'triggerAltWrite', - [addresses.opForwarder, addresses.arbForwarder], + [addresses.chain2Forwarder, addresses.chain1Forwarder], evmxChain, abi ); - await awaitEvents(numberOfRequests * 3n, 'CounterIncreased(address,uint256,uint256)', addresses.appGateway, evmxChain); + await Promise.all([ + awaitEvents(numberOfRequests / 2n, 'CounterIncreasedTo(uint256)', addresses.chain1Onchain, randomChains[0]), + awaitEvents(numberOfRequests / 2n, 'CounterIncreasedTo(uint256)', addresses.chain2Onchain, randomChains[1]), + awaitEvents(numberOfRequests, 'CounterIncreased(address,uint256,uint256)', addresses.appGateway, evmxChain), + ]) } export async function executeWriteTests( - evmxChain: ChainConfig, - arbChain: ChainConfig + chains: Record, ): Promise { console.log(`${COLORS.GREEN}=== Running Write Tests ===${COLORS.NC}`); const addresses: ContractAddresses = { - appGateway: await deployAppGateway('WriteAppGateway', evmxChain) + appGateway: await deployAppGateway('WriteAppGateway', chains.evmxChain) }; - await depositFunds(addresses.appGateway, arbChain, evmxChain); - await deployOnchain(CHAIN_IDS.ARB_SEP, addresses.appGateway, evmxChain); - await deployOnchain(CHAIN_IDS.OP_SEP, addresses.appGateway, evmxChain); - - const arbAddresses = await fetchForwarderAndOnchainAddress('multichain', CHAIN_IDS.ARB_SEP, addresses.appGateway, evmxChain); - addresses.arbForwarder = arbAddresses.forwarder; - addresses.arbOnchain = arbAddresses.onchain; + await depositFunds(addresses.appGateway, chains.arbMainnetChain, chains.evmxChain); - const opAddresses = await fetchForwarderAndOnchainAddress('multichain', CHAIN_IDS.OP_SEP, addresses.appGateway, evmxChain); - addresses.opForwarder = opAddresses.forwarder; - addresses.opOnchain = opAddresses.onchain; + // Selects two random chains out of the available ones + const randomChains = selectRandomChains(chains, 2); - await runWriteTests(addresses, evmxChain); - await withdrawFunds(addresses.appGateway, arbChain, evmxChain); + try { + await deployOnchain(randomChains[0].chainId, addresses.appGateway, chains.evmxChain); + await deployOnchain(randomChains[1].chainId, addresses.appGateway, chains.evmxChain); + const chain1Addresses = await fetchForwarderAndOnchainAddress('multichain', randomChains[0].chainId, addresses.appGateway, chains.evmxChain); + addresses.chain1Forwarder = chain1Addresses.forwarder; + addresses.chain1Onchain = chain1Addresses.onchain; + const chain2Addresses = await fetchForwarderAndOnchainAddress('multichain', randomChains[1].chainId, addresses.appGateway, chains.evmxChain); + addresses.chain2Forwarder = chain2Addresses.forwarder; + addresses.chain2Onchain = chain2Addresses.onchain; + await runWriteTests(addresses, chains.evmxChain, randomChains); + } finally { + await withdrawFunds(addresses.appGateway, chains.arbMainnetChain, chains.evmxChain); + } } diff --git a/script/utils/deployer.ts b/script/utils/deployer.ts index a1c43e8..e875e3e 100644 --- a/script/utils/deployer.ts +++ b/script/utils/deployer.ts @@ -91,8 +91,9 @@ export async function sendTransaction( value: value }); + const timestamp = new Date().toISOString(); await new Promise(resolve => setTimeout(resolve, 2000)); - console.log(`${COLORS.GREEN}Tx Hash:${COLORS.NC} ${getExplorerUrl(hash, chainConfig)}`); + console.log(`${timestamp} ${COLORS.GREEN}Tx Hash:${COLORS.NC} ${getExplorerUrl(hash, chainConfig)}`); return hash; } catch (error) { diff --git a/script/utils/fees-manager.ts b/script/utils/fees-manager.ts index cc9d336..92c955b 100644 --- a/script/utils/fees-manager.ts +++ b/script/utils/fees-manager.ts @@ -1,7 +1,7 @@ // fees/manager.ts -import { parseAbi, formatEther, type Address, parseEther } from 'viem'; +import { parseAbi, formatEther, type Address } from 'viem'; import { ChainConfig } from './types.js'; -import { COLORS, AMOUNTS, CHAIN_IDS } from './constants.js'; +import { COLORS, AMOUNTS } from './constants.js'; import { sendTransaction } from './deployer.js'; // Check available fees @@ -27,6 +27,7 @@ export async function checkAvailableFees( }) as bigint; if (availableFees > 0n) { + process.stdout.write('\r\x1b[2K'); console.log(`Funds available: ${formatEther(availableFees)} Credits - ${availableFees} wei`); await new Promise(resolve => setTimeout(resolve, 1000)); return availableFees; diff --git a/script/utils/helpers.ts b/script/utils/helpers.ts index fa5b1a3..d374d14 100644 --- a/script/utils/helpers.ts +++ b/script/utils/helpers.ts @@ -88,40 +88,43 @@ export async function fetchForwarderAndOnchainAddress( export async function awaitEvents( expectedNewEvents: bigint, _eventSignature: string, - appGateway: Address, - evmxChain: ChainConfig, + contract: Address, + chain: ChainConfig, timeout: number = 300 ): Promise { console.log(`${COLORS.CYAN}Waiting logs for ${expectedNewEvents} new events (up to ${timeout} seconds)...${COLORS.NC}`); - - const interval: number = 2000; // 2 seconds - let elapsed: number = 0; + const interval: number = 1000; // 1 seconds + const startTimestamp = Date.now(); + const timeoutMs = timeout * 1000; let eventCount = 0n; + let previousEventCount = 0n; - while (elapsed <= timeout * 1000) { + const blockNumber = await chain.client.getBlockNumber(); + while (Date.now() <= startTimestamp + timeoutMs) { try { - const logs = await evmxChain.client.getLogs({ - address: appGateway, - fromBlock: 'earliest', + const logs = await chain.client.getLogs({ + address: contract, + fromBlock: blockNumber, toBlock: 'latest' }); - - eventCount = logs.length; + eventCount = BigInt(logs.length); + + // Check if we have new events and log them with timestamp + if (eventCount > previousEventCount) { + const newEventsFound = eventCount - previousEventCount; + const timestamp = new Date().toISOString(); + console.log(`${timestamp} Found ${newEventsFound} new event(s) for ${_eventSignature} on ${chain.chainId}: ${eventCount}/${expectedNewEvents} events.`); + previousEventCount = eventCount; + } if (eventCount >= expectedNewEvents) { - process.stdout.write(`\r`); - console.log(`\nTotal events on EVMx: ${eventCount} reached (expected ${expectedNewEvents})`); break; } - process.stdout.write(`\rWaiting for ${expectedNewEvents} logs on EVMx: ${eventCount}/${expectedNewEvents} (Elapsed: ${elapsed / 1000}/${timeout} sec)`); - await new Promise(resolve => setTimeout(resolve, interval)); - elapsed += interval; } catch (error) { console.error('Error fetching logs:', error); await new Promise(resolve => setTimeout(resolve, interval)); - elapsed += interval; } } @@ -141,8 +144,19 @@ export async function getTxDetails(endpoint: string, txHash: string): Promise, + count: number +): ChainConfig[] { + const { evmxChain, ...rest } = chains; + const available = Object.values(rest); + + // Shuffle array using Fisher-Yates algorithm + for (let i = available.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [available[i], available[j]] = [available[j], available[i]]; + } + + return available.slice(0, count); } diff --git a/script/utils/types.ts b/script/utils/types.ts index c218537..a47bb79 100644 --- a/script/utils/types.ts +++ b/script/utils/types.ts @@ -10,10 +10,12 @@ export interface ChainConfig { export interface ContractAddresses { appGateway: Address; - arbForwarder?: Address; - arbOnchain?: Address; - opForwarder?: Address; - opOnchain?: Address; + chain1Forwarder?: Address; + chain1Onchain?: Address; + chain2Forwarder?: Address; + chain2Onchain?: Address; + deployForwarders?: Address[]; + deployOnchain?: Address[]; } export interface TestFlags { @@ -24,5 +26,6 @@ export interface TestFlags { scheduler: boolean; insufficient: boolean; revert: boolean; + deployment: boolean; all: boolean; }