> ## Documentation Index
> Fetch the complete documentation index at: https://docs.privy.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Trade on Lighter

> Use Privy wallets to create a Lighter account, fund it, register a trading API key, and place perpetual futures orders.

[Lighter](https://lighter.xyz/) is a high-performance, zk-based orderbook exchange for perpetual futures. It settles on Ethereum with a validity-proof rollup, offering low fees and verifiable execution.

This guide shows how to use Privy wallets with Lighter: owning a user's Lighter account, registering a trading API key on-chain, funding the account, and placing orders.

## How Lighter differs from a typical EVM integration

Unlike most exchanges, Lighter separates authority into two layers, and it's important to understand which key does what before you start:

* **L1 account owner (the Privy wallet).** A standard Ethereum address. This wallet owns the Lighter account and signs every on-chain action: registering a trading API key (`changePubKey`), deposits, and withdrawals. All L1 interactions can be sponsored with native [gas sponsorship](/wallets/gas-and-asset-management/gas/overview).
* **L2 trading API key (a Lighter keypair).** Use Lighter API keys to sign and submit orders directly to the order book. Lighter signs orders with a separate API key using its own signature scheme. This key is generated by the Lighter SDK and managed by your application.

<Note>
  A Privy embedded or server wallet cannot produce Lighter's L2 order signatures — that scheme is
  not ECDSA. Use the Privy embedded wallet to authorize the trading API key on-chain. Your
  application holds the Lighter API key that signs orders, and Privy never has to expose a raw
  private key to do so.
</Note>

This guide shows how to:

* Create a Lighter account
* Add funds to the Lighter account
* Register a Lighter trading API key
* Sign and submit trades to the Lighter order book

## Prerequisites

Before you begin, make sure you have:

* A [Privy app](https://dashboard.privy.io) with [gas sponsorship enabled](/wallets/gas-and-asset-management/gas/setup). Lighter's contract is on **Ethereum mainnet**, so sponsor there (or fund the wallet with ETH for gas).
* Python 3.10+.
* The Lighter contract address on Ethereum mainnet: `0x3B4D794a66304F130a4Db8F2551B0070dfCf5ca7`.

## Installation

```bash theme={"system"}
pip install privy-client git+https://github.com/elliottech/lighter-python.git web3 requests
```

This guide is Python throughout: Privy's on-chain steps use the [Privy Python SDK](https://github.com/privy-io/python-sdk), and Lighter ships its order signer for Python and Go but not JavaScript.

## 1. Create the account owner wallet

Create the Ethereum wallet that will own the Lighter account.

```python theme={"system"}
from privy import PrivyAPI

privy = PrivyAPI(app_id='insert-your-app-id', app_secret='insert-your-app-secret')

wallet = privy.wallets.create(chain_type='ethereum')
owner_address = wallet.address
```

## 2. Fund the account

To activate a Lighter account, deposit USDC directly into the Privy wallet. The minimum direct deposit is **1 USDC**. USDC on Ethereum mainnet is `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48`.

A deposit is two ordinary transactions signed by the Privy wallet: an ERC-20 `approve` to the Lighter contract, then `deposit(to, assetIndex, routeType, amount)` with `routeType = 0` for the perps account.

```python theme={"system"}
from web3 import Web3

LIGHTER = Web3.to_checksum_address('0x3B4D794a66304F130a4Db8F2551B0070dfCf5ca7')
USDC = Web3.to_checksum_address('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48')
ETHEREUM = 'eip155:1'

w3 = Web3(Web3.HTTPProvider('https://your-ethereum-rpc-url'))
amount = 5 * 10**6  # 5 USDC (6 decimals)

erc20 = w3.eth.contract(abi=[{
    'name': 'approve', 'type': 'function', 'stateMutability': 'nonpayable',
    'inputs': [{'name': 'spender', 'type': 'address'}, {'name': 'amount', 'type': 'uint256'}],
    'outputs': [{'name': '', 'type': 'bool'}],
}])
lighter = w3.eth.contract(address=LIGHTER, abi=[
    {
        'name': 'deposit', 'type': 'function', 'stateMutability': 'payable',
        'inputs': [
            {'name': '_to', 'type': 'address'}, {'name': '_assetIndex', 'type': 'uint16'},
            {'name': '_routeType', 'type': 'uint8'}, {'name': '_amount', 'type': 'uint256'},
        ], 'outputs': [],
    },
    {
        'name': 'tokenToAssetIndex', 'type': 'function', 'stateMutability': 'view',
        'inputs': [{'name': '', 'type': 'address'}], 'outputs': [{'name': '', 'type': 'uint16'}],
    },
])

# Read USDC's asset index from the Lighter contract
usdc_asset_index = lighter.functions.tokenToAssetIndex(USDC).call()

def send_tx(to, data):
    # Sign and broadcast an EVM transaction from the Privy wallet, with gas sponsored.
    return privy.intents.rpc(
        wallet.id,
        method='eth_sendTransaction',
        caip2=ETHEREUM,
        sponsor=True,
        params={'transaction': {'to': to, 'data': data}},
    )

# 1. Approve, then 2. Deposit into the perps account (routeType 0)
send_tx(USDC, erc20.encode_abi('approve', args=[LIGHTER, amount]))
send_tx(LIGHTER, lighter.encode_abi('deposit', args=[owner_address, usdc_asset_index, 0, amount]))
```

<Note>
  Ethereum mainnet gas can be significant. For cheaper funding from Arbitrum, Base, and other
  chains, Lighter also supports deposits through the Fun.xyz Universal Deposit Address — see the
  [deposits guide](https://apidocs.lighter.xyz/docs/deposits-transfers-and-withdrawals). API-key
  registration in the next step is always a one-time mainnet transaction.
</Note>

## 3. Register a trading API key

Generate a Lighter API keypair with the SDK, then register its public key on-chain with `changePubKey`, signed by the Privy wallet. The signature scheme means the key is registered through the contract directly rather than handing a raw private key to the SDK — the recommended path when the account owner is a smart-contract or multi-sig wallet.

First, find the account index (assigned when the account was funded) and generate the keypair:

```python theme={"system"}
import lighter, requests

# Look up the account index for the L1 address via Lighter's API
resp = requests.get(
    'https://mainnet.zklighter.elliot.ai/api/v1/accountsByL1Address',
    params={'l1_address': owner_address},
).json()
account_index = resp['sub_accounts'][0]['index']

# Generate a Lighter API keypair (this does NOT need the Ethereum key)
api_private_key, api_public_key, err = lighter.create_api_key()
if err is not None:
    raise RuntimeError(err)

# Store api_private_key securely — your application signs orders with it.
```

Then register the public key on-chain from the Privy wallet. `changePubKey(accountIndex, apiKeyIndex, pubKey)` must be sent by the L1 address that owns the account (the Privy wallet). API key indices `2`–`254` are available (`0`–`1` are reserved).

```python theme={"system"}
API_KEY_INDEX = 2

change_pub_key = w3.eth.contract(abi=[{
    'name': 'changePubKey', 'type': 'function', 'stateMutability': 'nonpayable',
    'inputs': [
        {'name': '_accountIndex', 'type': 'uint48'},
        {'name': '_apiKeyIndex', 'type': 'uint8'},
        {'name': '_pubKey', 'type': 'bytes'},
    ], 'outputs': [],
}])

pub_key_bytes = bytes.fromhex(api_public_key.removeprefix('0x'))
send_tx(LIGHTER, change_pub_key.encode_abi(
    'changePubKey', args=[account_index, API_KEY_INDEX, pub_key_bytes]
))
```

<Warning>
  Keep `api_private_key` server-side and out of source control. It can place and cancel orders on
  the account, but it cannot move funds — deposits and withdrawals still require the Privy-owned L1
  wallet.
</Warning>

## 4. Place an order

With the API key registered, sign and submit orders using the Lighter `SignerClient`. This uses the API key, not the Privy wallet.

```python theme={"system"}
import asyncio
import lighter

BASE_URL = 'https://mainnet.zklighter.elliot.ai'


async def main():
    client = lighter.SignerClient(
        url=BASE_URL,
        account_index=account_index,
        api_private_keys={API_KEY_INDEX: api_private_key},
    )

    # Place a limit buy order
    created_order, api_response, err = await client.create_order(
        market_index=0,          # e.g. 0 = BTC perp
        client_order_index=0,    # your own client-side id
        base_amount=100,         # size, in the market's base units
        price=95000,             # limit price, in the market's price units
        is_ask=False,            # False = buy, True = sell
        order_type=lighter.SignerClient.ORDER_TYPE_LIMIT,
        time_in_force=lighter.SignerClient.ORDER_TIME_IN_FORCE_GOOD_TILL_TIME,
    )
    if err is not None:
        raise RuntimeError(err)


asyncio.run(main())
```

<Note>
  `base_amount` and `price` are integers scaled by each market's size and price decimals. Fetch
  market metadata (decimals, indices) from Lighter's `orderBookDetails` endpoint before placing
  orders. See the [trading guide](https://apidocs.lighter.xyz/docs/trading) for order types and
  time-in-force options.
</Note>

## Withdrawing

Withdrawals return funds to the account owner and are authorized by the Privy L1 wallet, either through the contract's `withdraw` function or Lighter's fast-withdraw flow (min 4 USDC). See the [withdrawals guide](https://apidocs.lighter.xyz/docs/deposits-transfers-and-withdrawals).

## Resources

<CardGroup cols={3}>
  <Card title="Lighter API Docs" icon="arrow-up-right-from-square" href="https://apidocs.lighter.xyz/docs/partner-integration" arrow>
    Lighter's partner integration, trading, and deposit documentation.
  </Card>

  <Card title="Lighter Python SDK" icon="arrow-up-right-from-square" href="https://github.com/elliottech/lighter-python" arrow>
    The signer client, API-key generation, and order examples.
  </Card>

  <Card title="EVM Transactions with Privy" icon="arrow-up-right-from-square" href="/wallets/using-wallets/ethereum/send-a-transaction" arrow>
    Learn how to send EVM transactions using Privy wallets.
  </Card>
</CardGroup>

## Why use Privy with Lighter?

* **Security**: The account owner's private key never leaves Privy's secure infrastructure.
* **Multi-sig ready**: On-chain registration via `changePubKey` works for smart-contract and multi-sig owners, no raw key required.
* **Simplicity**: No key storage or rotation to manage for the account owner.
* **Gas sponsorship**: Sponsor account setup, deposits, and withdrawals so users never hold ETH.

<Check>You're ready to build trading applications on Lighter with Privy.</Check>
