L1 and Core

Transfers between Ethereum L1 and Core move ETH or an asset with an active L1 representation. For an L1-native asset, this path becomes available after Core registration. For an EVM-native asset, its L1 wrapper must also be enabled. Core-native assets cannot be transferred to L1.

See Token linking for setup and amounts and routes for Core transfer conventions.

L1 to Core

Call L1InteropManager.sendToCore(...) on L1. The recipient is a Core master account identified by its controlling L1 address. If it does not exist, the deposit path allocates the account index and Core creates the account when processing the deposit.

function sendToCore(
    uint32 assetIndex,
    address to,
    uint256 amount,
    RouteType routeType
) external payable;

amount is in the L1 token's smallest units and must be a nonzero multiple of the asset's L1 tickSize. Read the L1 configuration from L1InteropManager.getAssetConfig(assetIndex). The deposit credits amount / tickSize Core base units to the selected perps or spot route, subject to Core acceptance.

  1. For an ERC-20, approve L1InteropManager to spend amount of the configured L1 token.
  2. Call sendToCore(...) with the recipient's controlling L1 address. For ETH, use assetIndex = 1 and send exactly amount as msg.value. For an ERC-20, send no ETH with the call.
  3. Confirm the deposit's processing and credited amount in Core. A successful L1 receipt only confirms submission.

L1-native tokens are escrowed on L1. An EVM-native asset's L1 wrapper is burned through its selected mint gateway. L1InteropManager submits the deposit through L1CoreMessaging; applications do not call registerDeposit(...) directly.

This deposit path targets L1-controlled masters, not subaccounts or EVM-controlled masters. Use a supported internal Core transfer to move funds into a subaccount after depositing.

Unaccepted deposits

If Core does not accept the full deposit, the unaccepted amount is returned to the original deposit destination through a Core-originated L1 Call. It belongs to to, which may differ from the address that paid for the deposit. Follow Core message execution on L1 to complete delivery once the call is ready.

Core to L1

Initiating a Core withdrawal

A withdrawal to L1 can be initiated in three ways, depending on the account's controller.

  • From Core. Submit one of the following signed transactions.

    • Withdraw (txType = 13). L1-controlled Core accounts can withdraw to their controlling L1 address using only an API-key signature. No controller ECDSA signature is required.
    • Withdraw to L1 Address (txType = 132). L1-controlled or EVM-controlled Core accounts can specify an L1 recipient. This requires both an API-key signature and the EOA controller's ECDSA signature, even when withdrawing to the controller's own address.
  • From L1. The controlling L1 address calls L1CoreMessaging.withdraw(...) to withdraw to itself, or L1CoreMessaging.withdrawToL1Address(...) to specify a recipient.

  • From EVM. The controlling EVM address calls EvmToCoreEntrypoint.withdrawToL1Address(...).

A contract controller cannot supply an ECDSA signature and must use its native-domain call for the explicit-recipient option. The debit account may be the controller's master account or one of its subaccounts, subject to Core authorization.

Finalizing a Core withdrawal

Once Core accepts the withdrawal and its batch has been executed on L1, follow Executing Core messages on L1 to retrieve the call data and execute the call.


Did this page help you?