> For the complete documentation index, see [llms.txt](https://docs.lighter.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.lighter.xyz/evm/interop/reading-core-from-evm.md).

# Reading Core from EVM

EVM contracts can read Core state synchronously through the `READ_CORE` [precompile](/evm/chain-info.md#precompiles). Each read completes within the calling transaction and returns its result directly.

For each EVM block, the sequencer selects one sealed Core block (called the **parent Core block**) and pins its post-execution state for all Core reads in that EVM block. This keeps read results consistent throughout the EVM block, even if the selected snapshot lags the Core tip.

The `READ_CORE` precompile charges 20,000 gas per call, plus any memory expansion costs.

## Execution

An EVM contract reads Core state by calling the `READ_CORE` [precompile](/evm/chain-info.md#precompiles) with an encoded query. The read completes synchronously and returns its result within the same call. Reads can also be evaluated off-chain through `eth_call`.

{% hint style="info" %}
**Note**

`eth_call`s that perform `READ_CORE` only succeed with the `latest` block tag. Support for earlier blocks is planned for an upcoming update.
{% endhint %}

Reads have no request ID, do not enter a queue, and require no destination transaction. They neither modify Core state nor record a request on Core.

Reads use the pinned snapshot rather than the latest Core state. Consequently:

* The same read in a later EVM block can return a different result if that block uses a newer Core snapshot.
* Reads do not reflect writes submitted earlier in the same EVM block, including within the same transaction.
* A [transaction-status read](#transaction-status) returns status `0` if the request was unprocessed in this Core snapshot, even if the Core tip has processed it since.

## Failures

A failed read consumes all gas forwarded to `READ_CORE` and returns no data. In Solidity, `call` and `staticcall` report the failure by returning `false`.

Reads fail for unsupported selectors, malformed input, insufficient gas, or unmet query requirements—for example, a requested account, asset, or market that does not exist.

## Supported reads

| Selector | Read                                        | Description                                                        |
| -------- | ------------------------------------------- | ------------------------------------------------------------------ |
| `0x0000` | [Transaction status](#transaction-status)   | Processing status and result of an EVM-initiated Core write.       |
| `0x0001` | [Account info](#account-info)               | Account identity, controlling addresses, and collateral.           |
| `0x0002` | [Core asset decimals](#core-asset-decimals) | Number of decimal places Core uses for an asset.                   |
| `0x0003` | [L1 token address](#l1-token-address)       | L1 token address associated with a Core asset.                     |
| `0x0004` | [EVM token address](#evm-token-address)     | EVM token address associated with a Core asset.                    |
| `0x0005` | [Market info](#market-info)                 | Market configuration, fees, and prices.                            |
| `0x0006` | [Spot balance](#spot-balance)               | Available and locked spot balances for an account and asset.       |
| `0x0007` | [Position](#position)                       | Position, margin, and order information for an account and market. |
| `0x0008` | [L1 account index](#l1-account-index)       | Core master account index for an L1 controlling address.           |
| `0x0009` | [EVM account index](#evm-account-index)     | Core master account index for an EVM controlling address.          |

Reads that take a controlling address resolve to its master account, so subaccounts cannot be read.

### Transaction status

Returns the processing status and result of an EVM-initiated Core write, identified by its request ID (`reqId`).

**Input**

```solidity
abi.encodePacked(uint16(0x0000), reqId)
```

| Type     | Field   | Description                           |
| -------- | ------- | ------------------------------------- |
| `uint64` | `reqId` | EVM-to-Core write request identifier. |

**Output**

```solidity
abi.encode(status, data)
```

| Type    | Field    | Description                                                  |
| ------- | -------- | ------------------------------------------------------------ |
| `uint8` | `status` | `0`: unprocessed; `1`: successful; `2`: failed.              |
| `bytes` | `data`   | Empty for status `0`; otherwise the write-specific response. |

Status `0` indicates that the request is either pending or has never been issued. Status `1` means the request has been successfully processed and status `2` indicates a failure.

Decode the response as `(uint8 status, bytes data)`.

* For status `0`, `data` is empty.
* For status `1`, the write type determines whether `data` contains a return value or is empty.
* For status `2`, `data` contains `abi.encode(uint32(errorCode))`.

### Account info

Returns information about a Core account identified by its controlling address and whether it is L1-controlled or EVM-controlled.

**Input**

```solidity
abi.encodePacked(uint16(0x0001), accountAddress, isL1Account)
```

| Type      | Field            | Description                                                                 |
| --------- | ---------------- | --------------------------------------------------------------------------- |
| `address` | `accountAddress` | Controlling address of the Core account.                                    |
| `bool`    | `isL1Account`    | `true` for an L1-controlled account; `false` for an EVM-controlled account. |

**Output**

```solidity
abi.encode(
    accountType,
    accountIndex,
    masterAccountIndex,
    l1Address,
    evmAddress,
    collateralBaseAmount
)
```

| Type      | Field                  | Description                                                                                                                                                                                                                                                                                                                                                                                             |
| --------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `uint8`   | `accountType`          | `0`: master account; `1`: subaccount; `2`: public pool; `3`: insurance fund.                                                                                                                                                                                                                                                                                                                            |
| `uint48`  | `accountIndex`         | Core account index.                                                                                                                                                                                                                                                                                                                                                                                     |
| `uint48`  | `masterAccountIndex`   | Controlling master account index.                                                                                                                                                                                                                                                                                                                                                                       |
| `address` | `l1Address`            | Stored L1 address; the zero address for an EVM-controlled account.                                                                                                                                                                                                                                                                                                                                      |
| `address` | `evmAddress`           | Stored EVM address; the zero address for an L1-controlled account.                                                                                                                                                                                                                                                                                                                                      |
| `int128`  | `collateralBaseAmount` | Shared USDC collateral, expressed as a signed amount in [Core USDC base units](/evm/interop/tokens/token-transfers.md#amounts). On a unified account, it includes USDC transferred on either [route](/evm/interop/tokens/token-transfers.md#routes) and can support both perpetuals and spot operations, subject to margin requirements. Excludes margin allocated to isolated positions. Rounded down. |

The call fails if the account does not exist in Core state. A system address's presence in the L1 bridge mapping does not make its Core system account accessible through this read.

### Core asset decimals

Returns the number of decimal places Core uses for the asset.

**Input**

```solidity
abi.encodePacked(uint16(0x0002), assetId)
```

| Type     | Field     | Description            |
| -------- | --------- | ---------------------- |
| `uint32` | `assetId` | Core asset identifier. |

**Output**

```solidity
abi.encode(decimals)
```

| Type    | Field      | Description                                       |
| ------- | ---------- | ------------------------------------------------- |
| `uint8` | `decimals` | Number of decimal places Core uses for the asset. |

The call fails if the asset does not exist.

### L1 token address

Returns the L1 token address associated with the Core asset.

**Input**

```solidity
abi.encodePacked(uint16(0x0003), assetId)
```

| Type     | Field     | Description            |
| -------- | --------- | ---------------------- |
| `uint32` | `assetId` | Core asset identifier. |

**Output**

```solidity
abi.encode(l1Token)
```

| Type      | Field     | Description                                                                               |
| --------- | --------- | ----------------------------------------------------------------------------------------- |
| `address` | `l1Token` | Associated L1 token address; `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` for native ETH. |

The call fails if the asset does not exist.

### EVM token address

Returns the EVM token address associated with the Core asset.

**Input**

```solidity
abi.encodePacked(uint16(0x0004), assetId)
```

| Type     | Field     | Description            |
| -------- | --------- | ---------------------- |
| `uint32` | `assetId` | Core asset identifier. |

**Output**

```solidity
abi.encode(evmToken)
```

| Type      | Field      | Description                                                                                                                                |
| --------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `address` | `evmToken` | Associated EVM token address; `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` for native ETH, and the zero address if no EVM token is linked. |

The call fails if the asset does not exist.

### Market info

Returns configuration, fees, and prices for the selected market.

**Input**

```solidity
abi.encodePacked(uint16(0x0005), marketId)
```

| Type     | Field      | Description                                                                                 |
| -------- | ---------- | ------------------------------------------------------------------------------------------- |
| `uint16` | `marketId` | Core market identifier. Perpetuals: `0 <= marketId < 255`; spot: `2048 <= marketId < 4095`. |

**Output**

```solidity
abi.encode(
    marketType,
    baseAssetId,
    quoteAssetId,
    takerFee,
    makerFee,
    minBaseAmount,
    minQuoteAmount,
    liquidationFee,
    indexPrice,
    markPrice
)
```

| Type     | Field            | Description                                                                                    |
| -------- | ---------------- | ---------------------------------------------------------------------------------------------- |
| `uint8`  | `marketType`     | `0`: perpetuals; `1`: spot.                                                                    |
| `uint32` | `baseAssetId`    | Base asset identifier of a spot market; `0` for perpetuals.                                    |
| `uint32` | `quoteAssetId`   | Quote asset identifier of a spot market; `0` for perpetuals.                                   |
| `uint32` | `takerFee`       | Upper bound on the taker fee rate: the market's maximum, in units of `10^-6` (`500` is 0.05%). |
| `uint32` | `makerFee`       | Upper bound on the maker fee rate: the market's maximum, in units of `10^-6`.                  |
| `uint64` | `minBaseAmount`  | Minimum order `amount`.                                                                        |
| `uint64` | `minQuoteAmount` | Minimum order value: `amount * price` must be at least this.                                   |
| `uint32` | `liquidationFee` | Liquidation fee rate in units of `10^-6`.                                                      |
| `uint64` | `indexPrice`     | Core index price; `0` for spot markets.                                                        |
| `uint64` | `markPrice`      | Core mark price; `0` for spot markets.                                                         |

Amounts and prices use the same market-specific scales as [`createOrder`](/evm/interop/message-passing/evm-and-core.md#create-order)'s `amount` and `price`. READ\_CORE does not return the decimals; read them from `GET /api/v1/orderBookDetails`.

The fee actually charged is at the sequencer's discretion. It depends on the account's fee tier and is always at most than `takerFee` and `makerFee`. Most of the time, it is substantially lower.

The call fails if the market does not exist.

### Spot balance

Returns the account's available and locked spot balances for the selected asset.

**Input**

```solidity
abi.encodePacked(uint16(0x0006), accountAddress, isL1Account, assetId)
```

| Type      | Field            | Description                                                                 |
| --------- | ---------------- | --------------------------------------------------------------------------- |
| `address` | `accountAddress` | Controlling address of the Core account.                                    |
| `bool`    | `isL1Account`    | `true` for an L1-controlled account; `false` for an EVM-controlled account. |
| `uint32`  | `assetId`        | Core asset identifier.                                                      |

**Output**

```solidity
abi.encode(availableBalance, lockedBalance)
```

| Type     | Field              | Description                                                                                                                                                                                                                                                                                                                         |
| -------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `int128` | `availableBalance` | Available balance held separately from the margin balance. A [unified account](/evm/interop/tokens/token-transfers.md#routes) keeps its USDC in the margin balance, so USDC reads as `0` here even after a `Spot`-route deposit; its shared USDC collateral is reported by `collateralBaseAmount` in [account info](#account-info). |
| `int128` | `lockedBalance`    | Balance locked in open orders.                                                                                                                                                                                                                                                                                                      |

Both balances are expressed in [Core base units](/evm/interop/tokens/token-transfers.md#amounts), the units used by [`baseAmount`](/evm/interop/tokens/token-transfers.md#amounts). One [base unit](/evm/interop/tokens/token-transfers.md#amounts) equals `tickSize` of the EVM token's smallest units. Divide the corresponding amount in EVM token units by `tickSize` and round down to obtain the Core balance. See [Amounts](/evm/interop/tokens/token-transfers.md#amounts) for the definition of `tickSize` and how to look it up.

The call fails if the account or asset does not exist.

### Position

Returns the account's position in the selected market.

**Input**

```solidity
abi.encodePacked(uint16(0x0007), accountAddress, isL1Account, marketId)
```

| Type      | Field            | Description                                                                                                                                                                 |
| --------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `address` | `accountAddress` | Controlling address of the Core account.                                                                                                                                    |
| `bool`    | `isL1Account`    | `true` for an L1-controlled account; `false` for an EVM-controlled account.                                                                                                 |
| `uint16`  | `marketId`       | Core market identifier. Perpetuals: `0 <= marketId < 255`; spot: `2048 <= marketId < 4095`. Spot markets have no positions, so a spot `marketId` returns an empty position. |

**Output**

```solidity
abi.encode(
    lastFundingRatePrefixSum,
    position,
    entryQuote,
    initialMarginFraction,
    totalOrderCount,
    totalPositionTiedOrderCount,
    marginMode,
    allocatedMargin
)
```

| Type     | Field                         | Description                                                                                                                                                                                            |
| -------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `int64`  | `lastFundingRatePrefixSum`    | Cumulative funding rate last recorded for the position.                                                                                                                                                |
| `int64`  | `position`                    | Signed position size, on the same scale as [`createOrder`](/evm/interop/message-passing/evm-and-core.md#create-order)'s `amount`. Positive for long, negative for short; magnitude at most `2^56 - 1`. |
| `uint56` | `entryQuote`                  | Unsigned value of the position at entry, in USDC base units (`10^6` per USDC).                                                                                                                         |
| `uint16` | `initialMarginFraction`       | Fraction of the position value required as initial margin, in units of `10^-4` (`500` is 5%). `0` means the market's default.                                                                          |
| `uint64` | `totalOrderCount`             | Number of orders for the position.                                                                                                                                                                     |
| `uint64` | `totalPositionTiedOrderCount` | Number of orders tied to the position.                                                                                                                                                                 |
| `uint8`  | `marginMode`                  | `0`: cross; `1`: isolated.                                                                                                                                                                             |
| `int128` | `allocatedMargin`             | Allocated margin in Core's extended USDC units, which use 12 decimal places (10^12 units per USDC).                                                                                                    |

The call fails if the account or market does not exist.

### L1 account index

Resolves an L1 controlling address to its Core master account index.

**Input**

```solidity
abi.encodePacked(uint16(0x0008), l1Address)
```

| Type      | Field       | Description                         |
| --------- | ----------- | ----------------------------------- |
| `address` | `l1Address` | Controlling address on Ethereum L1. |

**Output**

```solidity
abi.encode(accountIndex)
```

| Type     | Field          | Description                                                                                                                             |
| -------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `uint48` | `accountIndex` | Core master account index for the supplied address. Read from Core's view of the L1 bridge mapping, `addressToAccountIndex[l1Address]`. |

The call fails if the account does not exist in Core state. A system address's presence in the L1 bridge mapping does not make its Core system account accessible through this read or the [account-info read](#account-info).

### EVM account index

Resolves an EVM controlling address to its Core master account index.

**Input**

```solidity
abi.encodePacked(uint16(0x0009), accountAddress)
```

| Type      | Field            | Description                         |
| --------- | ---------------- | ----------------------------------- |
| `address` | `accountAddress` | Controlling address on Lighter EVM. |

**Output**

```solidity
abi.encode(accountIndex)
```

| Type     | Field          | Description                                                                                        |
| -------- | -------------- | -------------------------------------------------------------------------------------------------- |
| `uint48` | `accountIndex` | Core master account index for the supplied address. Read from `evmAccountMapping[accountAddress]`. |

The call fails if the account does not exist in Core state.

## Example: reading a spot balance

The following contract reads a Core spot balance.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract CoreReader {
    address constant READ_CORE = 0x6600000000000000000000000000000000000000;

    function spotBalance(
        address accountAddress,
        bool isL1Account,
        uint32 assetId
    ) external view returns (int128 availableBalance, int128 lockedBalance) {
        (bool success, bytes memory result) = READ_CORE.staticcall(
            abi.encodePacked(uint16(0x0006), accountAddress, isL1Account, assetId)
        );
        require(success, "Core balance read failed");
        return abi.decode(result, (int128, int128));
    }
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.lighter.xyz/evm/interop/reading-core-from-evm.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
