> 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/message-passing/l1-and-core.md).

# L1 and Core

The L1 bridge [`ZkLighter`](https://github.com/elliottech/lighter-contracts/blob/lighter-evm-devnet/contracts/ZkLighter.sol) intermediates messaging between L1 and Core.

Arbitrary cross-domain messaging is not supported. The protocol defines a fixed set of messages that can be sent between L1 and Core.

## L1 to Core

L1 accounts can request actions on Core, such as placing orders or transferring tokens. Each request is submitted to a priority queue on L1 and processed asynchronously by the Core sequencer in first-in, first-out order.

Two L1 contracts provide access to these requests.

* [`L1CoreMessaging`](https://github.com/elliottech/lighter-contracts/blob/lighter-evm-devnet/contracts/messaging/L1CoreMessaging.sol) exposes all supported L1-to-Core writes. Some methods are restricted to [`L1InteropManager`](https://github.com/elliottech/lighter-contracts/blob/lighter-evm-devnet/contracts/interop/L1InteropManager.sol) or governance.
* [`L1InteropManager`](https://github.com/elliottech/lighter-contracts/blob/lighter-evm-devnet/contracts/interop/L1InteropManager.sol) handles token-specific logic and permissions before calling the restricted [`L1CoreMessaging`](https://github.com/elliottech/lighter-contracts/blob/lighter-evm-devnet/contracts/messaging/L1CoreMessaging.sol) methods. See [Token transfers](/evm/interop/tokens/token-transfers/l1-and-core.md) and [Token linking](/evm/interop/tokens/token-linking.md) for those flows.

![L1-to-Core request flow showing L1CoreMessaging, ZkLighter, the L1 priority queue, and asynchronous Core processing, with separate Ethereum L1 and Lighter Core domains.](https://1283879166-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNb0n4Ug3DwUnIWDRnc85%2Fuploads%2Fgit-blob-3604ab9b3eaa1e5f4c5b4587571bbe270cef684f%2Fl1-to-core-write-dark-af9befde.svg?alt=media)

Every request ultimately passes through [`ZkLighter.addPriorityRequestExt(...)`](https://github.com/elliottech/lighter-contracts/blob/lighter-evm-devnet/contracts/ZkLighter.sol). This is the bridge's general mechanism for adding Core priority requests, but it accepts calls only from [`L1CoreMessaging`](https://github.com/elliottech/lighter-contracts/blob/lighter-evm-devnet/contracts/messaging/L1CoreMessaging.sol). Thus, users can only submit supported operations to Core rather than engaging in arbitrary messaging.

L1-controlled Core accounts can use this priority queue to bypass censorship of transactions submitted directly to Core. The Core sequencer is obligated to process these requests. If the oldest pending request remains unfulfilled past its 14-day expiration, anyone can activate the [escape hatch](/evm/technical-architecture.md#escape-hatch), allowing L1-controlled accounts to exit their balances on L1.

For EVM-controlled Core accounts, circumvention of sequencer downtime or censorship is covered in [L1 and EVM message passing](/evm/interop/message-passing/l1-and-evm.md#circumventing-core-sequencer-censorship-for-evm-controlled-core-accounts).

### Submitting a priority request to Core

Submit a request to Core through the appropriate L1 contract introduced above. To authorize operations on an existing account, [`L1CoreMessaging`](https://github.com/elliottech/lighter-contracts/blob/lighter-evm-devnet/contracts/messaging/L1CoreMessaging.sol) resolves the caller's L1-controlled master account and includes its index in the request. The same address on Lighter EVM does not authorize an L1-controlled account, or vice versa. See [Accounts](/evm/interop/accounts.md).

If the L1 call reverts, no request is submitted. A successful L1 transaction confirms only submission, not successful execution on Core. Since submission and fulfillment are not atomic, a failure on Core does not revert the initiating L1 transaction.

[`GET /api/v1/txFromL1TxHash?hash=...`](https://docs.lighter.xyz/api/transactions) returns the Core transaction for an L1 transaction hash. Core includes every priority request, so `status` is `3` once Core has processed the request, whether or not the operation succeeded. The outcome is the `ae` field of `event_info`: both are JSON strings, and `ae` is empty on success. On failure it holds a [Core error code](https://docs.lighter.xyz/developers/reference/data-structures-constants-and-errors):

```json
{
  "status": 3,
  "event_info": "{\"a\":4,\"f\":0,\"ti\":0,\"ae\":\"{\\\"code\\\":21128,\\\"message\\\":\\\"invalid master account index\\\"}\"}"
}
```

`L1CoreMessaging` does not check that the caller controls the target `accountIndex`; Core does. The request above targeted an account under another master account, so L1 accepted it and Core rejected it with `21128`.

If Core processing produces an outgoing message, track that delivery separately. For example, [`L1CoreMessaging.sendToEvm(...)`](https://github.com/elliottech/lighter-contracts/blob/lighter-evm-devnet/contracts/messaging/L1CoreMessaging.sol) requests a debit on Core, which then schedules a transfer to EVM. See [L1-initiated send to EVM](/evm/interop/tokens/token-transfers/evm-and-core.md#l1-initiated-send-to-evm) for the full flow.

### Supported requests

Users can directly call the following methods on [`L1CoreMessaging`](https://github.com/elliottech/lighter-contracts/blob/lighter-evm-devnet/contracts/messaging/L1CoreMessaging.sol) to submit account operations.

| Method                     | Requested Core operation                                                                                                              |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `changePubKey(...)`        | Register or replace an API key.                                                                                                       |
| `createOrder(...)`         | Reduce or close a perps position: Core runs it as a reduce-only, immediate-or-cancel order.                                           |
| `cancelAllOrders(...)`     | Cancel the account's orders.                                                                                                          |
| `burnShares(...)`          | Redeem public-pool shares.                                                                                                            |
| `withdraw(...)`            | Initiate a [withdrawal to L1](/evm/interop/tokens/token-transfers/l1-and-core.md#core-to-l1).                                         |
| `withdrawToL1Address(...)` | Initiate a [withdrawal to a specified L1 recipient](/evm/interop/tokens/token-transfers/l1-and-core.md#initiating-a-core-withdrawal). |
| `sendToEvm(...)`           | Initiate a [transfer from Core to EVM](/evm/interop/tokens/token-transfers/evm-and-core.md#l1-initiated-send-to-evm).                 |

The following methods accept calls only from [`L1InteropManager`](https://github.com/elliottech/lighter-contracts/blob/lighter-evm-devnet/contracts/interop/L1InteropManager.sol).

| Method                                                                                                        | Requested Core operation                                                                                                                            |
| ------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `registerDeposit(...)`                                                                                        | Credit an [L1 deposit](/evm/interop/tokens/token-transfers/l1-and-core.md#l1-to-core).                                                              |
| `registerL1NativeAssetOnCore(...)`, `registerEvmNativeAssetOnCore(...)`, `registerCoreNativeAssetOnCore(...)` | Register an asset on Core. See [Registering on Core](/evm/interop/tokens/token-linking.md#registering-on-core) for L1-native and EVM-native assets. |
| `finalizeEvmWrapperLink(...)`                                                                                 | Record the [EVM wrapper](/evm/interop/tokens/token-linking.md#enable-an-evm-wrapper-for-an-l1-native-asset) for an L1-native asset.                 |
| `finalizeL1WrapperLink(...)`                                                                                  | Record the [L1 wrapper](/evm/interop/tokens/token-linking.md#enable-an-l1-wrapper-for-an-evm-native-asset) for an EVM-native asset.                 |

[`L1CoreMessaging`](https://github.com/elliottech/lighter-contracts/blob/lighter-evm-devnet/contracts/messaging/L1CoreMessaging.sol) also exposes `setSystemConfig(...)`, `updateAsset(...)`, `createMarket(...)`, and `updateMarket(...)` for governance-authorized callers. These submit protocol-configuration requests through the same queue.

## Core to L1

Core emits [**L1 Calls**](/evm/interop/message-passing.md) in the following cases.

* Processing [withdrawals to L1](/evm/interop/tokens/token-transfers/l1-and-core.md#core-to-l1).
* Returning [unaccepted L1 deposit amounts](/evm/interop/tokens/token-transfers/l1-and-core.md#unaccepted-deposits).
* Confirming an [EVM-native token link](/evm/interop/tokens/token-linking.md#linking-the-canonical-token).

These **L1 Calls** are included in a batch. Once that batch has been [executed on L1](/evm/technical-architecture.md#batch-lifecycle-and-finalization), anyone can call the bridge to execute them.

For Core-originated **L1 Calls**, `l2Sender` is always the [Core system address](/evm/chain-info.md#system-addresses).

### Executing Core messages on L1

Once the batch containing the call has been executed on L1, retrieve the call data from Core using `GET /api/v1/coreL1Call?tx_hash=...`. Set `CORE_API_URL` to your network's Core API URL and `CORE_TX_HASH` to the hash of the Core transaction that generated the call.

For operations initiated on L1 or EVM, obtain `CORE_TX_HASH` as follows.

* **From L1.** Look up the initiating L1 transaction with [`GET /api/v1/txFromL1TxHash?hash=...`](https://docs.lighter.xyz/api/transactions) and use the returned Core transaction's `hash` field.
* **From EVM.** [Derive the Core transaction hash](/evm/interop/message-passing/evm-and-core.md#core-transaction-hash) from the request's `WriteToCore` event.

{% code title="Request" %}

```bash
curl --get "$CORE_API_URL/api/v1/coreL1Call" \
  --data-urlencode "tx_hash=$CORE_TX_HASH" | jq
```

{% endcode %}

{% code title="Response (example)" %}

```json
{
  "code": 200,
  "call": {
    "l2_sender": "0x7fffffffffffffffffffffffffffffffffffffff",
    "target": "0x...",
    "value": "0",
    "msg_nonce": "42",
    "calldata": "0x...",
    "l1_call_hash": "0x..."
  }
}
```

{% endcode %}

The response's `call` object contains the arguments needed to execute the **L1 Call** through [`ZkLighter.executeCoreL1Call(...)`](https://github.com/elliottech/lighter-contracts/blob/lighter-evm-devnet/contracts/ZkLighter.sol). Submit them once the batch has been executed on L1.

Call data may be available before batch execution. The API does not report whether the **L1 Call** has already been executed.

```solidity
function executeCoreL1Call(
    address _l2Sender,
    address to,
    uint256 value,
    uint256 msgNonce,
    bytes calldata data
) external;
```

The bridge checks that the call belongs to an executed batch and has not already been executed.

During execution, the target can read the authenticated cross-domain sender through the bridge's `l2Sender()` function. To authenticate a Core-originated **L1 Call**, the target **MUST** check the following.

* `msg.sender` is the address of the [`ZkLighter`](https://github.com/elliottech/lighter-contracts/blob/lighter-evm-devnet/contracts/ZkLighter.sol) bridge.
* `ZkLighter.l2Sender()` equals the [Core system address](/evm/chain-info.md#system-addresses).

If `executeCoreL1Call(...)` fails, it can be retried. Once it succeeds, the same **L1 Call** cannot be executed again. The transaction sender pays the L1 gas fees but cannot alter the message itself.


---

# 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/message-passing/l1-and-core.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.
