Skip to content

Commit 5f4dc1d

Browse files
committed
fix: return actual post-fee fill data from createOrder
Both Limitless and Polymarket createOrder wrappers were echoing back requested amounts (filled: 0, amount: requestedAmount) instead of actual post-fee fill data from the venue response. Limitless: extract makerMatches[].matchedSize for immediate fills Polymarket: use takingAmount/makingAmount from CLOB OrderResponse Both: report feeRateBps when available
1 parent 5d1756f commit 5f4dc1d

4 files changed

Lines changed: 67 additions & 10 deletions

File tree

changelog.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [2.40.4] - 2026-05-09
6+
7+
### Fixed
8+
9+
- **Limitless**: `createOrder` now extracts actual fill data from `makerMatches[].matchedSize` instead of echoing back requested amounts. Reports real post-fee filled shares and `feeRateBps`.
10+
- **Polymarket**: `createOrder` now uses `takingAmount`/`makingAmount` from the CLOB `OrderResponse` instead of echoing back requested amounts. Correctly reports filled shares for immediately matched orders.
11+
- **Order type**: Added optional `filledShares` and `feeRateBps` fields to the `Order` interface for venues that report post-fee fill data.
12+
513
## [2.40.3] - 2026-05-09
614

715
### Fixed

core/src/exchanges/limitless/index.ts

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -287,20 +287,39 @@ export class LimitlessExchange extends PredictionMarketExchange {
287287
onBehalfOf: params.onBehalfOf,
288288
});
289289

290-
// Map response to Order object
291-
// The SDK returns OrderResponse with order.id
290+
// Map response to Order object.
291+
// The SDK returns OrderResponse: { order: CreatedOrder, makerMatches?: OrderMatch[] }
292+
// For GTC orders that rest on the book, makerMatches is empty.
293+
// For FOK/FAK orders (or GTC with immediate partial matches), makerMatches contains fills.
294+
// Each OrderMatch.matchedSize is in USDC raw units (6 decimals).
295+
const USDC_DECIMALS = 6;
296+
const raw = response as any;
297+
const matches: any[] = raw.makerMatches ?? raw.order?.makerMatches ?? [];
298+
const filledRaw = matches.reduce((sum: number, m: any) => {
299+
const size = typeof m.matchedSize === 'string'
300+
? parseFloat(m.matchedSize)
301+
: (m.matchedSize ?? 0);
302+
return sum + size;
303+
}, 0);
304+
const filled = filledRaw / Math.pow(10, USDC_DECIMALS);
305+
const remaining = Math.max(0, params.amount - filled);
306+
const orderFeeRateBps = raw.order?.feeRateBps
307+
?? raw.feeRateBps
308+
?? undefined;
309+
292310
return {
293-
id: response.order.id || 'unknown',
311+
id: raw.order?.id || raw.id || 'unknown',
294312
marketId: params.marketId,
295313
outcomeId: params.outcomeId,
296314
side: params.side,
297315
type: params.type,
298316
price: params.price,
299317
amount: params.amount,
300-
status: 'open',
301-
filled: 0,
302-
remaining: params.amount,
318+
status: filled >= params.amount ? 'filled' : 'open',
319+
filled,
320+
remaining,
303321
timestamp: Date.now(),
322+
...(orderFeeRateBps != null ? { feeRateBps: orderFeeRateBps } : {}),
304323
};
305324
} catch (error: any) {
306325
throw limitlessErrorMapper.mapError(error);

core/src/exchanges/polymarket/index.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,32 @@ export class PolymarketExchange extends PredictionMarketExchange {
248248

249249
const side = built.params.side.toUpperCase() === 'BUY' ? Side.BUY : Side.SELL;
250250
const price = built.params.price || (side === Side.BUY ? 0.99 : 0.01);
251+
252+
// Extract actual fill data from the CLOB OrderResponse.
253+
// response.status: 'MATCHED' | 'CONFIRMED' = immediately filled,
254+
// 'LIVE' = resting on the book (filled: 0 is correct).
255+
// takingAmount / makingAmount are string representations of raw USDC amounts (6 decimals).
256+
const USDC_DECIMALS = 6;
257+
const responseStatus = (response.status || '').toUpperCase();
258+
const isImmediatelyFilled = responseStatus === 'MATCHED' || responseStatus === 'CONFIRMED';
259+
let filled = 0;
260+
if (isImmediatelyFilled) {
261+
const takingRaw = typeof response.takingAmount === 'string'
262+
? parseFloat(response.takingAmount)
263+
: (response.takingAmount ?? 0);
264+
const makingRaw = typeof response.makingAmount === 'string'
265+
? parseFloat(response.makingAmount)
266+
: (response.makingAmount ?? 0);
267+
// For BUY: makingAmount is USDC spent, takingAmount is shares received.
268+
// For SELL: makingAmount is shares sold, takingAmount is USDC received.
269+
// `filled` should reflect the share size that executed.
270+
filled = side === Side.BUY
271+
? takingRaw / Math.pow(10, USDC_DECIMALS)
272+
: makingRaw / Math.pow(10, USDC_DECIMALS);
273+
}
274+
const remaining = Math.max(0, built.params.amount - filled);
275+
const orderStatus = filled >= built.params.amount ? 'filled' : 'open';
276+
251277
return {
252278
id: response.orderID,
253279
marketId: built.params.marketId,
@@ -256,9 +282,9 @@ export class PolymarketExchange extends PredictionMarketExchange {
256282
type: built.params.type,
257283
price,
258284
amount: built.params.amount,
259-
status: 'open',
260-
filled: 0,
261-
remaining: built.params.amount,
285+
status: orderStatus,
286+
filled,
287+
remaining,
262288
fee: built.params.fee,
263289
timestamp: Date.now(),
264290
};

core/src/types.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,12 +189,16 @@ export interface Order {
189189
amount: number; // Size in contracts/shares
190190
/** Lifecycle status of the order. */
191191
status: 'pending' | 'open' | 'filled' | 'cancelled' | 'rejected';
192-
filled: number; // Amount filled
192+
filled: number; // Amount filled (USDC cost for buys, shares for sells)
193+
/** Amount filled in shares/contracts (if different from USDC-denominated `filled`). */
194+
filledShares?: number;
193195
remaining: number; // Amount remaining
194196
/** Unix timestamp in milliseconds when the order was created. */
195197
timestamp: number;
196198
/** Fee paid for this order, if known. */
197199
fee?: number;
200+
/** Fee rate in basis points applied to this order (e.g. 100 = 1%). */
201+
feeRateBps?: number;
198202
}
199203

200204
export interface Position {

0 commit comments

Comments
 (0)