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
6 changes: 3 additions & 3 deletions schema/tables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,9 @@ export const discreteOrder = onchainTable(
feeAmount: t.text().notNull(),
validTo: t.integer(), // uint32 Unix timestamp — from API or getTradeableOrderWithSignature
creationDate: t.bigint().notNull(), // block timestamp (seconds)
executedSellAmount: t.text(), // actual executed amount (from API, post-settlement)
executedBuyAmount: t.text(), // actual executed amount (from API, post-settlement)
executedFee: t.text(), // actual fee taken from surplus (API executedFee; the legacy executedFeeAmount is always "0")
executedSellAmount: t.bigint(), // actual executed amount (from API, post-settlement)
executedBuyAmount: t.bigint(), // actual executed amount (from API, post-settlement)
executedFee: t.bigint(), // actual fee taken from surplus (API executedFee; the legacy executedFeeAmount is always "0")
promotedAt: t.bigint(), // block timestamp when CandidateConfirmer promoted from candidate; null = created directly (precompute or OwnerBackfill)
// Sync cursor: the indexer's processing block of the last insert or
// status/executed-amount change. Every change here also bumps the parent
Expand Down
2 changes: 2 additions & 0 deletions src/api/endpoints/orders-by-owner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ export const ordersByOwnerHandler: RouteHandler<
enrichedOrders = orders.map((o) => ({
...o,
creationDate: o.creationDate.toString(),
executedSellAmount: o.executedSellAmount?.toString() ?? null,
executedBuyAmount: o.executedBuyAmount?.toString() ?? null,
generator: generatorById[o.generatorId],
}));
}
Expand Down
6 changes: 3 additions & 3 deletions src/application/helpers/executedAmounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ export async function refreshTwapExecutedTotals(
const rows = await context.db.sql
.select({
generatorId: discreteOrder.conditionalOrderGeneratorId,
executedSellAmount: sql<string>`coalesce(sum(${discreteOrder.executedSellAmount}::numeric), 0)::text`.as("executed_sell_amount_sum"),
executedBuyAmount: sql<string>`coalesce(sum(${discreteOrder.executedBuyAmount}::numeric), 0)::text`.as("executed_buy_amount_sum"),
executedFee: sql<string>`coalesce(sum(${discreteOrder.executedFee}::numeric), 0)::text`.as("executed_fee_sum"),
executedSellAmount: sql<string>`coalesce(sum(${discreteOrder.executedSellAmount}), 0)::text`.as("executed_sell_amount_sum"),
executedBuyAmount: sql<string>`coalesce(sum(${discreteOrder.executedBuyAmount}), 0)::text`.as("executed_buy_amount_sum"),
executedFee: sql<string>`coalesce(sum(${discreteOrder.executedFee}), 0)::text`.as("executed_fee_sum"),
})
.from(discreteOrder)
.where(
Expand Down
15 changes: 8 additions & 7 deletions src/application/helpers/orderbook/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
type FlashLoanEnrichment,
} from "./types";

/** Project a freshly-decoded ComposableOrder into the durable-cache row shape. */
/** Project a freshly-decoded ComposableOrder into the durable-cache row shape.
* The cache tables store amounts as TEXT — bigints convert at this boundary. */
export function toCacheRow(o: ComposableOrder): ComposableCacheRow {
return {
orderUid: o.uid,
Expand All @@ -23,9 +24,9 @@ export function toCacheRow(o: ComposableOrder): ComposableCacheRow {
feeAmount: o.feeAmount,
validTo: o.validTo ?? null,
creationDate: o.creationDate,
executedSellAmount: o.executedSellAmount ?? null,
executedBuyAmount: o.executedBuyAmount ?? null,
executedFee: o.executedFee ?? null,
executedSellAmount: o.executedSellAmount?.toString() ?? null,
executedBuyAmount: o.executedBuyAmount?.toString() ?? null,
executedFee: o.executedFee?.toString() ?? null,
};
}

Expand Down Expand Up @@ -228,9 +229,9 @@ export async function cacheUidStatuses(
orderUid: order.uid,
status: order.status,
fetchedAt: now,
executedSellAmount: order.executedSellAmount,
executedBuyAmount: order.executedBuyAmount,
executedFee: order.executedFee,
executedSellAmount: order.executedSellAmount?.toString() ?? null,
executedBuyAmount: order.executedBuyAmount?.toString() ?? null,
executedFee: order.executedFee?.toString() ?? null,
})))
.onConflictDoUpdate({
target: [orderUidCache.chainId, orderUidCache.orderUid],
Expand Down
25 changes: 13 additions & 12 deletions src/application/helpers/orderbook/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {
import {
PAGE_LIMIT,
TERMINAL_STATUSES,
toBigIntOrNull,
type ComposableOrder,
type FlashLoanEnrichment,
type OrderStatusInfo,
Expand Down Expand Up @@ -338,9 +339,9 @@ export async function fetchOrderStatusByUids(
if (cachedData && TERMINAL_STATUSES.has(cachedData.status)) {
const info: OrderStatusInfo = {
status: cachedData.status,
executedSellAmount: cachedData.executedSellAmount,
executedBuyAmount: cachedData.executedBuyAmount,
executedFee: cachedData.executedFee,
executedSellAmount: toBigIntOrNull(cachedData.executedSellAmount),
executedBuyAmount: toBigIntOrNull(cachedData.executedBuyAmount),
executedFee: toBigIntOrNull(cachedData.executedFee),
};
if (cachedData.status === "fulfilled" && cachedData.executedFee == null) {
staleFallbacks.set(uid, info);
Expand Down Expand Up @@ -380,9 +381,9 @@ export async function fetchOrderStatusByUids(
for (const order of fetched) {
result.set(order.uid, {
status: order.status,
executedSellAmount: order.executedSellAmount,
executedBuyAmount: order.executedBuyAmount,
executedFee: order.executedFee,
executedSellAmount: toBigIntOrNull(order.executedSellAmount),
executedBuyAmount: toBigIntOrNull(order.executedBuyAmount),
executedFee: toBigIntOrNull(order.executedFee),
});
if (TERMINAL_STATUSES.has(order.status)) {
newTerminal.push({
Expand All @@ -396,9 +397,9 @@ export async function fetchOrderStatusByUids(
feeAmount: order.feeAmount,
validTo: order.validTo,
creationDate: 0n,
executedSellAmount: order.executedSellAmount,
executedBuyAmount: order.executedBuyAmount,
executedFee: order.executedFee,
executedSellAmount: toBigIntOrNull(order.executedSellAmount),
executedBuyAmount: toBigIntOrNull(order.executedBuyAmount),
executedFee: toBigIntOrNull(order.executedFee),
});
}
}
Expand Down Expand Up @@ -436,9 +437,9 @@ export async function fetchOwnerOrderStatuses(
for (const order of orders) {
result.set(order.uid, {
status: order.status,
executedSellAmount: order.executedSellAmount,
executedBuyAmount: order.executedBuyAmount,
executedFee: order.executedFee,
executedSellAmount: toBigIntOrNull(order.executedSellAmount),
executedBuyAmount: toBigIntOrNull(order.executedBuyAmount),
executedFee: toBigIntOrNull(order.executedFee),
});
}
return result;
Expand Down
13 changes: 7 additions & 6 deletions src/application/helpers/orderbook/processing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { fetchOrdersByUids } from "./http";
import { upsertComposableCache } from "./cache";
import {
TERMINAL_STATUSES,
toBigIntOrNull,
type ComposableCacheRow,
type ComposableOrder,
type OrderbookOrder,
Expand Down Expand Up @@ -102,9 +103,9 @@ export async function filterAndProcess(
feeAmount: order.feeAmount,
validTo: order.validTo,
creationDate: BigInt(Math.floor(new Date(order.creationDate).getTime() / 1000)),
executedSellAmount: order.executedSellAmount,
executedBuyAmount: order.executedBuyAmount,
executedFee: order.executedFee,
executedSellAmount: toBigIntOrNull(order.executedSellAmount),
executedBuyAmount: toBigIntOrNull(order.executedBuyAmount),
executedFee: toBigIntOrNull(order.executedFee),
});
}

Expand Down Expand Up @@ -197,9 +198,9 @@ export async function remapToCurrentGenerators(
feeAmount: row.feeAmount,
validTo: row.validTo,
creationDate: row.creationDate,
executedSellAmount: row.executedSellAmount,
executedBuyAmount: row.executedBuyAmount,
executedFee: row.executedFee,
executedSellAmount: toBigIntOrNull(row.executedSellAmount),
executedBuyAmount: toBigIntOrNull(row.executedBuyAmount),
executedFee: toBigIntOrNull(row.executedFee),
});
}
return results;
Expand Down
15 changes: 11 additions & 4 deletions src/application/helpers/orderbook/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,19 @@ export type ComposableOrder = Pick<
creationDate: bigint;
};

/** Status + executed amounts returned by fetchOrderStatusByUids. */
/** Status + executed amounts returned by fetchOrderStatusByUids.
* Amounts are bigint (matching the discreteOrder columns); null when the
* cached entry predates the executed columns. */
export interface OrderStatusInfo {
status: string;
executedSellAmount: string | null; // null when served from cache
executedBuyAmount: string | null;
executedFee: string | null;
executedSellAmount: bigint | null;
executedBuyAmount: bigint | null;
executedFee: bigint | null;
}

/** API/cache decimal string -> bigint at the storage boundary. */
export function toBigIntOrNull(value: string | null | undefined): bigint | null {
return value == null ? null : BigInt(value);
}

/** CoW-order fields used to enrich a flash-loan order, from the orderbook. */
Expand Down
48 changes: 24 additions & 24 deletions tests/helpers/orderbookClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,9 @@ describe("fetchOrderStatusByUids", () => {
try {
const result = await fetchOrderStatusByUids(makeContext(), TEST_CHAIN_ID, [UID_A]);
const info = result.get(UID_A);
expect(info?.executedSellAmount).toBe("1000000000000000000");
expect(info?.executedBuyAmount).toBe("2000000000000000000");
expect(info?.executedFee).toBe("1000000000000000");
expect(info?.executedSellAmount).toBe(1000000000000000000n);
expect(info?.executedBuyAmount).toBe(2000000000000000000n);
expect(info?.executedFee).toBe(1000000000000000n);
} finally {
await close();
}
Expand Down Expand Up @@ -267,9 +267,9 @@ describe("fetchOrderStatusByUids — stale fulfilled cache entries", () => {
expect(calls).toBe(1); // stale entry treated as a miss
expect(result.get(UID_A)).toEqual({
status: "fulfilled",
executedSellAmount: "1000000000000000000",
executedBuyAmount: "2000000000000000000",
executedFee: "1000000000000000",
executedSellAmount: 1000000000000000000n,
executedBuyAmount: 2000000000000000000n,
executedFee: 1000000000000000n,
});
} finally {
await close();
Expand All @@ -289,8 +289,8 @@ describe("fetchOrderStatusByUids — stale fulfilled cache entries", () => {
const result = await fetchOrderStatusByUids(ctx, TEST_CHAIN_ID, [UID_A]);
expect(result.get(UID_A)).toEqual({
status: "fulfilled",
executedSellAmount: "1",
executedBuyAmount: "2",
executedSellAmount: 1n,
executedBuyAmount: 2n,
executedFee: null,
});
} finally {
Expand All @@ -312,7 +312,7 @@ describe("fetchOrderStatusByUids — stale fulfilled cache entries", () => {
try {
const result = await fetchOrderStatusByUids(ctx, TEST_CHAIN_ID, [UID_A]);
expect(calls).toBe(0); // no network — cache is complete
expect(result.get(UID_A)?.executedFee).toBe("3");
expect(result.get(UID_A)?.executedFee).toBe(3n);
} finally {
await close();
}
Expand Down Expand Up @@ -428,21 +428,21 @@ describe("fetchOwnerOrderStatuses", () => {

expect(result.get("0xuid1")).toEqual({
status: "fulfilled",
executedSellAmount: "500",
executedBuyAmount: "1000",
executedFee: "0",
executedSellAmount: 500n,
executedBuyAmount: 1000n,
executedFee: 0n,
});
expect(result.get("0xuid2")).toEqual({
status: "open",
executedSellAmount: "0",
executedBuyAmount: "0",
executedFee: "0",
executedSellAmount: 0n,
executedBuyAmount: 0n,
executedFee: 0n,
});
expect(result.get("0xuid3")).toEqual({
status: "expired",
executedSellAmount: "250",
executedBuyAmount: "500",
executedFee: "0",
executedSellAmount: 250n,
executedBuyAmount: 500n,
executedFee: 0n,
});
});
} finally {
Expand Down Expand Up @@ -539,9 +539,9 @@ describe("fetchOwnerOrderStatuses", () => {

expect(result.get("0xpage2-0")).toEqual({
status: "fulfilled",
executedSellAmount: "999",
executedBuyAmount: "888",
executedFee: "0",
executedSellAmount: 999n,
executedBuyAmount: 888n,
executedFee: 0n,
});
});
} finally {
Expand Down Expand Up @@ -823,7 +823,7 @@ describe("drainOwnerSlice — delta mode (fully drained owner)", () => {
expect(row).toBeDefined();
expect(row!.conditionalOrderGeneratorId).toBe("gen-current");
expect(row!.status).toBe("fulfilled");
expect(row!.executedFee).toBe("17");
expect(row!.executedFee).toBe(17n);
});
} finally {
await close();
Expand Down Expand Up @@ -947,8 +947,8 @@ describe("upsertDiscreteOrders — chunking", () => {
feeAmount: "0",
validTo: 9999999999,
creationDate: 1700000000n,
executedSellAmount: "0",
executedBuyAmount: "0",
executedSellAmount: 0n,
executedBuyAmount: 0n,
}));

const { ctx, inserted, statementCount } = makeDrainContext();
Expand Down
Loading