How to Monitor Arbitrum Assertion Status and Rollup Validation: A Complete Guide
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:
ArbitrumChainClient(src/clients/arbitrum-chain-client.ts): Core logic for querying parent chain events and calculating assertion statusassertion_statustool (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:
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 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:
const status = await client.getAssertionStatus(
"https://eth.llamarpc.com",
"0xYourRollupContractAddress"
);
Internally, the method performs these operations (src/clients/arbitrum-chain-client.ts lines 67-115):
- Creates a parent client: Initializes a second Viem client pointing at the Ethereum RPC
- Defines event ABIs: Uses
nodeCreatedEventAbi(lines 76-86) andnodeConfirmedEventAbi(lines 88-98) to parse event logs - Fetches historical logs: Queries the last approximately 50,000 blocks on Ethereum for both event types:
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 lines 117-124):
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):
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 (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:
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:
{
"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:
{
"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
NodeCreatedandNodeConfirmedevents. - The
ArbitrumChainClient.getAssertionStatusmethod insrc/clients/arbitrum-chain-client.tsqueries 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_statusMCP 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →