# How to Monitor Arbitrum Assertion Status and Rollup Validation: A Complete Guide

> Monitor Arbitrum assertion status and rollup validation by querying parent chain events and using ArbitrumChainClient.getAssertionStatus. Learn the complete process for efficient monitoring.

- Repository: [Dewansh/arbitrum-mcp](https://github.com/dewanshparashar/arbitrum-mcp)
- Tags: how-to-guide
- Published: 2026-02-28

---

**Monitor Arbitrum rollup validation by querying `NodeCreated` and `NodeConfirmed` events from the parent chain, then calculating the gap between the latest created and confirmed assertion IDs using the `ArbitrumChainClient.getAssertionStatus` method.**

Arbitrum rollup validation depends on tracking assertions—cryptographic claims about the state of the L2 chain submitted to Ethereum. The `dewanshparashar/arbitrum-mcp` repository provides a dedicated client that automates this monitoring process by interfacing with both Arbitrum and Ethereum RPC endpoints. This guide explains how to monitor Arbitrum assertion status and rollup validation using the source code implementation.

## Understanding Arbitrum Assertions and Rollup Validation

Arbitrum uses an optimistic rollup model where validators submit assertions (also called nodes) to the parent chain. These assertions represent claims about the L2 state. The validation process hinges on two critical events emitted by the rollup contract:

- **NodeCreated**: Emitted when a new assertion is submitted to the parent chain
- **NodeConfirmed**: Emitted when an assertion passes the challenge period and is finalized

The gap between the latest created assertion and the latest confirmed assertion indicates the current validation backlog. A growing gap suggests potential liveness issues, while a zero gap indicates the rollup is fully caught up.

## The Monitoring Architecture in arbitrum-mcp

The repository implements assertion monitoring through two primary components:

1. **`ArbitrumChainClient`** ([`src/clients/arbitrum-chain-client.ts`](https://github.com/dewanshparashar/arbitrum-mcp/blob/main/src/clients/arbitrum-chain-client.ts)): Core logic for querying parent chain events and calculating assertion status
2. **`assertion_status` tool** ([`src/index.ts`](https://github.com/dewanshparashar/arbitrum-mcp/blob/main/src/index.ts)): MCP tool interface that exposes the client functionality to external consumers

The client uses Viem for RPC interactions, creating separate public clients for the Arbitrum chain (child) and Ethereum chain (parent).

## Step-by-Step: Monitoring Assertion Status

### Initializing the ArbitrumChainClient

To begin monitoring, instantiate the client with the Arbitrum RPC endpoint:

```typescript
import { ArbitrumChainClient } from "./src/clients/arbitrum-chain-client";

const client = new ArbitrumChainClient("https://arb1.arbitrum.io/rpc");

```

The constructor initializes a Viem `publicClient` using HTTP transport ([`src/clients/arbitrum-chain-client.ts`](https://github.com/dewanshparashar/arbitrum-mcp/blob/main/src/clients/arbitrum-chain-client.ts) lines 39-44). This client handles all subsequent Arbitrum chain interactions.

### Querying Parent Chain Events

The `getAssertionStatus` method requires the parent chain RPC URL and the rollup contract address:

```typescript
const status = await client.getAssertionStatus(
  "https://eth.llamarpc.com",
  "0xYourRollupContractAddress"
);

```

Internally, the method performs these operations ([`src/clients/arbitrum-chain-client.ts`](https://github.com/dewanshparashar/arbitrum-mcp/blob/main/src/clients/arbitrum-chain-client.ts) lines 67-115):

1. **Creates a parent client**: Initializes a second Viem client pointing at the Ethereum RPC
2. **Defines event ABIs**: Uses `nodeCreatedEventAbi` (lines 76-86) and `nodeConfirmedEventAbi` (lines 88-98) to parse event logs
3. **Fetches historical logs**: Queries the last approximately 50,000 blocks on Ethereum for both event types:

```typescript
const [createdLogs, confirmedLogs] = await Promise.all([
  parentClient.getLogs({ 
    address: rollupAddress, 
    event: nodeCreatedEventAbi, 
    fromBlock, 
    toBlock: latestBlockNumber 
  }),
  parentClient.getLogs({ 
    address: rollupAddress, 
    event: nodeConfirmedEventAbi, 
    fromBlock, 
    toBlock: latestBlockNumber 
  })
]);

```

### Calculating the Creation-Confirmation Gap

After retrieving the logs, the method extracts the latest assertion numbers ([`src/clients/arbitrum-chain-client.ts`](https://github.com/dewanshparashar/arbitrum-mcp/blob/main/src/clients/arbitrum-chain-client.ts) lines 117-124):

```typescript
const latestCreatedAssertion = createdLogs.length > 0
  ? createdLogs[createdLogs.length - 1].args?.nodeNum || null
  : null;

const latestConfirmedAssertion = confirmedLogs.length > 0
  ? confirmedLogs[confirmedLogs.length - 1].args?.nodeNum || null
  : null;

```

It then calculates the gap between created and confirmed assertions (lines 126-130):

```typescript
const creationConfirmationGap = (latestCreatedAssertion && latestConfirmedAssertion)
  ? latestCreatedAssertion - latestConfirmedAssertion
  : 0n;

```

A gap of `0` indicates all assertions are confirmed. Any positive number represents pending assertions awaiting finalization.

## Using the MCP Tool for Real-Time Monitoring

While the client class provides programmatic access, the repository exposes this functionality through the `assertion_status` MCP tool defined in [`src/index.ts`](https://github.com/dewanshparashar/arbitrum-mcp/blob/main/src/index.ts) (lines 40-49). This tool accepts the parent RPC URL and rollup address, then returns the structured status object.

The tool handles RPC URL resolution through the chain lookup service, allowing you to specify chain names (e.g., "arbitrum", "ethereum") instead of raw URLs.

## Code Examples

### Direct Client Implementation

For custom monitoring dashboards or alerting systems, use the client directly:

```typescript
import { ArbitrumChainClient } from "./src/clients/arbitrum-chain-client";

async function monitorAssertions() {
  const arbRpc = "https://arb1.arbitrum.io/rpc";
  const ethRpc = "https://eth.llamarpc.com";
  const rollupAddress = "0xYourRollupContract";

  const client = new ArbitrumChainClient(arbRpc);
  
  try {
    const status = await client.getAssertionStatus(ethRpc, rollupAddress);
    
    console.log("🧩 Assertion Status:", status.summary);
    
    // Alert if gap is growing
    if (status.creationConfirmationGap && BigInt(status.creationConfirmationGap) > 5n) {
      console.warn("⚠️ Large confirmation gap detected:", status.creationConfirmationGap);
    }
  } catch (error) {
    console.error("Failed to fetch assertion status:", error);
  }
}

// Run every 60 seconds
setInterval(monitorAssertions, 60000);

```

### JSON-RPC MCP Request

For integrations using the MCP protocol:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "assertion_status",
  "params": {
    "rpcUrl": "https://arb1.arbitrum.io/rpc",
    "parentRpcUrl": "https://eth.llamarpc.com",
    "rollupAddress": "0xYourRollupContractAddress"
  }
}

```

Expected response format:

```json
{
  "content": [
    {
      "type": "text",
      "text": "{\"latestCreatedAssertion\":\"12345\",\"latestConfirmedAssertion\":\"12344\",\"creationConfirmationGap\":\"1\",\"summary\":\"Latest created assertion: 12345, Latest confirmed: 12344. Gap: 1\"}"
    }
  ]
}

```

## Summary

- **Arbitrum validation relies on assertions** submitted to the parent chain, tracked via `NodeCreated` and `NodeConfirmed` events.
- **The `ArbitrumChainClient.getAssertionStatus` method** in [`src/clients/arbitrum-chain-client.ts`](https://github.com/dewanshparashar/arbitrum-mcp/blob/main/src/clients/arbitrum-chain-client.ts) queries the last 50,000 blocks of Ethereum to retrieve these events.
- **The creation-confirmation gap** indicates rollup health—zero means fully caught up, while positive values show pending assertions.
- **The `assertion_status` MCP tool** exposes this functionality for external monitoring systems via JSON-RPC.
- **Error handling** ensures RPC failures return safe defaults rather than crashing the monitoring process.

## Frequently Asked Questions

### What is the difference between NodeCreated and NodeConfirmed events?

`NodeCreated` events fire when a validator submits a new assertion to the rollup contract on Ethereum, capturing the `nodeNum` (assertion ID) at creation time. `NodeConfirmed` events fire when that assertion passes the challenge window and is finalized, also referencing the same `nodeNum`. The sequence between these two events constitutes the validation lifecycle of a single assertion.

### How does the creation-confirmation gap indicate rollup health?

The gap represents the mathematical difference between the latest created assertion ID and the latest confirmed assertion ID. A gap of zero indicates the rollup is fully synchronized with all assertions validated. A growing gap suggests validators are submitting assertions faster than they are being confirmed, potentially indicating network congestion, validator disputes, or liveness issues that require investigation.

### What RPC endpoints are required for monitoring?

The monitoring process requires two distinct RPC endpoints: an **Arbitrum RPC URL** (child chain) used to initialize the `ArbitrumChainClient`, and a **parent chain (Ethereum) RPC URL** passed to `getAssertionStatus` to query the rollup contract events. The implementation supports both raw URLs and chain name resolution via the built-in chain lookup service.

### How does arbitrum-mcp handle RPC failures?

The `getAssertionStatus` method wraps its logic in a try-catch block that returns a safe default object when any RPC call fails. This fallback object contains `null` values for assertion numbers, a zero gap, and an error summary string, ensuring that monitoring dashboards receive predictable JSON even during network outages or endpoint failures.