Skip to main content

Why Blockchain

The hash chain (Layer 1) detects tampering — but only if you trust that the hashes themselves haven’t been rewritten. Blockchain anchoring removes that trust requirement. By publishing Merkle roots to a public blockchain, we create a permanent, independently verifiable record that exists outside our control. Even if we rewrote our entire database and recomputed every hash, the on-chain Merkle roots would not match.

How It Works

1

Collect events

Immutable groups all events created within an anchoring period (daily by default) for each workspace.
2

Build Merkle tree

A binary Merkle tree is constructed from the event hashes. If the number of leaves is odd, the last leaf is duplicated. The tree is reduced to a single 64-character hex root.
3

Submit to Base

The Merkle root is submitted to the ImmutableAnchor smart contract on the Base blockchain (Chain ID 8453) — an Ethereum L2.
4

Confirm on-chain

Once the transaction is confirmed, the anchor record is updated with the transaction hash, block number, and explorer URL.
Events in period          Merkle Tree              On-chain
┌────┐ ┌────┐ ┌────┐
│ h1 │ │ h2 │ │ h3 │     h12 = SHA256(h1+h2)     ┌──────────────┐
└────┘ └────┘ └────┘     h33 = SHA256(h3+h3)     │ ImmutableAnchor │
                          root = SHA256(h12+h33)   │ anchor(root)    │
                                                   │ tx: 0xabc...   │
                                                   └──────────────┘
The Merkle tree is a standard binary tree. When the number of leaves is odd, the last leaf is duplicated to complete the pair. This produces a single 64-character hex root that represents all events in the period.

The Smart Contract

The ImmutableAnchor.sol contract is deliberately simple — its only job is to permanently record Merkle roots:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

contract ImmutableAnchor {
    event Anchored(bytes32 indexed merkleRoot, uint256 timestamp);

    function anchor(bytes32 merkleRoot) external {
        emit Anchored(merkleRoot, block.timestamp);
    }
}
The Anchored event log is permanent and publicly readable. Anyone can query it from Basescan or directly from a Base node.

Why Base

Base is an Ethereum L2 (Layer 2) rollup. It provides:
PropertyBenefit
Low transaction costAnchoring costs fractions of a cent per workspace per day
Fast confirmationsTransactions confirm in seconds, not minutes
Ethereum securityInherits Ethereum’s security guarantees via rollup proofs
Public and permissionlessAnyone can read the chain — no account or API key needed
Chain ID 8453Standard EVM chain, supported by all major tools

Anchor Lifecycle

Each anchor transitions through three statuses:
pending  →  submitted  →  confirmed
StatusMeaning
pendingMerkle root computed, transaction not yet sent
submittedTransaction sent to Base, awaiting confirmation
confirmedTransaction confirmed on-chain, tx_hash and block_number recorded

Anchor Chaining

Anchors are themselves chained. Each anchor stores a previous_anchor_hash computed from the previous anchor:
previous_anchor_hash = SHA256(previous_merkle_root + previous_tx_hash)
This means deleting or reordering anchors is also detectable. The anchor chain provides a second layer of sequential integrity on top of the event hash chain.
Anchor 1                Anchor 2                Anchor 3
┌────────────────┐      ┌────────────────┐      ┌────────────────┐
│ merkle_root: r1│      │ merkle_root: r2│      │ merkle_root: r3│
│ tx_hash: 0xa.. │      │ tx_hash: 0xb.. │      │ tx_hash: 0xc.. │
│ prev: null     │─────>│ prev: sha(r1+a)│─────>│ prev: sha(r2+b)│
└────────────────┘      └────────────────┘      └────────────────┘

Basescan Verification

Every confirmed anchor includes an explorer_url pointing directly to the transaction on Basescan:
https://basescan.org/tx/{tx_hash}
On Basescan, you can:
  1. Confirm the transaction exists and is confirmed
  2. Read the Anchored event log
  3. Extract the merkleRoot bytes32 value
  4. Compare it to what Immutable reports via the API
This is fully independent verification — no Immutable API involved.

API Access

curl https://getimmutable.dev/api/v1/anchors \
  -H "Authorization: Bearer imk_your_api_key_here"
See the full API reference: List Anchors | Get Anchor | Verify Anchor
Anchors in pending or submitted status cannot be verified on-chain yet. Only confirmed anchors have a tx_hash and block_number. The verify endpoint will return the current status for non-confirmed anchors.