<!-- Canonical: https://docs.linea.build/network/overview/transaction-finality -->

> For the complete Linea documentation index, see [llms.txt](/llms.txt).
> Agents can fetch this page as Markdown at [https://docs.linea.build/network/overview/transaction-finality.md](https://docs.linea.build/network/overview/transaction-finality.md).

# Transaction finality

A Linea transaction moves through two finality states before it is permanently settled on Ethereum.

## Transaction lifecycle

When you submit a transaction on Linea, it follows this path: the [sequencer](/protocol/architecture/sequencer) [validates and includes](/protocol/architecture/sequencer#transaction-validity-conditions) it in an L2 block, reaching soft finality in approximately 1 second. The [Coordinator](/protocol/architecture/coordinator) then groups blocks into a batch and submits it to Ethereum. The [prover](/protocol/architecture/prover) generates a [ZK proof](/protocol/reference/zero-knowledge-glossary#zero-knowledge-proof) for the batch, which is verified by the [Linea rollup contract](/protocol/architecture/smart-contracts) on L1. Once the L1 block containing the proof is [finalized by Ethereum's consensus](https://ethereum.org/developers/docs/consensus-mechanisms/pos#finality), the transaction reaches hard finality.

For the full protocol-level breakdown, see [Architecture: Transaction lifecycle](/protocol/architecture#transaction-lifecycle).

## Soft finality

When the [sequencer](/protocol/architecture/sequencer) orders, executes, and seals your transaction into an L2 block, it has reached **soft finality**. This happens within approximately 1 second, which is Linea's block time.

At soft finality:

-   The transaction is confirmed on Linea and visible in your wallet
-   Once a transaction reaches soft finality on Linea, it will not be removed or reordered by Linea
-   Ethereum (L1) may still reorg, but this does not affect Linea's confirmed state

For most application use cases, including swaps, transfers, and in-app interactions, soft finality is sufficient.

## Hard finality

Hard finality is reached when the [ZK proof](/protocol/reference/zero-knowledge-glossary#zero-knowledge-proof) covering your transaction's batch has been verified by the [Linea rollup contract](/protocol/architecture/smart-contracts) on Ethereum, and the L1 block containing that verification transaction is itself [finalized by Ethereum's consensus](https://ethereum.org/developers/docs/consensus-mechanisms/pos#finality) (two epochs / ~12.8 minutes).

At hard finality:

-   The transaction is cryptographically proven on Ethereum and inherits its security guarantees
-   It is anchored to Ethereum's security guarantees
-   The current median time to hard finality is under 1 hour 40 minutes, and is expected to reach approximately 30 minutes as proving performance improves
-   Hard finality should never exceed 16 hours under normal operating conditions

Hard finality is required for cross-layer withdrawals, CEX deposit confirmations, and any use case where Ethereum-level security guarantees are needed.

## What you should care about

| Use case | Finality needed | Why |
| --- | --- | --- |
| In-app transactions, swaps | Soft | Once confirmed on Linea, the transaction is in the canonical chain and [will not be reversed](/protocol/reference/zero-knowledge-glossary#reorgs) by the L2 |
| Bridge withdrawals to L1 | Hard | Funds must be provably settled on Ethereum |
| CEX deposits | Hard | Exchanges require irreversibility |
| Onchain gaming, NFT mints | Soft | Speed matters, because Linea does not reorg after soft finality |

## How to check finality

### Use the `finalized` tag

Use the `finalized` tag in JSON-RPC calls to target the latest hard-finalized block:

```bash
curl https://rpc.linea.build \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["finalized",false],"id":1}'
```

The `finalized` tag is supported by all applicable JSON-RPC methods on Linea Mainnet and Linea Sepolia, with the exception of `eth_call`. On Linea, `eth_call` does not currently support the `finalized` block tag.

### Query the rollup contract

As an alternative to the `finalized` tag, you can query the [Linea L1 rollup contract](https://etherscan.io/address/0xd19d4b5d358258f05d7b411e21a1460d11b0876f#readProxyContract) to retrieve the value of the current finalized L2 block number stored in the `currentL2BlockNumber` variable.

note

Etherscan reads contract state from the **latest** L1 block, not the **finalized** one. The value shown may therefore be slightly ahead of the actual hard-finalized L2 block number. For exact finalized state, use the `finalized` JSON-RPC tag described above.

**Prerequisites:** [Node.js](https://nodejs.org/en) installed.

1.  Initialize the project and install the `web3` package:

```bash
npm init -y && npm install web3
```

2.  Create a JavaScript file (for example `index.js`) and copy the following code:

    info

    Replace the Infura endpoint with your preferred Ethereum L1 RPC provider. You can use any L1 endpoint, including Infura, Alchemy, or a self-hosted node.

    index.js

```javascript
const { Web3 } = require("web3")
const web3 = new Web3(new Web3.providers.HttpProvider(`https://mainnet.infura.io/v3/<YOUR-API-KEY>`))
const lineaRollupAbi = [{"constant":true,"inputs":[],"name":"currentL2BlockNumber","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}];
const lineaRollupAddress = '0xd19d4b5d358258f05d7b411e21a1460d11b0876f';
const lineaRollupContract = new web3.eth.Contract(lineaRollupAbi, lineaRollupAddress);
async function getFinalizedL2BlockNumber() {
  try {
    const currentL2BlockNumber = await lineaRollupContract.methods.currentL2BlockNumber().call();
    const blockNumberHex = '0x' + BigInt(currentL2BlockNumber).toString(16);
    console.log('Finalized L2 Block Number:', currentL2BlockNumber.toString());
    console.log('Finalized L2 Block Number (Hex):', blockNumberHex);
    return { blockNumber: currentL2BlockNumber, blockNumberHex };
  } catch (error) {
    console.error('Error fetching L2 block number:', error);
  }
}
getFinalizedL2BlockNumber();
```

3.  Run the script:

```bash
node index.js
```

## Next steps

-   Understand how the [protocol architecture](/protocol/architecture) supports finality, including the full [transaction lifecycle](/protocol/architecture#transaction-lifecycle)
-   Learn about [predictable pricing](/network/overview/predictable-pricing) on Linea
-   [Run a node](/network/how-to/run-a-node) to query finality state yourself
-   Learn how to [submit forced transactions](/protocol/how-to/forced-transactions) directly to L1
