Skip to content

dynamic-labs-oss/python-lighter-demo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Dynamic × Lighter compatibility demo

A single Python script that proves a Dynamic server wallet can drive the Lighter chain flow which requires an L1 signature — registering an L2 API key (ChangePubKey).

Lighter's other flows need nothing more than an L2 key and an /api/v1/sendTx call, so once this one works, the rest follows: deposits are plain ERC-20 transfers on the EVM chain that the Dynamic wallet can do natively, and withdrawals / orders / transfers use the L2 key this script registered.

What this shows

  1. Create or load a Dynamic EVM server wallet (MPC — no raw key anywhere).
  2. Dynamic signs a plain demo message — the simplest compatibility check.
  3. Look up the wallet's Lighter account by L1 address.
  4. Generate an L2 API key in lighter-python's native signer.
  5. Ask the signer for the ChangePubKey messageToSign, sign it with Dynamic (DynamicEvmWalletClient.sign_message — EIP-191 personal_sign via MPC), splice the signature into tx_info.L1Sig, and POST /sendTx.
  6. Exercise the just-registered L2 key with a 0.01 USDC self-transfer (perp → spot), an L2-only call requiring no L1 signature.

Step 5 is the only step where Lighter cares about the L1 key holder, and Dynamic's signature is bit-identical to what eth_account.Account.sign_message would produce from a raw key — so lighter-python's signer accepts it.

Setup

Run from inside examples/python-lighter-demo/ with Python 3.11+:

cd examples/python-lighter-demo
python3.11 -m venv .venv
source .venv/bin/activate
pip install -e .

cp .env.example .env
# fill in DYNAMIC_API_TOKEN and DYNAMIC_ENV_ID

Prerequisite: the L1 address must already have a Lighter account. If not, bridge a small amount of USDC to it via app.lighter.xyz (or testnet) first — the account is created on first deposit.

Run

lighter-demo
# or: python3 main.py

Expected output:

[1] Created Dynamic wallet (ephemeral): 0x...
[2] Dynamic signed 'Hello from Dynamic! ...'
    → 0x...
[3] Lighter accountIndex: 12345  (https://testnet.app.lighter.xyz/account/12345)
[4] New L2 API key for slot 3
[5] ChangePubKey accepted: 0x...
    → https://testnet.zklighter.elliot.ai/api/v1/tx?by=hash&value=0x...
[6] Self-transfer 0.01 USDC perp→spot: 0x...
    → https://testnet.zklighter.elliot.ai/api/v1/tx?by=hash&value=0x...

Dynamic × Lighter: compatible ✓

Set DYNAMIC_WALLET_ADDRESS in .env to reuse an existing wallet across runs instead of creating a fresh one each time.

Security considerations

  • The L2 API key is generated in-process and discarded when the script exits. Re-running this rotates it (ChangePubKey invalidates the prior key at the same slot).
  • API_KEY_INDEX = 3 — do not use slot 0 in production, it's reserved for the main Lighter web app session.
  • The L1 signature is scoped by Lighter's chain id (300 testnet / 304 mainnet) inside messageToSign, so testnet signatures can't be replayed on mainnet.
  • Dynamic's MPC never exposes the raw private key to this process — the signature comes back from sign_message already assembled.
  • No secrets committed: .env is gitignored, .env.example has no credentials.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages