Listening to Arbitrum events, fetching 4844 blobs, and destructuring batches for an L2 indexer

What I’m building

  • We’re building an L2 indexer that listens to Arbitrum contracts, fetches associated 4844 blobs, and decodes the batches into L2 messages and transactions.

What I need help with

  • I have a basic working model for listening to arbitrum’s sequence inbox contract on ethereum for the event SequencerBatchDelivered: 0x1c479675ad559DC151F6Ec7ed3FbF8ceE79582B6. Is this the right contract to keep listening to?

  • I am using blobscan’s APIs to fetch the blob for the current block submitted by Arbitrum’s contract.

  • Below is the production-safe way to decode the blob. Help me understand if this is right finding.

    • DAS/AnyTrust flagged blobs (0x80… first byte).

    • Nitro brotli batch header (0x00… first byte).

    • Already-decompressed RLP segment streams.

    • Direct L2 message boundary cases (0x03/0x04/0x09).

Brief findings so far (sanity check)

  • Validating KZG commitment before decoding seems correct. So i believe the blob that I am fetching is right according to the metadata found in the event.

  • Below is a top-level branching according to first byte of the blob that I’m following.

    • 0x80.. → treat as AnyTrust/DAS header; fetch via DAC using data hash, then decode Nitro batch.

    • 0x00 → brotli-decompress from byte 1 onward, then decode RLP segments.

    • Otherwise → probe: try RLP stream on raw; if not, try brotli then RLP; if first byte is 0x03/0x04/0x09, parse as L2 message directly.

  • Nitro batch → RLP segments (no outer list), where segment kinds: 0=L2 message, 1=L2 message brotli-compressed, 2=delayed pointer.

  • L2 message kinds: 0x04=SignedTx (accept legacy/0x01/0x02), 0x03=Nested batch (8-byte big-endian frame lengths), 0x09=synthetic delayed.

Questions

  • Is this branching/decoding strategy correct for production scenarios?

  • Are we missing any common edge cases or alternative encodings we should expect?

  • Any references or best practices for DAC fetch and base64 handling, and for robust RLP segment iteration?

Was reviewing this repo: arbitrum-cli-tools/packages/batch-tx-handler/src/main.ts at main · OffchainLabs/arbitrum-cli-tools · GitHub which helped me come up with the above findings. Is this a good place to start with? or are there any other resources which I can use to move ahead?

Here is my rust codebase

Hey, these questions may be too technical for an average DAO delegate, but perhaps @stonecoldpat could answer some, or point you to where you can get the answers.

Or maybe some of the Security Council candidates with deep technical understanding of Arbitrum could answer these, e.g. @gustavo-grieco, @emilianobonassi, @Cyfrin, @WakeUpLabs, @dzack23, @pablitoeth etc.

1 Like

Hello @jk_it_is !

Your best source of information on the block parsing is the nitro code itself, in particular:

Start from the inbox.go file and review all the called DA functions in nitro/daprovider.

In general, I think you are in the right track. There are no “alternative” encodings, however, some L2 messages changed a bit over time, so depending on the block number there are differences that must be accounted to preserved the code retro compatible. Keep that in mind if you want to parse past Arbitrum events as well.

Regards,

Gustavo.

4 Likes

Thanks @gustavo-grieco - Looking into the links you have shared.