> ## Documentation Index
> Fetch the complete documentation index at: https://seilabs-docs-evm-cookbook.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Sei EVM vs Ethereum: Key Differences

> A comparison of Sei EVM and Ethereum, highlighting Sei's advantages in blocktime, throughput, finality, and execution environment, as well as technical differences in opcodes, state storage, and other features.

export const SstoreGasLive = ({network = 'mainnet'}) => {
  const COLD = '0x50025cb2';
  const PARAM = '0x095f88b9';
  const RPC = {
    mainnet: {
      url: 'https://evm-rpc.sei-apis.com',
      chain: 'Sei Mainnet',
      id: 1329,
      probe: '0xeeB428bcf499D0A1c401f123F64BFf754a5de57A',
      explorer: 'https://seiscan.io/address/0xeeB428bcf499D0A1c401f123F64BFf754a5de57A'
    },
    testnet: {
      url: 'https://evm-rpc-testnet.sei-apis.com',
      chain: 'Sei Testnet',
      id: 1328,
      probe: '0xE5A35b2457E1C3cfF2F6527fAA32DE0B2a8e28E0',
      explorer: 'https://testnet.seiscan.io/address/0xE5A35b2457E1C3cfF2F6527fAA32DE0B2a8e28E0'
    }
  };
  const [net, setNet] = useState(network === 'testnet' ? 'testnet' : 'mainnet');
  const [data, setData] = useState(null);
  const [err, setErr] = useState(null);
  const [loading, setLoading] = useState(true);
  const [isDark, setIsDark] = useState(true);
  useLayoutEffect(() => {
    const el = document.documentElement;
    const update = () => setIsDark(el.classList.contains('dark'));
    update();
    const obs = new MutationObserver(update);
    obs.observe(el, {
      attributes: true,
      attributeFilter: ['class']
    });
    return () => obs.disconnect();
  }, []);
  const ethCall = async (url, to, data) => {
    const res = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        jsonrpc: '2.0',
        id: 1,
        method: 'eth_call',
        params: [{
          to,
          data
        }, 'latest']
      })
    });
    const json = await res.json();
    if (json.error) throw new Error(json.error.message || 'eth_call failed');
    return parseInt(json.result, 16);
  };
  const load = async which => {
    setLoading(true);
    setErr(null);
    try {
      const {url, probe} = RPC[which];
      const [param, cold] = await Promise.all([ethCall(url, probe, PARAM), ethCall(url, probe, COLD)]);
      setData({
        param,
        cold
      });
    } catch (e) {
      setErr(e && e.message ? e.message : 'Failed to query RPC');
      setData(null);
    } finally {
      setLoading(false);
    }
  };
  useEffect(() => {
    load(net);
  }, [net]);
  const fmt = n => n == null ? '—' : n.toLocaleString('en-US');
  const TabButton = ({value, children}) => {
    const active = net === value;
    return <button type="button" onClick={() => setNet(value)} className="px-3 py-1 transition-colors" style={{
      fontFamily: 'var(--sei-font-mono)',
      fontSize: '11px',
      textTransform: 'uppercase',
      letterSpacing: '0.04em',
      color: active ? '#ffffff' : isDark ? 'var(--sei-maroon-25)' : 'var(--sei-maroon-100)',
      backgroundColor: active ? 'var(--sei-maroon-100)' : 'transparent',
      border: `1px solid ${isDark ? 'var(--sei-maroon-25)' : 'var(--sei-maroon-100)'}`,
      cursor: active ? 'default' : 'pointer'
    }}>
        {children}
      </button>;
  };
  const Stat = ({label, value, sub}) => <div className="flex flex-col gap-0.5">
      <span className="text-[11px] uppercase tracking-wide text-neutral-600 dark:text-neutral-400" style={{
    fontFamily: 'var(--sei-font-mono)'
  }}>
        {label}
      </span>
      <span className="text-2xl font-semibold text-neutral-900 dark:text-neutral-50 tabular-nums" style={{
    fontFamily: 'var(--sei-font-mono)'
  }}>
        {loading ? '…' : value}
        <span className="text-sm font-normal text-neutral-600 dark:text-neutral-400"> gas</span>
      </span>
      {sub && <span className="text-[11px] text-neutral-600 dark:text-neutral-400">{sub}</span>}
    </div>;
  return <div className="not-prose w-full rounded-lg border border-neutral-200 dark:border-neutral-700 p-4" style={{
    backgroundColor: 'rgba(127,127,127,0.04)'
  }}>
      <div className="flex items-center justify-between gap-3 mb-3">
        <span className="text-[12px] font-semibold text-neutral-700 dark:text-neutral-200" style={{
    fontFamily: 'var(--sei-font-mono)'
  }}>
          Live SSTORE gas, measured on-chain
        </span>
        <div className="inline-flex">
          <TabButton value="mainnet">Mainnet</TabButton>
          <TabButton value="testnet">Testnet</TabButton>
        </div>
      </div>

      {err ? <div className="text-[12px] text-red-600 dark:text-red-400" style={{
    fontFamily: 'var(--sei-font-mono)'
  }}>
          Could not reach {RPC[net].chain} RPC: {err}{' '}
          <button type="button" onClick={() => load(net)} className="underline">
            retry
          </button>
        </div> : <div className="flex flex-wrap gap-x-10 gap-y-3">
          <Stat label="SSTORE_SET parameter" value={fmt((data && data.param) - 8)} sub="governance value (≈ 72,000)" />
          <Stat label="Cold first write" value={fmt((data && data.cold) - 7)} sub="SSTORE_SET + EIP-2929 cold access (2,100)" />
        </div>}

      <div className="mt-3 text-[11px] text-neutral-600 dark:text-neutral-400">
        {RPC[net].chain} ({RPC[net].id}) · read with <code>eth_call</code> from the verified{' '}
        <a href={RPC[net].explorer} target="_blank" rel="noopener noreferrer" className="underline">
          SstoreGasProbe
        </a>{' '}
        contract. Governance can change this value.{' '}
        <a href="https://seistream.app/proposals/109" target="_blank" rel="noopener noreferrer" className="underline">
          Proposal #109
        </a> set it.
      </div>
    </div>;
};

Sei has full EVM compatibility, but Sei EVM and Ethereum differ in some ways:

| Feature | Sei EVM | Ethereum |
| - | - | - |
| Block time | 400 ms | 12 s |
| Gas per second | \~ 100 MegaGas/s | \~ 5 MegaGas/s |
| Finality | Instant (\~400 ms) | Various commitment levels (safe, latest, justified, finalized) |
| Parallelized execution | Yes | No |
| EVM tooling compatibility | 100% | 100% |
| EVM version | Pectra (without blobs) | Fusaka |
| Gas limit | 12.5 M (block cap) | 60 M (block), \~16.7 M per-tx (EIP-7825) |
| Per-tx gas cap | 12.5 M (block limit) | \~16.7 M (EIP-7825) |
| Byte size limit | 21 MB | No byte-denominated limits |
| Execution environment | EVM and Cosmos SDK | EVM |
| Address space | Dual ECDSA-derived addresses: Cosmos Bech32 (sei…) and EVM-compatible (0x…) | ECDSA-derived address (0x…) |
| State storage | AVL tree (global root) | Merkle Patricia Trie (MPT) |
| SSTORE gas cost | 72k (on-chain parameter, governance-adjustable) | 20k (fixed) |

* Sei uses the Pectra (Prague and Electra) version of the EVM, without blob transactions. Ethereum has since upgraded to Fusaka (December 2025). Fusaka introduced PeerDAS to improve data availability.
* Sei's gas limit is 12.5 M, compared with 60 M on Ethereum. The Fusaka upgrade increased Ethereum's limit from 45 M through EIP-7935. Sei also has a byte size limit of 21 MB.
* Sei has instant finality. A transaction is final as soon as its block is committed (approximately 400 ms). As a result, the commitment levels typical for Ethereum (safe, latest, and justified) do not apply on Sei.

<Danger>
  **Deprecation notice**

  Cosmos SDK and CosmWasm functionality is being deprecated in favor of EVM-only. For more details, see [SIP-3](https://github.com/sei-protocol/sips/blob/main/sips/sip-3.md) and [Proposal 99](https://seistream.app/proposals/99).

  [Proposal 115](https://seistream.app/proposals/115) also disables CosmWasm code uploads and contract instantiations chain-wide. As a result, you cannot deploy new CosmWasm contracts. Only `execute` and `query` against existing CosmWasm contracts remain available.
</Danger>

* **Sei is a dual-execution environment (EVM and Cosmos SDK).** This means that:
  * Non-EVM transactions can update EVM-accessible state.
    * For example, both Cosmos transactions (bank send, wasm execute) and EVM send transactions can change an account's SEI balance.
  * Sei assets can exist as EVM tokens (ERC-20, ERC-721, and ERC-1155) or as legacy CosmWasm tokens (CW20, CW721, and CW1155). They can also exist as "native" Bank Module assets (Sei). Under Proposal 115, you can no longer deploy CosmWasm tokens.
  * User accounts on Sei have [two addresses](/learn/accounts) derived from the same public key (Cosmos Bech32 and EVM-compatible 0x…).
  * Interoperability between EVM and Cosmos SDK modules works through [precompiles](/evm/precompiles/example-usage) and [pointer contracts](/learn/pointers).

## Sei EVM release

Sei EVM was first deployed at these block heights and versions:

### Testnet

* **Name:** `v5.5.1`
* **Height:** `90526031`
* **Changelog:** [https://github.com/sei-protocol/sei-chain/blob/main/CHANGELOG.md#v5.5.1](https://github.com/sei-protocol/sei-chain/blob/main/CHANGELOG.md#v5.5.1)

### Mainnet

* **Name:** `v5.5.2`
* **Height:** `79123881`
* **Changelog:** [https://github.com/sei-protocol/sei-chain/blob/main/CHANGELOG.md#v552](https://github.com/sei-protocol/sei-chain/blob/main/CHANGELOG.md#v552)

## Opcode differences

| Opcode | Sei EVM | Ethereum | Notes |
| - | - | - | - |
| PREVRANDAO | Returns a value derived from the current block time | Returns the RANDAO mix (EIP‑4399) | Not a randomness source. Use an oracle/VRF. `DIFFICULTY` aliases to this. |
| COINBASE | Always the global fee collector address | Block proposer (miner) address | Do not assume it is the validator address. |
| BASEFEE | Returns the current base fee, with no burn | Returns the current base fee. A portion is burned (EIP‑1559). | Legacy transactions must meet Sei's governance-set minimum gas price (currently `50 gwei`). Query `eth_gasPrice` for the live value. |
| BLOCKHASH | Hash of the Tendermint header, with a different encoding | Keccak of the Ethereum block header | Usable for recent blocks only. Values are not interchangeable across chains. |
| GASLIMIT | = 12,500,000 per block | = 60,000,000 per block | Represents the block gas limit on both chains. |
| TIMESTAMP | Tendermint block time | Proposer-chosen block time | Same semantics. Do not use it for randomness. |
| DIFFICULTY | Alias of PREVRANDAO | Alias of PREVRANDAO (EIP‑4399) | Returns the same value as PREVRANDAO. |
| Blob‑related opcodes | Not supported (Pectra without blobs) | Supported post‑Cancun (EIP‑4844) | Blob transactions are not enabled on Sei. |

### PREVRANDAO

Proof of Stake (PoS) Ethereum uses pseudo‑randomness to determine the next
validator. Sei does not rely on the same method, so it does not have the
"randomness" artifact that can be set as `PREVRANDAO`'s return value. On Sei,
`PREVRANDAO` returns a value derived from the current block time. If your
contract logic needs strong randomness, use a verifiable randomness oracle.
This is also the advice for Ethereum.

### COINBASE

On Sei, the coinbase address is always the EVM address of the global fee
collector.

## State root

Sei uses an AVL tree instead of a Merkle Patricia Trie (MPT) for data storage.
Because of this, Sei does not have a per-account state root. The global state
root is the AVL-tree root. It is also not equivalent to Ethereum's overall
state root, which is an MPT root.

## Block hash

Sei computes the block hash from the block header in Tendermint data format.
As a result, it is different from Ethereum's block hash.

## Base fee & tips

Sei supports all non‑blob transaction types, including the Pectra `SetCode` transaction (EIP‑7702). However, for a legacy (non EIP‑1559)
transaction, you must specify a gas price at or above Sei's governance-set minimum gas price. The minimum is currently `50 gwei` on Sei Mainnet. Query the live value with `eth_gasPrice` instead of hard-coding it. Also,
excess "gas wanted/gas limit" beyond the actual "gas used" may not be refunded
in full or in part.

You can fetch the current EIP-1559 parameters with `seid`:

```sh theme={null}
seid q params subspace evm KeyTargetGasUsedPerBlock

key: KeyTargetGasUsedPerBlock
subspace: evm
value: '"850000"'
```

```sh theme={null}
seid q params subspace evm KeyMaxDynamicBaseFeeUpwardAdjustment

key: KeyMaxDynamicBaseFeeUpwardAdjustment
subspace: evm
value: '"0.007500000000000000"'
```

## Non-EVM transactions

On Sei, non-EVM transactions may update state that EVM transactions can
access. The simplest example is bank balances. Both native Cosmos bank send
transactions and EVM send transactions may update them. As a result, an
offchain application that parses only EVM transactions may find state changes
that it cannot attribute to any EVM transaction.

## EVM transaction envelope restrictions

On Sei, EVM transactions are carried inside a Cosmos transaction envelope. That envelope must not contain any Cosmos-specific fields. Tooling that builds raw transactions should know about these Sei-specific differences from a plain Ethereum transaction:

### No Cosmos wrapper fields on EVM transactions

An EVM transaction must not populate any of the Cosmos wrapper fields. If any of these fields are set, Sei rejects the transaction:

* `memo`
* `timeout_height`
* extension options (`extension_options` / `non_critical_extension_options`)
* `signer_infos`
* fee amount, fee `payer`, and fee `granter`
* top-level `signatures`

The EVM transaction's own signature (`v`, `r`, `s`) is inside the EVM payload itself, so the transaction does not need any of these Cosmos-level fields. Sei applies this check uniformly to all EVM transactions.

### Whole-block rejection on transaction decode failure

During proposal processing, Sei decodes every transaction in a proposed block. If any transaction fails to decode or panics during decode, Sei rejects the **entire block proposal**. It does not silently skip the offending transaction (treat it as nil) and continue with the rest of the block.

This also affects block gas accounting. A transaction that could not be decoded no longer contributes zero gas and gets skipped. Instead, its presence causes Sei to reject the block proposal outright.

<Warning>
  Make sure that your signing and broadcast tooling submits only transactions that decode cleanly. This is a consensus-level behavior change. A single undecodable transaction now invalidates the whole proposal. Tooling that produces malformed or non-canonical transactions can no longer rely on Sei to drop them individually from an otherwise-valid block.
</Warning>

### Rejection of bloated (non-canonical) transaction bodies

The transaction decoder rejects "bloated" transaction bodies. A bloated body has a raw protobuf wire encoding that is larger than the canonical re-marshal of the decoded body. The decoder rejects non-canonical encodings (for example, padded fields or an oversized `Any.Value`) with a decode error. This check has been enforced since v6.5.0.

<Warning>
  Make sure that your transaction-signing tooling produces a minimal, canonical envelope with no Cosmos wrapper fields populated.
</Warning>

## Finality

Sei has instant finality. A transaction is final as soon as its block is
committed (approximately 400 ms). This means that Ethereum's commitment levels
"safe", "latest", "justified", and "finalized" are all the same on Sei.

## Pending state

On Ethereum, the block proposer executes its proposed block first and updates
its local state. Then it broadcasts the proposal to others. The updated state
is marked "pending" until the node is accepted by other nodes.

However, on Sei, the block proposer broadcasts the proposal first. It executes
the proposal only if the proposal is accepted. This means that every node
executes the block at roughly the same time, so Sei does not have a window
when a "pending state" exists.

## Gas model & fees

Sei does not burn the base fee. All transaction fees go to validators. Fees are calculated as:

Transaction Fee = Gas Used × Gas Price

**Practical implications**

* Fee handling is simpler: use `gasPrice`, and you can omit `maxFeePerGas` and `maxPriorityFeePerGas`.
* Fees are more stable, because higher throughput reduces fee spikes during busy periods.
* Costs are typically lower. Many workloads that are costly on Ethereum become economical on Sei.

<Info>
  - **Does Sei burn a base fee (EIP‑1559)?** No.
  - **Who receives fees?** Validators.
  - **Are Sei fees lower?** Yes, because of higher throughput and parallel execution.
</Info>

## SSTORE gas cost

On Sei, the gas cost of the `SSTORE` opcode is a configurable on-chain parameter. A governance proposal can adjust it without a chain upgrade. This lets governance tune storage costs based on EVM state size and network conditions.

The `SSTORE` gas cost is currently set to the non-standard value of **72,000 gas**. This value is the same on Sei Mainnet and Sei Testnet. Governance [Proposal #109](https://seistream.app/proposals/109) ("Update EVM SSTORE set gas to 72000") set this value. The proposal changed the `evm` module parameter `KeySeiSstoreSetGasEIP2200` to `72000`.

The values below are read **live** from the Sei EVM:

<SstoreGasLive network="mainnet" />

To confirm the real cost yourself, make a live `eth_estimateGas` call against a Sei RPC. A Foundry `forge test --gas-report --fork-url <sei rpc>` report forks the chain *state*, but it applies revm's standard EVM gas schedule. As a result, it reports the Ethereum cost (approximately 22,100) instead of the Sei cost. The report is useful for relative profiling of your own logic, but not for the absolute storage-write cost.

<Info>Because the `SSTORE` gas cost is a governance-controlled parameter, a governance proposal may change this value in the future.</Info>

## ERC token standards compatibility

Sei EVM fully supports the common token standards:

* **ERC‑20** (fungible tokens)
* **ERC‑721** (NFTs)
* **ERC‑1155** (multi‑token)

Existing OpenZeppelin contracts and tools work unchanged.

## Testing & migration checklist

* Redeploy your Solidity code to Sei Testnet. Most contracts do not need changes.
* If you used SELFDESTRUCT, refactor it to a soft‑close pattern.
* Remove the EIP‑1559 fee complexity from your UI. Use a single `gasPrice` input in frontends.
* If you rely on on‑chain "randomness," integrate an oracle or VRF.
* Size your `gasLimit` with a modest buffer. Parallel execution can make estimates vary slightly.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.