Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/ord-2039.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@lifi/perps-sdk-provider-lighter": patch
---

Read Lighter order, client order and trade ids from the exact string fields, so ids above 2^53 no longer round in `Order.orderId`, `Order.clientOrderId`, `Fill.id`, `Fill.orderId` and the `getOrder` lookup.
5 changes: 2 additions & 3 deletions packages/perps-sdk-provider-lighter/src/LighterProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1617,7 +1617,7 @@ export const createLighterProvider = (
// `accountOrders` reaches active and inactive rows alike, so a reused
// client order index can match more than one row. Prefer the live one.
const matches = orders
.filter((o) => String(o.client_order_index) === clientOrderIndex)
.filter((o) => o.client_order_id === clientOrderIndex)
.flatMap((o) => mapDetail(o) ?? [])
const hit =
matches.find((o) => isActiveOrderStatus(o.status)) ?? matches[0]
Expand All @@ -1627,8 +1627,7 @@ export const createLighterProvider = (
return hit
}

const byOrderIndex = (o: LtOrder): boolean =>
String(o.order_index) === params.id
const byOrderIndex = (o: LtOrder): boolean => o.order_id === params.id

const active = await retryOnRevoked(params.address, token, (t) =>
fetchActiveOrders(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ const TRADES_RESPONSE = {
trades: [
{
trade_id: 7,
trade_id_str: '7',
tx_hash: '0xfeed',
type: 'trade',
market_id: 0,
Expand All @@ -350,6 +351,10 @@ const TRADES_RESPONSE = {
usd_amount: '25000',
ask_id: 11,
bid_id: 22,
ask_id_str: '11',
bid_id_str: '22',
ask_client_id_str: '0',
bid_client_id_str: '0',
ask_account_id: 99,
bid_account_id: 42,
is_maker_ask: true,
Expand Down Expand Up @@ -3171,7 +3176,7 @@ describe('LighterProvider — getOrders pagination contract', () => {
order_index: orderIndex,
client_order_index: 0,
order_id: String(orderIndex),
client_order_id: String(orderIndex),
client_order_id: '0',
market_index: 0,
owner_account_index: 42,
initial_base_amount: '0.1',
Expand Down Expand Up @@ -5352,6 +5357,11 @@ describe('LighterProvider — getOrder', () => {
})

describe('LighterProvider — one-call order reads', () => {
// A market 33 order index above 2^53: `JSON.parse` rounds the numeric twin
// to ...276, so only the string twin carries the exact id.
const UNSAFE_ORDER_ID = '9570149379440277'
const UNSAFE_ORDER_ID_PARSED = 9570149379440276

const TWO_MARKETS_RESPONSE = {
markets: [
MARKETS_RESPONSE.markets[0],
Expand Down Expand Up @@ -5461,8 +5471,8 @@ describe('LighterProvider — one-call order reads', () => {
code: 0,
next_cursor: '',
orders: [
makeOrder({ order_index: 900, market_index: 0 }),
makeOrder({ order_index: 901, market_index: 1 }),
makeOrder({ order_index: 900, order_id: '900', market_index: 0 }),
makeOrder({ order_index: 901, order_id: '901', market_index: 1 }),
],
})
}
Expand Down Expand Up @@ -5496,7 +5506,9 @@ describe('LighterProvider — one-call order reads', () => {
return respond({
code: 0,
next_cursor: '',
orders: [makeOrder({ order_index: 901, market_index: 1 })],
orders: [
makeOrder({ order_index: 901, order_id: '901', market_index: 1 }),
],
})
}
return undefined
Expand All @@ -5516,7 +5528,12 @@ describe('LighterProvider — one-call order reads', () => {
it('resolves an active order by client order index through one accountOrders request', async () => {
overrideFetch((u) =>
u.includes('/api/v1/accountOrders')
? respond({ code: 200, orders: [makeOrder({ client_order_index: 7 })] })
? respond({
code: 200,
orders: [
makeOrder({ client_order_index: 7, client_order_id: '7' }),
],
})
: undefined
)

Expand All @@ -5542,6 +5559,7 @@ describe('LighterProvider — one-call order reads', () => {
orders: [
makeOrder({
client_order_index: 8,
client_order_id: '8',
status: 'filled',
remaining_base_amount: '0',
filled_base_amount: '0.1',
Expand Down Expand Up @@ -5572,10 +5590,17 @@ describe('LighterProvider — one-call order reads', () => {
orders: [
makeOrder({
client_order_index: 7,
client_order_id: '7',
order_index: 800,
order_id: '800',
status: 'canceled',
}),
makeOrder({ client_order_index: 7, order_index: 901 }),
makeOrder({
client_order_index: 7,
client_order_id: '7',
order_index: 901,
order_id: '901',
}),
],
})
: undefined
Expand All @@ -5594,7 +5619,12 @@ describe('LighterProvider — one-call order reads', () => {
it('ignores an accountOrders row whose client order index differs', async () => {
overrideFetch((u) =>
u.includes('/api/v1/accountOrders')
? respond({ code: 200, orders: [makeOrder({ client_order_index: 9 })] })
? respond({
code: 200,
orders: [
makeOrder({ client_order_index: 9, client_order_id: '9' }),
],
})
: undefined
)

Expand Down Expand Up @@ -5649,6 +5679,54 @@ describe('LighterProvider — one-call order reads', () => {
expect(requestsTo('/api/v1/accountOrders')).toEqual([])
})

it('matches a bare order id above 2^53 on order_id, not the rounded order_index', async () => {
overrideFetch((u) =>
u.includes('/api/v1/accountActiveOrders')
? respond({
code: 0,
next_cursor: '',
orders: [
makeOrder({
order_index: UNSAFE_ORDER_ID_PARSED,
order_id: UNSAFE_ORDER_ID,
}),
],
})
: undefined
)

const order = await (await boundProvider()).getOrder({
address: ADDRESS,
id: UNSAFE_ORDER_ID,
})

expect(order.orderId).toBe(UNSAFE_ORDER_ID)
expect(requestsTo('/api/v1/accountInactiveOrders')).toEqual([])
})

it('matches a client order index above 2^53 on client_order_id', async () => {
overrideFetch((u) =>
u.includes('/api/v1/accountOrders')
? respond({
code: 200,
orders: [
makeOrder({
client_order_index: UNSAFE_ORDER_ID_PARSED,
client_order_id: UNSAFE_ORDER_ID,
}),
],
})
: undefined
)

const order = await (await boundProvider()).getOrder({
address: ADDRESS,
id: `${LIGHTER_CLIENT_ORDER_INDEX_ID_PREFIX}${UNSAFE_ORDER_ID}`,
})

expect(order.clientOrderId).toBe(UNSAFE_ORDER_ID)
})

it('falls back to the inactive orders for an order_index that no longer rests', async () => {
overrideFetch((u) => {
if (u.includes('/api/v1/accountActiveOrders')) {
Expand Down Expand Up @@ -5693,6 +5771,7 @@ describe('LighterProvider — getFills logos and realized PnL', () => {
// 50000 → realized PnL (50000 - 40000) × 1 = 10000.
const REDUCING_TRADE = {
trade_id: 9,
trade_id_str: '9',
tx_hash: '0xfeed',
type: 'trade',
market_id: 0,
Expand All @@ -5701,6 +5780,10 @@ describe('LighterProvider — getFills logos and realized PnL', () => {
usd_amount: '50000',
ask_id: 7,
bid_id: 8,
ask_id_str: '7',
bid_id_str: '8',
ask_client_id_str: '0',
bid_client_id_str: '0',
ask_account_id: 42,
bid_account_id: 0,
is_maker_ask: false,
Expand Down Expand Up @@ -5771,6 +5854,7 @@ describe('LighterProvider — getFills unresolvable market rows', () => {
const tradeRow = (tradeId: number, marketId: number) => ({
...TRADES_RESPONSE.trades[0],
trade_id: tradeId,
trade_id_str: String(tradeId),
market_id: marketId,
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ const ACTIVE_ORDERS = {
{
order_index: 88,
client_order_index: 0,
order_id: 'lt-88',
order_id: '88',
client_order_id: '0',
market_index: BTC_MARKET_ID,
owner_account_index: ACCOUNT_INDEX,
Expand Down Expand Up @@ -284,7 +284,7 @@ const ACTIVE_ORDERS = {
{
order_index: 89,
client_order_index: 0,
order_id: 'lt-89',
order_id: '89',
client_order_id: '0',
market_index: BTC_MARKET_ID,
owner_account_index: ACCOUNT_INDEX,
Expand Down Expand Up @@ -323,6 +323,7 @@ const TRADES = {
trades: [
{
trade_id: 7,
trade_id_str: '7',
tx_hash: '0xabc',
type: 'trade',
market_id: BTC_MARKET_ID,
Expand All @@ -331,6 +332,10 @@ const TRADES = {
usd_amount: '0.047',
ask_id: 100,
bid_id: 200,
ask_id_str: '100',
bid_id_str: '200',
ask_client_id_str: '0',
bid_client_id_str: '0',
ask_account_id: 0,
bid_account_id: ACCOUNT_INDEX,
is_maker_ask: false,
Expand Down
46 changes: 36 additions & 10 deletions packages/perps-sdk-provider-lighter/src/getOrders.unit.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const MARKET: Market = {
const order = (overrides: Partial<LtOrder> = {}): LtOrder => ({
order_index: 88,
client_order_index: 0,
order_id: 'lt-88',
order_id: '88',
client_order_id: '0',
market_index: 1,
owner_account_index: 42,
Expand Down Expand Up @@ -141,10 +141,16 @@ describe('Lighter getOrders lifecycle reads', () => {
order(),
order({
order_index: 90,
order_id: '90',
filled_base_amount: '0',
filled_quote_amount: '0',
}),
order({ type: 'twap-sub', order_index: 89, parent_order_id: '88' }),
order({
type: 'twap-sub',
order_index: 89,
order_id: '89',
parent_order_id: '88',
}),
])
const result = await provider.getOrders({ address: ADDRESS, marketId: '1' })
expect(result.orders).toMatchObject([
Expand Down Expand Up @@ -178,8 +184,13 @@ describe('Lighter getOrders lifecycle reads', () => {
[],
[
order({ status: 'filled' }),
order({ type: 'limit', order_index: 91, status: 'canceled-expired' }),
order({ order_index: 92, status: 'canceled' }),
order({
type: 'limit',
order_index: 91,
order_id: '91',
status: 'canceled-expired',
}),
order({ order_index: 92, order_id: '92', status: 'canceled' }),
],
'next-page'
)
Expand Down Expand Up @@ -213,8 +224,11 @@ describe('Lighter getOrders lifecycle reads', () => {

it('combines active and terminal filters without retaining unrequested statuses', async () => {
const { provider, requests } = await setup(
[order(), order({ order_index: 89, filled_base_amount: '0' })],
[order({ order_index: 90, status: 'filled' })]
[
order(),
order({ order_index: 89, order_id: '89', filled_base_amount: '0' }),
],
[order({ order_index: 90, order_id: '90', status: 'filled' })]
)
const result = await provider.getOrders({
address: ADDRESS,
Expand All @@ -231,7 +245,7 @@ describe('Lighter getOrders lifecycle reads', () => {
it('does not repeat the active snapshot on a mixed history continuation page', async () => {
const { provider, requests } = await setup(
[order()],
[order({ order_index: 90, status: 'filled' })]
[order({ order_index: 90, order_id: '90', status: 'filled' })]
)
const result = await provider.getOrders({
address: ADDRESS,
Expand Down Expand Up @@ -287,7 +301,12 @@ describe('Lighter getOrders lifecycle reads', () => {
[],
[
order({ status: 'filled' }),
order({ order_index: 91, market_index: 999, status: 'filled' }),
order({
order_index: 91,
order_id: '91',
market_index: 999,
status: 'filled',
}),
]
)
const result = await provider.getOrders({
Expand All @@ -300,7 +319,14 @@ describe('Lighter getOrders lifecycle reads', () => {
it('keeps a history row whose market is delisted', async () => {
const { provider } = await setup(
[],
[order({ order_index: 91, market_index: 2, status: 'filled' })],
[
order({
order_index: 91,
order_id: '91',
market_index: 2,
status: 'filled',
}),
],
'',
[MARKET, { ...MARKET, id: '2', isDelisted: true }]
)
Expand All @@ -324,7 +350,7 @@ describe('Lighter getOrders lifecycle reads', () => {
it('uses the same order shape for list reads and single-order reads', async () => {
const { provider } = await setup(
[],
[order({ status: 'filled', client_order_index: 7 })]
[order({ status: 'filled', client_order_index: 7, client_order_id: '7' })]
)
const params: ProviderGetOrdersParams = {
address: ADDRESS,
Expand Down
5 changes: 5 additions & 0 deletions packages/perps-sdk-provider-lighter/src/types/fill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
export type LtTrade = {
trade_id: number
trade_id_str: string
tx_hash: string
type: string
market_id: number
Expand All @@ -24,6 +25,10 @@ export type LtTrade = {
usd_amount: string
ask_id: number
bid_id: number
ask_id_str: string
bid_id_str: string
ask_client_id_str: string
bid_client_id_str: string
ask_account_id: number
bid_account_id: number
is_maker_ask: boolean
Expand Down
4 changes: 2 additions & 2 deletions packages/perps-sdk-provider-lighter/src/utils/mapFill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,8 @@ export const mapFill = (
: tickToFeeAmount(trade.usd_amount, feeTick, integratorFeeTick)

return {
id: trade.trade_id.toString(),
orderId: String(isBuyer ? trade.bid_id : trade.ask_id),
id: trade.trade_id_str,
orderId: isBuyer ? trade.bid_id_str : trade.ask_id_str,
market,
side: isBuyer ? OrderSide.BUY : OrderSide.SELL,
type: OrderType.LIMIT,
Expand Down
Loading
Loading