Token transfers

This section covers how to transfer assets between Ethereum L1, Lighter EVM, and Lighter Core. These transfers build on the cross-domain pathways introduced in Message passing.

Transfers to and from Core

The following conventions apply to transfers between EVM and Core and L1 and Core.

Supported assets

Every asset on Core is identified by a uint32 assetIndex.

Transfers to and from Core support the following asset types.

  • ETH. ETH uses assetIndex = 1 and is transferred as the native currency on L1 and Lighter EVM.
  • ERC-20 tokens. The asset must be registered on Core and linked on the relevant non-Core domain. See Token linking.

If a Core asset has representations on both L1 and Lighter EVM, the protocol assumes they use the same number of decimals.

The following assets are currently registered on Core.

AssetassetIndexL1 / EVM decimalstickSizeL1 addressEVM address
ETH11810^10Not applicableNot applicable
LIT21810^100x24734C47a5967b3ab43eC137909BcF72593E65E8Not linked
USDC3610xb90a9f16ddf0AE8054d53AF5C8b559a19741991F0xf2A5728d366c6d0f764Af612cD47F3608E2B4d5B

Amounts

Core tracks balances in base units. During asset registration, the protocol records a tickSize for the Core asset, which specifies how many of the token's smallest units on L1 or Lighter EVM correspond to one Core base unit.

An asset's tickSize can be read from L1InteropManager.getAssetConfig(assetIndex). If the asset is linked on EVM, EVM contracts can also read it from EvmInteropManager.getAssetConfig(assetIndex). The two calls return:

enum CanonicalDomain { None, L1, Core, EVM }

// L1InteropManager.getAssetConfig(uint32 assetIndex)
struct CoreAssetL1Config {
    CanonicalDomain canonicalDomain;
    address l1Token;
    address coreTokenAdmin;
    uint56 extensionMultiplier;
    uint128 tickSize;
    address l1Gateway;
}

// EvmInteropManager.getAssetConfig(uint32 assetIndex)
struct CoreAssetEvmConfig {
    CanonicalDomain canonicalDomain;
    address evmToken;
    address evmGateway;
    uint128 tickSize;
}

Convert from the token's smallest units to Core base units with baseAmount = amount / tickSize, and back with amount = baseAmount * tickSize.

As an example, ETH has tickSize = 10^10 wei, so transferring 1 ETH (10^18 wei) corresponds to 10^8 Core base units.

Routes

A route names the Core balance that a transfer uses: Perps for collateral in perpetuals markets, or Spot for the balance used in spot markets. Transfers involving Core specify a route. A transfer to Core credits the selected route, and a transfer from Core debits it.

New Core master accounts, including every account created through Lighter EVM, are unified trading accounts. A unified account keeps its USDC in one shared margin balance, so both routes credit and debit the same USDC. The account-info read reports this shared USDC collateral as collateralBaseAmount. It is not reserved exclusively for perpetuals and can also support spot operations, subject to margin requirements.

A USDC deposit through the Spot route can therefore leave the spot-balance read at zero while collateralBaseAmount increases. The spot read alone does not capture all funds usable for spot operations, and the shared collateral is not necessarily all available to spend.

Other assets enabled as margin for a unified account also prioritize the margin balance. Incoming amounts that exceed the remaining per-account or global supply cap stay in the separate spot balance. Enabling margin for an asset reallocates its existing spot balance in the same way, subject to those caps. USDC has no supply cap, and switching an account to unified mode moves all existing spot USDC into the margin balance.

The Perps route accepts an asset other than USDC only if the asset is enabled as margin for the account. ETH is currently not enabled as margin, so send ETH on the Spot route: an ETH deposit on the Perps route is refunded in full.

Core's account API reports an account's mode as account_trading_mode: 0 for classic, 1 for unified. A classic account keeps separate perps and spot balances.

The RouteType enum is ABI-encoded as uint8.

enum RouteType {
    Perps, // 0
    Spot   // 1
}

Did this page help you?