diff --git a/.changeset/fast-cobras-sell.md b/.changeset/fast-cobras-sell.md new file mode 100644 index 0000000000..c5b085edea --- /dev/null +++ b/.changeset/fast-cobras-sell.md @@ -0,0 +1,5 @@ +--- +'@chainlink/layer2-sequencer-health-adapter': minor +--- + +Added support for Ink, Mantle, Unichain and Soneium diff --git a/packages/sources/layer2-sequencer-health/README.md b/packages/sources/layer2-sequencer-health/README.md index 6a943fab10..685ce2faa1 100644 --- a/packages/sources/layer2-sequencer-health/README.md +++ b/packages/sources/layer2-sequencer-health/README.md @@ -39,6 +39,22 @@ Adapter that checks the Layer 2 Sequencer status | | `ZKSYNC_HEALTH_ENDPOINT` | zkSync Health Endpoint | | | | | `ZKSYNC_CHAIN_ID` | The chain id to connect to zkSync | | 324 | | | `ZKSYNC_DELTA` | Maximum time in milliseconds from last seen block to consider zkSync sequencer healthy | | 120000 (2 min) | +| | `INK_RPC_ENDPOINT` | Ink RPC Endpoint | | https://rpc-gel.inkonchain.com | +| | `INK_HEALTH_ENDPOINT` | Ink Health Endpoint | | | +| | `INK_CHAIN_ID` | The chain id to connect to Ink | | 57073 | +| | `INK_DELTA` | Maximum time in milliseconds from last seen block to consider Ink sequencer healthy | | 120000 (2 min) | +| | `MANTLE_RPC_ENDPOINT` | Mantle RPC Endpoint | | https://rpc.mantle.xyz | +| | `MANTLE_HEALTH_ENDPOINT` | Mantle Health Endpoint | | | +| | `MANTLE_CHAIN_ID` | The chain id to connect to Mantle | | 5000 | +| | `MANTLE_DELTA` | Maximum time in milliseconds from last seen block to consider Mantle sequencer healthy | | 120000 (2 min) | +| | `UNICHAIN_RPC_ENDPOINT` | Unichain RPC Endpoint | | https://mainnet.unichain.org | +| | `UNICHAIN_HEALTH_ENDPOINT` | Unichain Health Endpoint | | | +| | `UNICHAIN_CHAIN_ID` | The chain id to connect to Unichain | | 130 | +| | `UNICHAIN_DELTA` | Maximum time in milliseconds from last seen block to consider Unichain sequencer healthy | | 120000 (2 min) | +| | `SONEIUM_RPC_ENDPOINT` | Soneium RPC Endpoint | | https://rpc.soneium.org | +| | `SONEIUM_HEALTH_ENDPOINT` | Soneium Health Endpoint | | | +| | `SONEIUM_CHAIN_ID` | The chain id to connect to Soneium | | 1868 | +| | `SONEIUM_DELTA` | Maximum time in milliseconds from last seen block to consider Soneium sequencer healthy | | 120000 (2 min) | For the adapter to be useful on the desired network, at least one endpoint (RPC or HEALTH) needs to provided @@ -46,9 +62,9 @@ For the adapter to be useful on the desired network, at least one endpoint (RPC ### Input Parameters -| Required? | Name | Description | Options | Defaults to | -| :-------: | :-----: | :----------------------: | :-------------------------------------------------------------------------------: | :---------: | -| ✅ | network | Layer 2 Network to check | `arbitrum`, `optimism`, `base`, `linea`, `metis`, `scroll`, `starkware`, `zksync` | | +| Required? | Name | Description | Options | Defaults to | +| :-------: | :-----: | :----------------------: | :-----------------------------------------------------------------------------------------------------------------------: | :---------: | +| ✅ | network | Layer 2 Network to check | `arbitrum`, `optimism`, `base`, `linea`, `metis`, `scroll`, `starkware`, `zksync`, `ink`, `mantle`, `unichain`, `soneium` | | --- diff --git a/packages/sources/layer2-sequencer-health/schemas/env.json b/packages/sources/layer2-sequencer-health/schemas/env.json index abe0a73f32..825b50c626 100644 --- a/packages/sources/layer2-sequencer-health/schemas/env.json +++ b/packages/sources/layer2-sequencer-health/schemas/env.json @@ -149,6 +149,62 @@ "description": "The blockchain id to connect to", "type": "string", "default": "324" + }, + "INK_RPC_ENDPOINT": { + "type": "string", + "default": "https://rpc-gel.inkonchain.com" + }, + "INK_HEALTH_ENDPOINT": { + "type": "string", + "default": "" + }, + "INK_CHAIN_ID": { + "required": false, + "description": "The blockchain id to connect to", + "type": "string", + "default": "57073" + }, + "MANTLE_RPC_ENDPOINT": { + "type": "string", + "default": "https://rpc.mantle.xyz" + }, + "MANTLE_HEALTH_ENDPOINT": { + "type": "string", + "default": "" + }, + "MANTLE_CHAIN_ID": { + "required": false, + "description": "The blockchain id to connect to", + "type": "string", + "default": "5000" + }, + "UNICHAIN_RPC_ENDPOINT": { + "type": "string", + "default": "https://mainnet.unichain.org" + }, + "UNICHAIN_HEALTH_ENDPOINT": { + "type": "string", + "default": "" + }, + "UNICHAIN_CHAIN_ID": { + "required": false, + "description": "The blockchain id to connect to", + "type": "string", + "default": "130" + }, + "SONEIUM_RPC_ENDPOINT": { + "type": "string", + "default": "https://rpc.soneium.org" + }, + "SONEIUM_HEALTH_ENDPOINT": { + "type": "string", + "default": "" + }, + "SONEIUM_CHAIN_ID": { + "required": false, + "description": "The blockchain id to connect to", + "type": "string", + "default": "1868" } }, "allOf": [ diff --git a/packages/sources/layer2-sequencer-health/src/config/index.ts b/packages/sources/layer2-sequencer-health/src/config/index.ts index cb89e6098f..975c7a5fb5 100644 --- a/packages/sources/layer2-sequencer-health/src/config/index.ts +++ b/packages/sources/layer2-sequencer-health/src/config/index.ts @@ -31,6 +31,10 @@ export const ENV_LINEA_RPC_ENDPOINT = 'LINEA_RPC_ENDPOINT' export const ENV_METIS_RPC_ENDPOINT = 'METIS_RPC_ENDPOINT' export const ENV_SCROLL_RPC_ENDPOINT = 'SCROLL_RPC_ENDPOINT' export const ENV_ZKSYNC_RPC_ENDPOINT = 'ZKSYNC_RPC_ENDPOINT' +export const ENV_INK_RPC_ENDPOINT = 'INK_RPC_ENDPOINT' +export const ENV_MANTLE_RPC_ENDPOINT = 'MANTLE_RPC_ENDPOINT' +export const ENV_UNICHAIN_RPC_ENDPOINT = 'UNICHAIN_RPC_ENDPOINT' +export const ENV_SONEIUM_RPC_ENDPOINT = 'SONEIUM_RPC_ENDPOINT' export const ENV_ARBITRUM_CHAIN_ID = 'ARBITRUM_CHAIN_ID' export const ENV_OPTIMISM_CHAIN_ID = 'OPTIMISM_CHAIN_ID' @@ -39,6 +43,10 @@ export const ENV_LINEA_CHAIN_ID = 'BASE_CHAIN_ID' export const ENV_METIS_CHAIN_ID = 'METIS_CHAIN_ID' export const ENV_SCROLL_CHAIN_ID = 'SCROLL_CHAIN_ID' export const ENV_ZKSYNC_CHAIN_ID = 'ZKSYNC_CHAIN_ID' +export const ENV_INK_CHAIN_ID = 'INK_CHAIN_ID' +export const ENV_MANTLE_CHAIN_ID = 'MANTLE_CHAIN_ID' +export const ENV_UNICHAIN_CHAIN_ID = 'UNICHAIN_CHAIN_ID' +export const ENV_SONEIUM_CHAIN_ID = 'SONEIUM_CHAIN_ID' export const DEFAULT_ARBITRUM_CHAIN_ID = '42161' export const DEFAULT_OPTIMISM_CHAIN_ID = '10' @@ -47,6 +55,10 @@ export const DEFAULT_LINEA_CHAIN_ID = '59144' export const DEFAULT_METIS_CHAIN_ID = '1088' export const DEFAULT_SCROLL_CHAIN_ID = '534352' export const DEFAULT_ZKSYNC_CHAIN_ID = '324' +export const DEFAULT_INK_CHAIN_ID = '57073' +export const DEFAULT_MANTLE_CHAIN_ID = '5000' +export const DEFAULT_UNICHAIN_CHAIN_ID = '130' +export const DEFAULT_SONEIUM_CHAIN_ID = '1868' export enum Networks { Arbitrum = 'arbitrum', @@ -57,6 +69,10 @@ export enum Networks { Scroll = 'scroll', Starkware = 'starkware', zkSync = 'zksync', + Ink = 'ink', + Mantle = 'mantle', + Unichain = 'unichain', + Soneium = 'soneium', } export type EVMNetworks = Exclude @@ -68,6 +84,10 @@ const DEFAULT_LINEA_RPC_ENDPOINT = 'https://rpc.linea.build' const DEFAULT_METIS_RPC_ENDPOINT = 'https://andromeda.metis.io/?owner=1088' const DEFAULT_SCROLL_RPC_ENDPOINT = 'https://rpc.scroll.io' const DEFAULT_ZKSYNC_RPC_ENDPOINT = 'https://mainnet.era.zksync.io' +const DEFAULT_INK_RPC_ENDPOINT = 'https://rpc-gel.inkonchain.com' +const DEFAULT_MANTLE_RPC_ENDPOINT = 'https://rpc.mantle.xyz' +const DEFAULT_UNICHAIN_RPC_ENDPOINT = 'https://mainnet.unichain.org' +const DEFAULT_SONEIUM_RPC_ENDPOINT = 'https://rpc.soneium.org' export const RPC_ENDPOINTS: Record = { [Networks.Arbitrum]: util.getEnv(ENV_ARBITRUM_RPC_ENDPOINT) || DEFAULT_ARBITRUM_RPC_ENDPOINT, @@ -77,6 +97,10 @@ export const RPC_ENDPOINTS: Record = { [Networks.Metis]: util.getEnv(ENV_METIS_RPC_ENDPOINT) || DEFAULT_METIS_RPC_ENDPOINT, [Networks.Scroll]: util.getEnv(ENV_SCROLL_RPC_ENDPOINT) || DEFAULT_SCROLL_RPC_ENDPOINT, [Networks.zkSync]: util.getEnv(ENV_ZKSYNC_RPC_ENDPOINT) || DEFAULT_ZKSYNC_RPC_ENDPOINT, + [Networks.Ink]: util.getEnv(ENV_INK_RPC_ENDPOINT) || DEFAULT_INK_RPC_ENDPOINT, + [Networks.Mantle]: util.getEnv(ENV_MANTLE_RPC_ENDPOINT) || DEFAULT_MANTLE_RPC_ENDPOINT, + [Networks.Unichain]: util.getEnv(ENV_UNICHAIN_RPC_ENDPOINT) || DEFAULT_UNICHAIN_RPC_ENDPOINT, + [Networks.Soneium]: util.getEnv(ENV_SONEIUM_RPC_ENDPOINT) || DEFAULT_SONEIUM_RPC_ENDPOINT, } export const CHAIN_IDS: Record = { @@ -101,6 +125,18 @@ export const CHAIN_IDS: Record = { [Networks.zkSync]: parseInt(util.getEnv(ENV_ZKSYNC_CHAIN_ID) || DEFAULT_ZKSYNC_CHAIN_ID) || util.getEnv(ENV_ZKSYNC_CHAIN_ID), + [Networks.Ink]: + parseInt(util.getEnv(ENV_INK_CHAIN_ID) || DEFAULT_INK_CHAIN_ID) || + util.getEnv(ENV_INK_CHAIN_ID), + [Networks.Mantle]: + parseInt(util.getEnv(ENV_MANTLE_CHAIN_ID) || DEFAULT_MANTLE_CHAIN_ID) || + util.getEnv(ENV_MANTLE_CHAIN_ID), + [Networks.Unichain]: + parseInt(util.getEnv(ENV_UNICHAIN_CHAIN_ID) || DEFAULT_UNICHAIN_CHAIN_ID) || + util.getEnv(ENV_UNICHAIN_CHAIN_ID), + [Networks.Soneium]: + parseInt(util.getEnv(ENV_SONEIUM_CHAIN_ID) || DEFAULT_SONEIUM_CHAIN_ID) || + util.getEnv(ENV_SONEIUM_CHAIN_ID), } export const CHAIN_DELTA: Record = { @@ -112,6 +148,10 @@ export const CHAIN_DELTA: Record = { [Networks.Scroll]: Number(util.getEnv('SCROLL_DELTA')) || DEFAULT_DELTA_TIME, [Networks.Starkware]: Number(util.getEnv('STARKWARE_DELTA')) || DEFAULT_DELTA_TIME, [Networks.zkSync]: Number(util.getEnv('ZKSYNC_DELTA')) || DEFAULT_DELTA_TIME, + [Networks.Ink]: Number(util.getEnv('INK_DELTA')) || DEFAULT_DELTA_TIME, + [Networks.Mantle]: Number(util.getEnv('MANTLE_DELTA')) || DEFAULT_DELTA_TIME, + [Networks.Unichain]: Number(util.getEnv('UNICHAIN_DELTA')) || DEFAULT_DELTA_TIME, + [Networks.Soneium]: Number(util.getEnv('SONEIUM_DELTA')) || DEFAULT_DELTA_TIME, } const DEFAULT_METIS_HEALTH_ENDPOINT = 'https://andromeda-healthy.metisdevops.link/health' @@ -167,6 +207,26 @@ export const HEALTH_ENDPOINTS: HeathEndpoints = { responsePath: [], processResponse: () => undefined, }, + [Networks.Ink]: { + endpoint: util.getEnv('INK_HEALTH_ENDPOINT'), + responsePath: [], + processResponse: () => undefined, + }, + [Networks.Mantle]: { + endpoint: util.getEnv('MANTLE_HEALTH_ENDPOINT'), + responsePath: [], + processResponse: () => undefined, + }, + [Networks.Unichain]: { + endpoint: util.getEnv('UNICHAIN_HEALTH_ENDPOINT'), + responsePath: [], + processResponse: () => undefined, + }, + [Networks.Soneium]: { + endpoint: util.getEnv('SONEIUM_HEALTH_ENDPOINT'), + responsePath: [], + processResponse: () => undefined, + }, } const defaultProcessResponse = (data: unknown, network: Networks) => diff --git a/packages/sources/layer2-sequencer-health/src/endpoint/health.ts b/packages/sources/layer2-sequencer-health/src/endpoint/health.ts index f6e082fa55..943fe7f28d 100644 --- a/packages/sources/layer2-sequencer-health/src/endpoint/health.ts +++ b/packages/sources/layer2-sequencer-health/src/endpoint/health.ts @@ -25,6 +25,10 @@ const defaultRequireTxFailure = { [Networks.Scroll]: false, [Networks.Starkware]: true, [Networks.zkSync]: false, + [Networks.Ink]: false, + [Networks.Mantle]: false, + [Networks.Unichain]: false, + [Networks.Soneium]: false, } export type TInputParameters = { @@ -43,6 +47,10 @@ export const inputParameters: InputParameters = { Networks.Scroll, Networks.Starkware, Networks.zkSync, + Networks.Ink, + Networks.Mantle, + Networks.Unichain, + Networks.Soneium, ], }, requireTxFailure: { diff --git a/packages/sources/layer2-sequencer-health/src/evm.ts b/packages/sources/layer2-sequencer-health/src/evm.ts index 365f077edd..60f0328862 100644 --- a/packages/sources/layer2-sequencer-health/src/evm.ts +++ b/packages/sources/layer2-sequencer-health/src/evm.ts @@ -69,6 +69,30 @@ export const sendEVMDummyTransaction = async ( gasPrice: 0, to: wallet.address, }, + [Networks.Ink]: { + value: 0, + gasLimit: 0, + gasPrice: 0, + to: wallet.address, + }, + [Networks.Mantle]: { + value: 0, + gasLimit: 0, + gasPrice: 0, + to: wallet.address, + }, + [Networks.Unichain]: { + value: 0, + gasLimit: 0, + gasPrice: 0, + to: wallet.address, + }, + [Networks.Soneium]: { + value: 0, + gasLimit: 0, + gasPrice: 0, + to: wallet.address, + }, } await race({ timeout, @@ -106,6 +130,22 @@ const lastSeenBlock: Record = block: 0, timestamp: 0, }, + [Networks.Ink]: { + block: 0, + timestamp: 0, + }, + [Networks.Mantle]: { + block: 0, + timestamp: 0, + }, + [Networks.Unichain]: { + block: 0, + timestamp: 0, + }, + [Networks.Soneium]: { + block: 0, + timestamp: 0, + }, } export const checkOptimisticRollupBlockHeight = ( diff --git a/packages/sources/layer2-sequencer-health/src/network.ts b/packages/sources/layer2-sequencer-health/src/network.ts index 4b3a86b435..8aeac23090 100644 --- a/packages/sources/layer2-sequencer-health/src/network.ts +++ b/packages/sources/layer2-sequencer-health/src/network.ts @@ -28,6 +28,10 @@ const sequencerOnlineErrors: Record = { // the network detects a transaction sent with 0 gas. [Networks.Starkware]: ['Contract not found', 'Known(OutOfRangeFee)'], [Networks.zkSync]: ['max fee per gas less than block base fee'], + [Networks.Ink]: ['intrinsic gas too low: gas 0'], + [Networks.Mantle]: ['failed to forward tx to sequencer', 'intrinsic gas too low'], + [Networks.Unichain]: ['intrinsic gas too low: gas 0'], + [Networks.Soneium]: ['intrinsic gas too low: gas 0'], } export interface NetworkHealthCheck { @@ -94,6 +98,10 @@ const isExpectedErrorMessage = (network: Networks, error: Error) => { [Networks.Scroll]: ['error', 'error', 'message'], [Networks.Starkware]: ['message'], [Networks.zkSync]: ['error', 'message'], + [Networks.Ink]: ['error', 'message'], + [Networks.Mantle]: ['error', 'message'], + [Networks.Unichain]: ['error', 'message'], + [Networks.Soneium]: ['error', 'message'], } return (Requester.getResult(error, paths[network]) as string) || '' } diff --git a/packages/sources/layer2-sequencer-health/test/integration/__snapshots__/onchainFailKnown.test.ts.snap b/packages/sources/layer2-sequencer-health/test/integration/__snapshots__/onchainFailKnown.test.ts.snap index fe1e353d66..7035ba4ee0 100644 --- a/packages/sources/layer2-sequencer-health/test/integration/__snapshots__/onchainFailKnown.test.ts.snap +++ b/packages/sources/layer2-sequencer-health/test/integration/__snapshots__/onchainFailKnown.test.ts.snap @@ -66,6 +66,50 @@ exports[`execute base network should return success when transaction submission } `; +exports[`execute ink network should return failure if tx not required 1`] = ` +{ + "data": { + "result": 1, + }, + "jobRunID": "1", + "result": 1, + "statusCode": 200, +} +`; + +exports[`execute ink network should return success when transaction submission is known 1`] = ` +{ + "data": { + "result": 0, + }, + "jobRunID": "1", + "result": 0, + "statusCode": 200, +} +`; + +exports[`execute mantle network should return failure if tx not required 1`] = ` +{ + "data": { + "result": 1, + }, + "jobRunID": "1", + "result": 1, + "statusCode": 200, +} +`; + +exports[`execute mantle network should return success when transaction submission is known 1`] = ` +{ + "data": { + "result": 0, + }, + "jobRunID": "1", + "result": 0, + "statusCode": 200, +} +`; + exports[`execute metis network should return failure if tx not required 1`] = ` { "data": { @@ -132,6 +176,50 @@ exports[`execute scroll network should return success when transaction submissio } `; +exports[`execute soneium network should return failure if tx not required 1`] = ` +{ + "data": { + "result": 1, + }, + "jobRunID": "1", + "result": 1, + "statusCode": 200, +} +`; + +exports[`execute soneium network should return success when transaction submission is known 1`] = ` +{ + "data": { + "result": 0, + }, + "jobRunID": "1", + "result": 0, + "statusCode": 200, +} +`; + +exports[`execute unichain network should return failure if tx not required 1`] = ` +{ + "data": { + "result": 1, + }, + "jobRunID": "1", + "result": 1, + "statusCode": 200, +} +`; + +exports[`execute unichain network should return success when transaction submission is known 1`] = ` +{ + "data": { + "result": 0, + }, + "jobRunID": "1", + "result": 0, + "statusCode": 200, +} +`; + exports[`execute zksync network should return failure if tx not required 1`] = ` { "data": { diff --git a/packages/sources/layer2-sequencer-health/test/integration/__snapshots__/onchainFailUnknown.test.ts.snap b/packages/sources/layer2-sequencer-health/test/integration/__snapshots__/onchainFailUnknown.test.ts.snap index f6f0a83e9d..4bf90bf612 100644 --- a/packages/sources/layer2-sequencer-health/test/integration/__snapshots__/onchainFailUnknown.test.ts.snap +++ b/packages/sources/layer2-sequencer-health/test/integration/__snapshots__/onchainFailUnknown.test.ts.snap @@ -22,6 +22,28 @@ exports[`execute base network should return failure when transaction submission } `; +exports[`execute ink network should return failure when transaction submission is unknown 1`] = ` +{ + "data": { + "result": 1, + }, + "jobRunID": "1", + "result": 1, + "statusCode": 200, +} +`; + +exports[`execute mantle network should return failure when transaction submission is unknown 1`] = ` +{ + "data": { + "result": 1, + }, + "jobRunID": "1", + "result": 1, + "statusCode": 200, +} +`; + exports[`execute metis network should return failure when transaction submission is unknown 1`] = ` { "data": { @@ -43,3 +65,25 @@ exports[`execute optimism network should return failure when transaction submiss "statusCode": 200, } `; + +exports[`execute soneium network should return failure when transaction submission is unknown 1`] = ` +{ + "data": { + "result": 1, + }, + "jobRunID": "1", + "result": 1, + "statusCode": 200, +} +`; + +exports[`execute unichain network should return failure when transaction submission is unknown 1`] = ` +{ + "data": { + "result": 1, + }, + "jobRunID": "1", + "result": 1, + "statusCode": 200, +} +`; diff --git a/packages/sources/layer2-sequencer-health/test/integration/__snapshots__/onchainSuccess.test.ts.snap b/packages/sources/layer2-sequencer-health/test/integration/__snapshots__/onchainSuccess.test.ts.snap index 7421a9e0d0..d57ebc2737 100644 --- a/packages/sources/layer2-sequencer-health/test/integration/__snapshots__/onchainSuccess.test.ts.snap +++ b/packages/sources/layer2-sequencer-health/test/integration/__snapshots__/onchainSuccess.test.ts.snap @@ -99,6 +99,72 @@ exports[`execute base network should return transaction submission is successful } `; +exports[`execute ink network should return failure if tx not required even if it would be successful 1`] = ` +{ + "data": { + "result": 1, + }, + "jobRunID": "1", + "result": 1, + "statusCode": 200, +} +`; + +exports[`execute ink network should return success when all methods succeed 1`] = ` +{ + "data": { + "result": 0, + }, + "jobRunID": "1", + "result": 0, + "statusCode": 200, +} +`; + +exports[`execute ink network should return transaction submission is successful 1`] = ` +{ + "data": { + "result": 0, + }, + "jobRunID": "1", + "result": 0, + "statusCode": 200, +} +`; + +exports[`execute mantle network should return failure if tx not required even if it would be successful 1`] = ` +{ + "data": { + "result": 1, + }, + "jobRunID": "1", + "result": 1, + "statusCode": 200, +} +`; + +exports[`execute mantle network should return success when all methods succeed 1`] = ` +{ + "data": { + "result": 0, + }, + "jobRunID": "1", + "result": 0, + "statusCode": 200, +} +`; + +exports[`execute mantle network should return transaction submission is successful 1`] = ` +{ + "data": { + "result": 0, + }, + "jobRunID": "1", + "result": 0, + "statusCode": 200, +} +`; + exports[`execute metis network should return failure if tx not required even if it would be successful 1`] = ` { "data": { @@ -198,6 +264,72 @@ exports[`execute scroll network should return transaction submission is successf } `; +exports[`execute soneium network should return failure if tx not required even if it would be successful 1`] = ` +{ + "data": { + "result": 1, + }, + "jobRunID": "1", + "result": 1, + "statusCode": 200, +} +`; + +exports[`execute soneium network should return success when all methods succeed 1`] = ` +{ + "data": { + "result": 0, + }, + "jobRunID": "1", + "result": 0, + "statusCode": 200, +} +`; + +exports[`execute soneium network should return transaction submission is successful 1`] = ` +{ + "data": { + "result": 0, + }, + "jobRunID": "1", + "result": 0, + "statusCode": 200, +} +`; + +exports[`execute unichain network should return failure if tx not required even if it would be successful 1`] = ` +{ + "data": { + "result": 1, + }, + "jobRunID": "1", + "result": 1, + "statusCode": 200, +} +`; + +exports[`execute unichain network should return success when all methods succeed 1`] = ` +{ + "data": { + "result": 0, + }, + "jobRunID": "1", + "result": 0, + "statusCode": 200, +} +`; + +exports[`execute unichain network should return transaction submission is successful 1`] = ` +{ + "data": { + "result": 0, + }, + "jobRunID": "1", + "result": 0, + "statusCode": 200, +} +`; + exports[`execute zksync network should return failure if tx not required even if it would be successful 1`] = ` { "data": { diff --git a/packages/sources/layer2-sequencer-health/test/integration/fixtures.ts b/packages/sources/layer2-sequencer-health/test/integration/fixtures.ts index 0a6acd0178..6422abc8d8 100644 --- a/packages/sources/layer2-sequencer-health/test/integration/fixtures.ts +++ b/packages/sources/layer2-sequencer-health/test/integration/fixtures.ts @@ -124,6 +124,58 @@ export const mockResponseSuccessBlock = (): void => { 'Vary', 'Origin', ]) + + nock('https://rpc-gel.inkonchain.com') + .post('/', { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: /^\d+$/ }) + .reply(200, () => ({ jsonrpc: '2.0', id: 1, result: '0x42d293' }), [ + 'Content-Type', + 'application/json', + 'Connection', + 'close', + 'Vary', + 'Accept-Encoding', + 'Vary', + 'Origin', + ]) + + nock('https://rpc.mantle.xyz') + .post('/', { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: /^\d+$/ }) + .reply(200, () => ({ jsonrpc: '2.0', id: 1, result: '0x42d293' }), [ + 'Content-Type', + 'application/json', + 'Connection', + 'close', + 'Vary', + 'Accept-Encoding', + 'Vary', + 'Origin', + ]) + + nock('https://mainnet.unichain.org') + .post('/', { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: /^\d+$/ }) + .reply(200, () => ({ jsonrpc: '2.0', id: 1, result: '0x42d293' }), [ + 'Content-Type', + 'application/json', + 'Connection', + 'close', + 'Vary', + 'Accept-Encoding', + 'Vary', + 'Origin', + ]) + + nock('https://rpc.soneium.org') + .post('/', { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: /^\d+$/ }) + .reply(200, () => ({ jsonrpc: '2.0', id: 1, result: '0x42d293' }), [ + 'Content-Type', + 'application/json', + 'Connection', + 'close', + 'Vary', + 'Accept-Encoding', + 'Vary', + 'Origin', + ]) } export const mockResponseSuccessRollup = (): void => { @@ -255,6 +307,58 @@ export const mockResponseFailureBlock = (): void => { 'Vary', 'Origin', ]) + + nock('https://rpc-gel.inkonchain.com') + .post('/', { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: /^\d+$/ }) + .reply(200, () => ({ jsonrpc: '2.0', id: 1, result: '0x00' }), [ + 'Content-Type', + 'application/json', + 'Connection', + 'close', + 'Vary', + 'Accept-Encoding', + 'Vary', + 'Origin', + ]) + + nock('https://rpc.mantle.xyz') + .post('/', { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: /^\d+$/ }) + .reply(200, () => ({ jsonrpc: '2.0', id: 1, result: '0x00' }), [ + 'Content-Type', + 'application/json', + 'Connection', + 'close', + 'Vary', + 'Accept-Encoding', + 'Vary', + 'Origin', + ]) + + nock('https://mainnet.unichain.org') + .post('/', { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: /^\d+$/ }) + .reply(200, () => ({ jsonrpc: '2.0', id: 1, result: '0x00' }), [ + 'Content-Type', + 'application/json', + 'Connection', + 'close', + 'Vary', + 'Accept-Encoding', + 'Vary', + 'Origin', + ]) + + nock('https://rpc.soneium.org') + .post('/', { jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: /^\d+$/ }) + .reply(200, () => ({ jsonrpc: '2.0', id: 1, result: '0x00' }), [ + 'Content-Type', + 'application/json', + 'Connection', + 'close', + 'Vary', + 'Accept-Encoding', + 'Vary', + 'Origin', + ]) } export const mockResponseFailureRollup = (): void => { diff --git a/packages/sources/layer2-sequencer-health/test/integration/onchainFailKnown.test.ts b/packages/sources/layer2-sequencer-health/test/integration/onchainFailKnown.test.ts index 2794512c4a..7d4d69d645 100644 --- a/packages/sources/layer2-sequencer-health/test/integration/onchainFailKnown.test.ts +++ b/packages/sources/layer2-sequencer-health/test/integration/onchainFailKnown.test.ts @@ -15,6 +15,10 @@ const mockMessages = { 'https://rpc.scroll.io': 'invalid transaction: insufficient funds for l1fee + gas * price + value', 'https://mainnet.era.zksync.io': 'max fee per gas less than block base fee', + 'https://rpc-gel.inkonchain.com': 'intrinsic gas too low: gas 0', + 'https://rpc.mantle.xyz': 'failed to forward tx to sequencer', + 'https://mainnet.unichain.org': 'intrinsic gas too low: gas 0', + 'https://rpc.soneium.org': 'intrinsic gas too low: gas 0', } jest.mock('ethers', () => { @@ -276,4 +280,120 @@ describe('execute', () => { await sendRequestAndExpectStatus(data, 1) }) }) + + describe('ink network', () => { + it('should return success when transaction submission is known', async () => { + mockResponseFailureBlock() + + const data: AdapterRequest = { + id, + data: { + network: 'ink', + requireTxFailure: true, + }, + } + + await sendRequestAndExpectStatus(data, 0) + }) + + it('should return failure if tx not required', async () => { + mockResponseFailureBlock() + + const data: AdapterRequest = { + id, + data: { + network: 'ink', + }, + } + + await sendRequestAndExpectStatus(data, 1) + }) + }) + + describe('mantle network', () => { + it('should return success when transaction submission is known', async () => { + mockResponseFailureBlock() + + const data: AdapterRequest = { + id, + data: { + network: 'mantle', + requireTxFailure: true, + }, + } + + await sendRequestAndExpectStatus(data, 0) + }) + + it('should return failure if tx not required', async () => { + mockResponseFailureBlock() + + const data: AdapterRequest = { + id, + data: { + network: 'mantle', + }, + } + + await sendRequestAndExpectStatus(data, 1) + }) + }) + + describe('unichain network', () => { + it('should return success when transaction submission is known', async () => { + mockResponseFailureBlock() + + const data: AdapterRequest = { + id, + data: { + network: 'unichain', + requireTxFailure: true, + }, + } + + await sendRequestAndExpectStatus(data, 0) + }) + + it('should return failure if tx not required', async () => { + mockResponseFailureBlock() + + const data: AdapterRequest = { + id, + data: { + network: 'unichain', + }, + } + + await sendRequestAndExpectStatus(data, 1) + }) + }) + + describe('soneium network', () => { + it('should return success when transaction submission is known', async () => { + mockResponseFailureBlock() + + const data: AdapterRequest = { + id, + data: { + network: 'soneium', + requireTxFailure: true, + }, + } + + await sendRequestAndExpectStatus(data, 0) + }) + + it('should return failure if tx not required', async () => { + mockResponseFailureBlock() + + const data: AdapterRequest = { + id, + data: { + network: 'soneium', + }, + } + + await sendRequestAndExpectStatus(data, 1) + }) + }) }) diff --git a/packages/sources/layer2-sequencer-health/test/integration/onchainFailUnknown.test.ts b/packages/sources/layer2-sequencer-health/test/integration/onchainFailUnknown.test.ts index 21436dd18a..8390a6127a 100644 --- a/packages/sources/layer2-sequencer-health/test/integration/onchainFailUnknown.test.ts +++ b/packages/sources/layer2-sequencer-health/test/integration/onchainFailUnknown.test.ts @@ -137,4 +137,68 @@ describe('execute', () => { await sendRequestAndExpectStatus(data, 1) }) }) + + describe('ink network', () => { + const data: AdapterRequest = { + id, + data: { + network: 'ink', + }, + } + + it('should return failure when transaction submission is unknown', async () => { + mockResponseFailureHealth() + mockResponseFailureBlock() + + await sendRequestAndExpectStatus(data, 1) + }) + }) + + describe('mantle network', () => { + const data: AdapterRequest = { + id, + data: { + network: 'mantle', + }, + } + + it('should return failure when transaction submission is unknown', async () => { + mockResponseFailureHealth() + mockResponseFailureBlock() + + await sendRequestAndExpectStatus(data, 1) + }) + }) + + describe('unichain network', () => { + const data: AdapterRequest = { + id, + data: { + network: 'unichain', + }, + } + + it('should return failure when transaction submission is unknown', async () => { + mockResponseFailureHealth() + mockResponseFailureBlock() + + await sendRequestAndExpectStatus(data, 1) + }) + }) + + describe('soneium network', () => { + const data: AdapterRequest = { + id, + data: { + network: 'soneium', + }, + } + + it('should return failure when transaction submission is unknown', async () => { + mockResponseFailureHealth() + mockResponseFailureBlock() + + await sendRequestAndExpectStatus(data, 1) + }) + }) }) diff --git a/packages/sources/layer2-sequencer-health/test/integration/onchainSuccess.test.ts b/packages/sources/layer2-sequencer-health/test/integration/onchainSuccess.test.ts index f80d372a57..03ed18ff6f 100644 --- a/packages/sources/layer2-sequencer-health/test/integration/onchainSuccess.test.ts +++ b/packages/sources/layer2-sequencer-health/test/integration/onchainSuccess.test.ts @@ -427,4 +427,184 @@ describe('execute', () => { await sendRequestAndExpectStatus(data, 1) }) }) + + describe('ink network', () => { + it('should return success when all methods succeed', async () => { + mockResponseSuccessHealth() + mockResponseSuccessBlock() + + const data: AdapterRequest = { + id, + data: { + network: 'ink', + }, + } + + await sendRequestAndExpectStatus(data, 0) + }) + + it('should return transaction submission is successful', async () => { + mockResponseFailureHealth() + mockResponseFailureBlock() + + const data: AdapterRequest = { + id, + data: { + network: 'ink', + requireTxFailure: true, + }, + } + + await sendRequestAndExpectStatus(data, 0) + }) + + it('should return failure if tx not required even if it would be successful', async () => { + mockResponseFailureHealth() + mockResponseFailureBlock() + + const data: AdapterRequest = { + id, + data: { + network: 'ink', + }, + } + + await sendRequestAndExpectStatus(data, 1) + }) + }) + + describe('mantle network', () => { + it('should return success when all methods succeed', async () => { + mockResponseSuccessHealth() + mockResponseSuccessBlock() + + const data: AdapterRequest = { + id, + data: { + network: 'mantle', + }, + } + + await sendRequestAndExpectStatus(data, 0) + }) + + it('should return transaction submission is successful', async () => { + mockResponseFailureHealth() + mockResponseFailureBlock() + + const data: AdapterRequest = { + id, + data: { + network: 'mantle', + requireTxFailure: true, + }, + } + + await sendRequestAndExpectStatus(data, 0) + }) + + it('should return failure if tx not required even if it would be successful', async () => { + mockResponseFailureHealth() + mockResponseFailureBlock() + + const data: AdapterRequest = { + id, + data: { + network: 'mantle', + }, + } + + await sendRequestAndExpectStatus(data, 1) + }) + }) + + describe('unichain network', () => { + it('should return success when all methods succeed', async () => { + mockResponseSuccessHealth() + mockResponseSuccessBlock() + + const data: AdapterRequest = { + id, + data: { + network: 'unichain', + }, + } + + await sendRequestAndExpectStatus(data, 0) + }) + + it('should return transaction submission is successful', async () => { + mockResponseFailureHealth() + mockResponseFailureBlock() + + const data: AdapterRequest = { + id, + data: { + network: 'unichain', + requireTxFailure: true, + }, + } + + await sendRequestAndExpectStatus(data, 0) + }) + + it('should return failure if tx not required even if it would be successful', async () => { + mockResponseFailureHealth() + mockResponseFailureBlock() + + const data: AdapterRequest = { + id, + data: { + network: 'unichain', + }, + } + + await sendRequestAndExpectStatus(data, 1) + }) + }) + + describe('soneium network', () => { + it('should return success when all methods succeed', async () => { + mockResponseSuccessHealth() + mockResponseSuccessBlock() + + const data: AdapterRequest = { + id, + data: { + network: 'soneium', + }, + } + + await sendRequestAndExpectStatus(data, 0) + }) + + it('should return transaction submission is successful', async () => { + mockResponseFailureHealth() + mockResponseFailureBlock() + + const data: AdapterRequest = { + id, + data: { + network: 'soneium', + requireTxFailure: true, + }, + } + + await sendRequestAndExpectStatus(data, 0) + }) + + it('should return failure if tx not required even if it would be successful', async () => { + mockResponseFailureHealth() + mockResponseFailureBlock() + + const data: AdapterRequest = { + id, + data: { + network: 'soneium', + }, + } + + await sendRequestAndExpectStatus(data, 1) + }) + }) })