Skip to content

Commit 48d8c6f

Browse files
authored
Merge pull request #246 from bitquery/docs/lighter-perp-dex-api
docs: Lighter perp DEX on Robinhood Chain API
2 parents 944e6c5 + 0b7ac41 commit 48d8c6f

2 files changed

Lines changed: 291 additions & 0 deletions

File tree

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
---
2+
title: "Lighter Perp DEX on Robinhood Chain API"
3+
description: "Track Lighter perpetual futures on Robinhood Chain with Bitquery — USDG margin deposits and withdrawals, the ZkLighter rollup contract, batch commits, and full flow history over GraphQL APIs and WebSocket streams."
4+
sidebar_position: 10
5+
keywords:
6+
- Lighter Robinhood API
7+
- Lighter perp DEX data
8+
- Robinhood perpetual futures onchain
9+
- ZkLighter contract Robinhood Chain
10+
- Lighter USDG deposits
11+
- Lighter margin withdrawals
12+
- Lighter deposit tracking
13+
- zkLighter rollup batches
14+
- Robinhood Chain perps
15+
- Bitquery Lighter API
16+
---
17+
18+
# Lighter Perp DEX on Robinhood Chain API
19+
20+
[Lighter](https://lighter.xyz) is the perpetual-futures DEX integrated into Robinhood Wallet. When Robinhood Chain mainnet went live on July 1, 2026, Lighter launched alongside it as the venue behind in-app perps: eligible users post **USDG** margin from their wallet, and the funds are locked in Lighter's smart contract on Robinhood Chain while positions are managed by Lighter's zk engine.
21+
22+
What actually lives on Robinhood Chain is a full **ZkLighter rollup contract** — not just a token vault. It receives every margin deposit, queues and pays withdrawals, and records the rollup's batch lifecycle (`commit → verify → execute`) at roughly **one batch per minute**. This page shows how to query and stream all of it with Bitquery's `EVM` cubes on `network: robinhood`.
23+
24+
Scale as of late August 2026, measured with the queries on this page: about **$33.4M USDG deposited and $7.7M withdrawn** since launch (net ≈ the contract's current $25.7M balance), with August deposits running at ~3.7× July and 1,000–3,000 deposits per day.
25+
26+
:::note API Key Required
27+
To query or stream data outside the Bitquery IDE, you need an API access token.
28+
29+
Follow the steps here: [How to generate Bitquery API token ➤](/docs/authorization/how-to-generate/)
30+
:::
31+
32+
:::tip Related docs
33+
- [Robinhood Events API](/docs/blockchain/robinhood/robinhood-events-api/)
34+
- [Robinhood Transfers](/docs/blockchain/robinhood/robinhood-transfers/)
35+
- [Robinhood Calls API](/docs/blockchain/robinhood/robinhood-calls-api/)
36+
- [Robinhood Balances API](/docs/blockchain/robinhood/robinhood-balances-api/)
37+
- [EVM Events schema](/docs/schema/evm/events/)
38+
:::
39+
40+
**On this page:** [What is on-chain](#what-is-on-chain-and-what-is-not) · [Contracts](#contract-map) · [Event reference](#event-reference-topic0-map) · [Deposits](#track-margin-deposits) · [Withdrawals](#track-withdrawals) · [Margin flow & history](#usdg-margin-flow-full-history) · [Rollup heartbeat](#monitor-the-rollup-heartbeat) · [Deposit calls](#deposit-calls-by-selector) · [Decoding notes](#decoding-notes)
41+
42+
---
43+
44+
## What is on-chain (and what is not)
45+
46+
Lighter's matching engine, order book, positions, funding, and liquidations run inside its zk rollup — they are **not** individual Robinhood Chain transactions. What settles on Robinhood Chain, and what Bitquery therefore indexes, is:
47+
48+
| On Robinhood Chain (queryable here) | Inside the Lighter engine (not on-chain) |
49+
| --- | --- |
50+
| USDG margin **deposits** into the ZkLighter contract | Individual trades and fills |
51+
| **Withdrawal** queue events and USDG payouts back to users | Open positions and PnL |
52+
| Rollup **batch lifecycle**: commit, verification, execution, state roots | Funding payments (hourly, peer-to-peer) |
53+
| Priority requests (forced operations, key changes, escape hatches) | Order placement and cancellation (except the on-chain `cancelAllOrders` escape hatch) |
54+
| Market/asset registry events | Liquidation events themselves (only the margin effects appear) |
55+
56+
This makes the on-chain data ideal for **money-flow questions** — who is depositing margin, how much, net flows, contract TVL, whether the rollup operator is alive — rather than trade-level analytics.
57+
58+
---
59+
60+
## Contract map
61+
62+
| Role | Address |
63+
| --- | --- |
64+
| **ZkLighter proxy** — receives margin, pays withdrawals, emits every Lighter event | `0x94bab9693ba2f6358507effcbd372b0660afff9d` |
65+
| Current verified implementation (`ZkLighter`) | `0x82DE5B1161C93afDFE21bA0D5343f01Cd7401d90` |
66+
| USDG (Global Dollar, 6 decimals) — canonical currency address in Bitquery cubes | `0x5fc5360d0400a0fd4f2af552add042d716f1d168` |
67+
| Robinhood deposit router (sweeps in-app deposits into `deposit()`) | `0x8062df5b3220ad1f528365650a3eb3e8c7b0dad1` |
68+
69+
:::info Filter by LogHeader.Address, not Log.SmartContract
70+
The ZkLighter proxy delegates to implementation modules, so `Log.SmartContract` shows the **implementation** address — and implementations rotate on upgrades (the last rotation was August 21, 2026; older module addresses you may see in results include `0x1be72833…`, `0xe470e41c…`, and `0xda2b59ff…`). The stable anchor is `LogHeader.Address` = the proxy `0x94bab969…`, combined with the event's `SignatureHash` (topic0). Every query below follows that pattern.
71+
:::
72+
73+
---
74+
75+
## Event reference (topic0 map)
76+
77+
All events are emitted with the proxy as `LogHeader.Address`. Hash fields in Bitquery are hex strings **without** a `0x` prefix.
78+
79+
| Event | topic0 (`Log.Signature.SignatureHash`) |
80+
| --- | --- |
81+
| `Deposit(uint48 toAccountIndex, address toAddress, uint16 assetIndex, uint8 routeType, uint128 baseAmount)` | `493c3b8240368e8343bcd42cac5f4b8b161c06d061710e542a72f06a40ddd9d1` |
82+
| `WithdrawPending(address indexed owner, uint16 assetIndex, uint128 baseAmount)` | `ef80235b5f4cf1822ad6a8621af41ac64372ff672c402874f507fc63dbe5e06f` |
83+
| `NewPriorityRequest(address sender, uint64 serialId, uint8 pubdataType, bytes pubData, uint64 expirationTimestamp)` | `efdd379e3e15772fcc7d2a67fa5bbb0790b932724153aded4648307094733b2f` |
84+
| `BatchCommit(uint64 batchNumber, uint32 batchSize, uint64 endBlockNumber)` | `181b25ea9d4d730f30d779f3d2099c03b26b653c889d33eef253d54baaacbd0d` |
85+
| `BatchVerification(uint64 batchNumber, uint32 batchSize, uint64 endBlockNumber)` | `5c836e1ff20ea85c52b6e3d2ef0124d3304bf3b37cc8fb0e2c84ae7d44c0593e` |
86+
| `BatchesExecuted(uint64 batchNumber, uint64 endBlockNumber)` | `5d490d991d08230b7690c7511bb854b7b8a05fb7c87e2348e1909384cb325511` |
87+
| `StateRootUpdate(uint64 batchNumber, bytes32 oldStateRoot, bytes32 newStateRoot)` | `645e0b8f839353842bdac87abd27fc8bdda536e0731cdb7cc75e4f0740b575ac` |
88+
| `CreateMarket((uint16,uint8,bytes), uint8 sizeDecimals, uint8 priceDecimals, bytes32 symbol)` | `134f63a6bbe3b3ef885ce4067eb2753fe1c912c51c4b8e0cc7966f21773c047e` |
89+
| `RegisterAssetConfig(uint16 assetIndex, address tokenAddress, …)` | `f1b24e81016b9f39e2290cf2a9303264a07534a569df7e6200a39573d7f26b0c` |
90+
91+
The remaining admin events (`UpdateMarket`, `UpdateAssetConfig`, `BatchesRevert`, `DesertMode`, `TreasuryUpdate`, `InsuranceFundOperatorUpdate`, `Initialized`) exist in the ABI but fire rarely; the full verified ABI is on the [Robinhood Chain explorer](https://robinhoodchain.blockscout.com/address/0x82DE5B1161C93afDFE21bA0D5343f01Cd7401d90?tab=contract).
92+
93+
---
94+
95+
## Track margin deposits
96+
97+
Every deposit into Lighter emits one `Deposit` event. This query returns the latest ones; turn it into a live stream by replacing `query` with `subscription` and dropping `dataset`/`limit`/`orderBy`.
98+
99+
```graphql
100+
{
101+
EVM(network: robinhood, dataset: realtime) {
102+
Events(
103+
limit: { count: 10 }
104+
orderBy: { descending: Block_Number }
105+
where: {
106+
LogHeader: { Address: { is: "0x94bab9693ba2f6358507effcbd372b0660afff9d" } }
107+
Log: { Signature: { SignatureHash: { is: "493c3b8240368e8343bcd42cac5f4b8b161c06d061710e542a72f06a40ddd9d1" } } }
108+
}
109+
) {
110+
Block { Number Time }
111+
Transaction { Hash From }
112+
Log { SmartContract Signature { SignatureHash } }
113+
LogHeader { Address Data }
114+
}
115+
}
116+
}
117+
```
118+
119+
`Deposit` has no indexed parameters, so all five fields sit in `LogHeader.Data` as 32-byte words, in ABI order:
120+
121+
| Word | Field | Notes |
122+
| --- | --- | --- |
123+
| 0 | `toAccountIndex` | The user's Lighter account index |
124+
| 1 | `toAddress` | The wallet credited — for Robinhood-app deposits this is the user's deposit address, while the ERC-20 transfer arrives via the router `0x8062df5b…` |
125+
| 2 | `assetIndex` | `3` = USDG on this deployment |
126+
| 3 | `routeType` | `0` for ~98% of deposits |
127+
| 4 | `baseAmount` | Raw token units — divide by 10⁶ for USDG (verified to match the ERC-20 transfer in the same transaction) |
128+
129+
---
130+
131+
## Track withdrawals
132+
133+
Withdrawals are two-step: the rollup queues the amount (`WithdrawPending`, with the receiving wallet **indexed** as `Topics[1]`), then operator transactions push the USDG payout to the user via `withdrawPendingBalance`. To watch the queue:
134+
135+
```graphql
136+
{
137+
EVM(network: robinhood, dataset: realtime) {
138+
Events(
139+
limit: { count: 10 }
140+
orderBy: { descending: Block_Number }
141+
where: {
142+
LogHeader: { Address: { is: "0x94bab9693ba2f6358507effcbd372b0660afff9d" } }
143+
Log: { Signature: { SignatureHash: { is: "ef80235b5f4cf1822ad6a8621af41ac64372ff672c402874f507fc63dbe5e06f" } } }
144+
}
145+
) {
146+
Block { Number Time }
147+
Transaction { Hash }
148+
Topics { Hash } # Topics[1] = padded owner address
149+
LogHeader { Data } # [assetIndex, baseAmount(6dp)]
150+
}
151+
}
152+
}
153+
```
154+
155+
The actual payout is a plain USDG transfer **from** the proxy, so the Transfers query below covers the money leg of withdrawals too.
156+
157+
---
158+
159+
## USDG margin flow (full history)
160+
161+
The simplest lens on Lighter needs no event decoding at all: USDG transfers to the proxy are margin in, transfers from it are margin out. The `combined` dataset holds Robinhood Chain history back to the chain's start, so this works from Lighter's first deposit (June 26, 2026 — a soft start a few days before the public July 1 launch).
162+
163+
Monthly deposit and withdrawal totals since launch:
164+
165+
```graphql
166+
{
167+
EVM(network: robinhood, dataset: combined) {
168+
deposits: Transfers(
169+
where: {
170+
Transfer: {
171+
Currency: { SmartContract: { is: "0x5fc5360d0400a0fd4f2af552add042d716f1d168" } }
172+
Receiver: { is: "0x94bab9693ba2f6358507effcbd372b0660afff9d" }
173+
}
174+
}
175+
) {
176+
Block { Date(interval: { count: 1, in: months }) }
177+
count
178+
sum(of: Transfer_Amount)
179+
}
180+
withdrawals: Transfers(
181+
where: {
182+
Transfer: {
183+
Currency: { SmartContract: { is: "0x5fc5360d0400a0fd4f2af552add042d716f1d168" } }
184+
Sender: { is: "0x94bab9693ba2f6358507effcbd372b0660afff9d" }
185+
}
186+
}
187+
) {
188+
Block { Date(interval: { count: 1, in: months }) }
189+
count
190+
sum(of: Transfer_Amount)
191+
}
192+
}
193+
}
194+
```
195+
196+
Swap the monthly interval for a `days` interval for daily flow charts, or drop the aggregation and add `limit`/`orderBy` to list individual transfers with sender and receiver. The difference between lifetime deposits and withdrawals is the contract's standing USDG balance — Lighter-on-Robinhood's margin TVL.
197+
198+
To size total activity, an aggregate probe over full history:
199+
200+
```graphql
201+
{
202+
EVM(network: robinhood, dataset: combined) {
203+
Events(
204+
where: {
205+
LogHeader: { Address: { is: "0x94bab9693ba2f6358507effcbd372b0660afff9d" } }
206+
Log: { Signature: { SignatureHash: { is: "493c3b8240368e8343bcd42cac5f4b8b161c06d061710e542a72f06a40ddd9d1" } } }
207+
}
208+
) {
209+
count
210+
earliest: Block { Time(minimum: Block_Time) }
211+
latest: Block { Time(maximum: Block_Time) }
212+
}
213+
}
214+
}
215+
```
216+
217+
---
218+
219+
## Monitor the rollup heartbeat
220+
221+
Lighter posts its zk batch lifecycle to Robinhood Chain about once a minute. Streaming the three lifecycle events is a ready-made **liveness monitor** for the venue — if commits stop, the engine or its operator has a problem:
222+
223+
```graphql
224+
subscription {
225+
EVM(network: robinhood) {
226+
Events(
227+
where: {
228+
LogHeader: { Address: { is: "0x94bab9693ba2f6358507effcbd372b0660afff9d" } }
229+
Log: {
230+
Signature: {
231+
SignatureHash: {
232+
in: [
233+
"181b25ea9d4d730f30d779f3d2099c03b26b653c889d33eef253d54baaacbd0d"
234+
"5c836e1ff20ea85c52b6e3d2ef0124d3304bf3b37cc8fb0e2c84ae7d44c0593e"
235+
"5d490d991d08230b7690c7511bb854b7b8a05fb7c87e2348e1909384cb325511"
236+
]
237+
}
238+
}
239+
}
240+
}
241+
) {
242+
Block { Number Time }
243+
Transaction { Hash From }
244+
Log { Signature { SignatureHash } }
245+
LogHeader { Data } # batchNumber, batchSize, endBlockNumber
246+
}
247+
}
248+
}
249+
```
250+
251+
Each of `commitBatch`, `verifyBatch`, and `executeBatches` is sent by a single operator EOA, so `Transaction.From` also identifies the Lighter operator.
252+
253+
---
254+
255+
## deposit() calls by selector
256+
257+
The Calls cube gives the function-call view of the same activity — useful for catching deposits, forced withdrawals (`withdraw`, selector `d20191bd`), key registrations (`changePubKey`, `17010c68`), and escape-hatch cancels (`cancelAllOrders`, `a4b6f756`):
258+
259+
```graphql
260+
{
261+
EVM(network: robinhood, dataset: realtime) {
262+
Calls(
263+
limit: { count: 10 }
264+
orderBy: { descending: Block_Number }
265+
where: {
266+
Call: {
267+
To: { is: "0x94bab9693ba2f6358507effcbd372b0660afff9d" }
268+
Signature: { SignatureHash: { is: "8a857083" } } # deposit(address,uint16,uint8,uint256)
269+
}
270+
}
271+
) {
272+
Block { Number Time }
273+
Call { From Value Signature { SignatureHash } }
274+
Transaction { Hash From }
275+
}
276+
}
277+
}
278+
```
279+
280+
---
281+
282+
## Decoding notes
283+
284+
- **Signatures currently arrive unparsed**`Log.Signature.Name` is empty for ZkLighter events until the ABI is registered in the decoding pipeline, so filter by `SignatureHash` (as every query on this page does) and decode `LogHeader.Data` client-side with the word layouts above. Once the ABI lands, the same queries also return decoded `Arguments`.
285+
- `LogHeader.Address` is the address a node's `eth_getLogs` would report; `Log.SmartContract` is the implementation behind the proxy and changes on upgrades. Pin queries to `LogHeader.Address`.
286+
- Amounts (`baseAmount` and USDG `Transfer.Amount`) are 6-decimal USDG units; `Transfer.Amount` in the API is already decimal-adjusted.
287+
- Robinhood in-app deposits are swept from per-user deposit addresses through the router `0x8062df5b…`, so the ERC-20 `Transfer.Sender` into the proxy is often the router while the credited wallet is `Deposit.toAddress`. Count depositors from the `Deposit` event, not from transfer senders.
288+
- For trade-level perps data (fills, positions, funding), use Lighter's own venue APIs — that activity never touches Robinhood Chain. On-chain data here answers flow, TVL, user-count, and liveness questions.
289+
290+
Every query on this page was executed against the production `streaming.bitquery.io/graphql` endpoint on August 22, 2026 before publishing.

sidebars.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,7 @@ const sidebars = {
912912
"blockchain/robinhood/robinhood-transactions-receipts-api",
913913
"blockchain/robinhood/robinhood-balances-api",
914914
"blockchain/robinhood/robinhood-token-holders-api",
915+
"blockchain/robinhood/lighter-perp-dex-api",
915916
"blockchain/robinhood/robinhood-meme-coin-launches",
916917
"blockchain/robinhood/pools-trade-api",
917918
"blockchain/robinhood/pons-api",

0 commit comments

Comments
 (0)