From 3bbdb262f09735a7aa606865a73b25b155c93314 Mon Sep 17 00:00:00 2001 From: Cesare Naldi <3353250+cesarenaldi@users.noreply.github.com> Date: Thu, 4 Jun 2026 14:51:58 +0200 Subject: [PATCH 1/6] fix account trade timestamp parsing --- .changeset/lazy-trades-fix.md | 6 +++ packages/bindings/src/clob/account.test.ts | 46 ++++++++++++++++++++++ packages/bindings/src/clob/account.ts | 18 ++++++++- 3 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 .changeset/lazy-trades-fix.md create mode 100644 packages/bindings/src/clob/account.test.ts diff --git a/.changeset/lazy-trades-fix.md b/.changeset/lazy-trades-fix.md new file mode 100644 index 0000000..2e40237 --- /dev/null +++ b/.changeset/lazy-trades-fix.md @@ -0,0 +1,6 @@ +--- +"@polymarket/client": patch +"@polymarket/bindings": patch +--- + +Fix account trade timestamp parsing for legacy CLOB epoch-seconds values. diff --git a/packages/bindings/src/clob/account.test.ts b/packages/bindings/src/clob/account.test.ts new file mode 100644 index 0000000..5a64b26 --- /dev/null +++ b/packages/bindings/src/clob/account.test.ts @@ -0,0 +1,46 @@ +import { describe, expect, it } from 'vitest'; +import { ClobTradeSchema } from './account'; + +const baseTrade = { + asset_id: '1', + bucket_index: 7, + fee_rate_bps: '0', + id: 'trade-1', + maker_address: `0x${'aa'.repeat(20)}`, + maker_orders: [ + { + asset_id: '1', + fee_rate_bps: '0', + maker_address: `0x${'bb'.repeat(20)}`, + matched_amount: '1.5', + order_id: 'order-1', + outcome: 'Yes', + owner: 'owner-1', + price: '0.5', + side: 'BUY', + }, + ], + market: `0x${'cc'.repeat(32)}`, + outcome: 'Yes', + owner: 'owner-1', + price: '0.5', + side: 'BUY', + size: '1.5', + status: 'CONFIRMED', + taker_order_id: 'order-2', + trader_side: 'TAKER', + transaction_hash: `0x${'dd'.repeat(32)}`, +}; + +describe('ClobTradeSchema', () => { + it('normalizes legacy epoch seconds timestamp strings', () => { + const trade = ClobTradeSchema.parse({ + ...baseTrade, + match_time: '1777996829', + last_update: '1777996840', + }); + + expect(trade.matchedAt).toBe('2026-05-05T16:00:29.000Z'); + expect(trade.updatedAt).toBe('2026-05-05T16:00:40.000Z'); + }); +}); diff --git a/packages/bindings/src/clob/account.ts b/packages/bindings/src/clob/account.ts index 8f4cbb1..127d119 100644 --- a/packages/bindings/src/clob/account.ts +++ b/packages/bindings/src/clob/account.ts @@ -10,6 +10,7 @@ import { NotificationIdSchema, OptionalEpochMillisecondsToIsoDateTimeStringSchema, TokenIdSchema, + toIsoDateTimeString, } from '../shared'; function createCursorPageSchema(item: TItem) { @@ -119,17 +120,30 @@ export const MakerOrderSchema = z }), ); +const ClobTradeTimestampSchema = z.union([ + z + .union([z.number().int(), z.string().regex(/^\d+$/).transform(Number)]) + .transform((value) => + toIsoDateTimeString( + new Date( + value < 1_000_000_000_000 ? value * 1000 : value, + ).toISOString(), + ), + ), + z.string().transform(toIsoDateTimeString), +]); + export const ClobTradeSchema = z .object({ asset_id: TokenIdSchema, bucket_index: z.number(), fee_rate_bps: DecimalStringSchema, id: z.string(), - last_update: EpochMillisecondsToIsoDateTimeStringSchema, + last_update: ClobTradeTimestampSchema, maker_address: z.string(), maker_orders: z.array(MakerOrderSchema), market: z.string(), - match_time: EpochMillisecondsToIsoDateTimeStringSchema, + match_time: ClobTradeTimestampSchema, outcome: z.string(), owner: z.string(), price: DecimalStringSchema, From aa0e1805dacbb065c1890df3f042f1114540858c Mon Sep 17 00:00:00 2001 From: Cesare Naldi <3353250+cesarenaldi@users.noreply.github.com> Date: Thu, 4 Jun 2026 15:04:04 +0200 Subject: [PATCH 2/6] move account trades to unified endpoint --- .changeset/lazy-trades-fix.md | 2 +- packages/bindings/src/clob/account.test.ts | 15 ++-- packages/bindings/src/clob/account.ts | 48 +++++------ packages/client/src/actions/account.test.ts | 91 +++++++++++++++++++++ packages/client/src/actions/account.ts | 53 +++++++----- 5 files changed, 154 insertions(+), 55 deletions(-) create mode 100644 packages/client/src/actions/account.test.ts diff --git a/.changeset/lazy-trades-fix.md b/.changeset/lazy-trades-fix.md index 2e40237..ea1170f 100644 --- a/.changeset/lazy-trades-fix.md +++ b/.changeset/lazy-trades-fix.md @@ -3,4 +3,4 @@ "@polymarket/bindings": patch --- -Fix account trade timestamp parsing for legacy CLOB epoch-seconds values. +Move account trade listing to the unified CLOB account trades endpoint. diff --git a/packages/bindings/src/clob/account.test.ts b/packages/bindings/src/clob/account.test.ts index 5a64b26..afcaad1 100644 --- a/packages/bindings/src/clob/account.test.ts +++ b/packages/bindings/src/clob/account.test.ts @@ -2,14 +2,13 @@ import { describe, expect, it } from 'vitest'; import { ClobTradeSchema } from './account'; const baseTrade = { - asset_id: '1', + token_id: '1', bucket_index: 7, fee_rate_bps: '0', id: 'trade-1', maker_address: `0x${'aa'.repeat(20)}`, maker_orders: [ { - asset_id: '1', fee_rate_bps: '0', maker_address: `0x${'bb'.repeat(20)}`, matched_amount: '1.5', @@ -18,9 +17,10 @@ const baseTrade = { owner: 'owner-1', price: '0.5', side: 'BUY', + token_id: '1', }, ], - market: `0x${'cc'.repeat(32)}`, + market_id: `0x${'cc'.repeat(32)}`, outcome: 'Yes', owner: 'owner-1', price: '0.5', @@ -33,13 +33,16 @@ const baseTrade = { }; describe('ClobTradeSchema', () => { - it('normalizes legacy epoch seconds timestamp strings', () => { + it('normalizes unified account trade responses', () => { const trade = ClobTradeSchema.parse({ ...baseTrade, - match_time: '1777996829', - last_update: '1777996840', + match_time: 1_777_996_829_000, + last_update: 1_777_996_840_000, }); + expect(trade.market).toBe(baseTrade.market_id); + expect(trade.tokenId).toBe(baseTrade.token_id); + expect(trade.makerOrders[0]?.tokenId).toBe('1'); expect(trade.matchedAt).toBe('2026-05-05T16:00:29.000Z'); expect(trade.updatedAt).toBe('2026-05-05T16:00:40.000Z'); }); diff --git a/packages/bindings/src/clob/account.ts b/packages/bindings/src/clob/account.ts index 127d119..d4ffe91 100644 --- a/packages/bindings/src/clob/account.ts +++ b/packages/bindings/src/clob/account.ts @@ -10,7 +10,6 @@ import { NotificationIdSchema, OptionalEpochMillisecondsToIsoDateTimeStringSchema, TokenIdSchema, - toIsoDateTimeString, } from '../shared'; function createCursorPageSchema(item: TItem) { @@ -92,7 +91,6 @@ export type OpenOrdersPage = z.infer; export const MakerOrderSchema = z .object({ - asset_id: TokenIdSchema, fee_rate_bps: DecimalStringSchema, maker_address: z.string(), matched_amount: DecimalStringSchema, @@ -101,18 +99,19 @@ export const MakerOrderSchema = z owner: z.string(), price: DecimalStringSchema, side: z.string(), + token_id: TokenIdSchema, }) .transform( ({ - asset_id, fee_rate_bps, maker_address, matched_amount, order_id, + token_id, ...rest }) => ({ ...rest, - tokenId: asset_id, + tokenId: token_id, feeRateBps: fee_rate_bps, makerAddress: maker_address, matchedAmount: matched_amount, @@ -120,30 +119,17 @@ export const MakerOrderSchema = z }), ); -const ClobTradeTimestampSchema = z.union([ - z - .union([z.number().int(), z.string().regex(/^\d+$/).transform(Number)]) - .transform((value) => - toIsoDateTimeString( - new Date( - value < 1_000_000_000_000 ? value * 1000 : value, - ).toISOString(), - ), - ), - z.string().transform(toIsoDateTimeString), -]); - export const ClobTradeSchema = z .object({ - asset_id: TokenIdSchema, + token_id: TokenIdSchema, bucket_index: z.number(), - fee_rate_bps: DecimalStringSchema, + fee_rate_bps: DecimalStringSchema.optional(), id: z.string(), - last_update: ClobTradeTimestampSchema, + last_update: EpochMillisecondsToIsoDateTimeStringSchema, maker_address: z.string(), maker_orders: z.array(MakerOrderSchema), - market: z.string(), - match_time: ClobTradeTimestampSchema, + market_id: z.string(), + match_time: EpochMillisecondsToIsoDateTimeStringSchema, outcome: z.string(), owner: z.string(), price: DecimalStringSchema, @@ -152,16 +138,17 @@ export const ClobTradeSchema = z status: z.string(), taker_order_id: z.string(), trader_side: z.enum(['TAKER', 'MAKER']), - transaction_hash: z.string(), + transaction_hash: z.string().optional(), }) .transform( ({ - asset_id, + token_id, bucket_index, fee_rate_bps, last_update, maker_address, maker_orders, + market_id, match_time, taker_order_id, trader_side, @@ -169,7 +156,8 @@ export const ClobTradeSchema = z ...rest }) => ({ ...rest, - tokenId: asset_id, + market: market_id, + tokenId: token_id, bucketIndex: bucket_index, feeRateBps: fee_rate_bps, updatedAt: last_update, @@ -184,7 +172,15 @@ export const ClobTradeSchema = z export type ClobTrade = z.infer; -export const ClobTradesPageSchema = createCursorPageSchema(ClobTradeSchema); +export const ClobTradesPageSchema = z + .object({ + data: z.array(ClobTradeSchema), + has_more: z.boolean(), + }) + .transform(({ has_more, ...rest }) => ({ + ...rest, + hasMore: has_more, + })); export type ClobTradesPage = z.infer; diff --git a/packages/client/src/actions/account.test.ts b/packages/client/src/actions/account.test.ts new file mode 100644 index 0000000..9014780 --- /dev/null +++ b/packages/client/src/actions/account.test.ts @@ -0,0 +1,91 @@ +import { HttpResponse, http } from 'msw'; +import { setupServer } from 'msw/node'; +import { afterAll, afterEach, beforeAll, describe, expect, it } from 'vitest'; +import type { BaseSecureClient } from '../clients'; +import { ServiceClient } from '../ServiceClient'; +import { listAccountTrades } from './account'; + +const clobRoot = 'http://localhost:4020'; +const server = setupServer(); + +const trade = { + id: 'trade-1', + taker_order_id: 'order-1', + market_id: `0x${'aa'.repeat(32)}`, + token_id: '1', + side: 'BUY', + size: '1', + fee_rate_bps: '0', + price: '0.5', + status: 'TRADE_STATUS_CONFIRMED', + match_time: 1_777_996_829_000, + last_update: 1_777_996_840_000, + outcome: 'Yes', + bucket_index: 7, + owner: 'owner-1', + maker_address: `0x${'bb'.repeat(20)}`, + transaction_hash: `0x${'cc'.repeat(32)}`, + maker_orders: [ + { + order_id: 'maker-order-1', + owner: 'owner-2', + maker_address: `0x${'dd'.repeat(20)}`, + matched_amount: '1', + price: '0.5', + fee_rate_bps: '0', + token_id: '1', + outcome: 'Yes', + side: 'SELL', + }, + ], + trader_side: 'TAKER', +}; + +describe('listAccountTrades', () => { + beforeAll(() => { + server.listen({ onUnhandledRequest: 'bypass' }); + }); + + afterEach(() => { + server.resetHandlers(); + }); + + afterAll(() => { + server.close(); + }); + + it('uses the unified account trades endpoint with offset pagination', async () => { + const requests: URL[] = []; + const client = { + secureClob: new ServiceClient({ root: clobRoot }), + } as BaseSecureClient; + + server.use( + http.get(`${clobRoot}/v1/account/trades`, ({ request }) => { + const url = new URL(request.url); + requests.push(url); + + return HttpResponse.json({ + data: [trade], + has_more: url.searchParams.get('offset') === '0', + }); + }), + ); + + const trades = listAccountTrades(client, { + market: trade.market_id, + tokenId: trade.token_id, + }); + const firstPage = await trades.firstPage(); + const secondPage = await trades.from(firstPage.nextCursor).firstPage(); + + expect(firstPage.hasMore).toBe(true); + expect(secondPage.hasMore).toBe(false); + expect(requests).toHaveLength(2); + expect(requests[0]?.pathname).toBe('/v1/account/trades'); + expect(requests[0]?.searchParams.get('market_id')).toBe(trade.market_id); + expect(requests[0]?.searchParams.get('token_id')).toBe(trade.token_id); + expect(requests[0]?.searchParams.get('offset')).toBe('0'); + expect(requests[1]?.searchParams.get('offset')).toBe('300'); + }); +}); diff --git a/packages/client/src/actions/account.ts b/packages/client/src/actions/account.ts index 668aba7..31252b9 100644 --- a/packages/client/src/actions/account.ts +++ b/packages/client/src/actions/account.ts @@ -40,7 +40,13 @@ import { UserInputError, } from '../errors'; import { parseUserInput } from '../input'; -import { PageSizeSchema, type Paginated, paginate } from '../pagination'; +import { + decodeOffsetCursor, + encodeOffsetCursor, + PageSizeSchema, + type Paginated, + paginate, +} from '../pagination'; import { validateWith } from '../response'; import { toSignatureType } from '../wallet'; import { snakeCase, toSearchParams } from './params'; @@ -240,6 +246,8 @@ const ListAccountTradesRequestSchema = z .object(ListAccountTradesRequestFields) .default({}); +const ACCOUNT_TRADES_PAGE_SIZE = 300; + export type ListAccountTradesRequest = z.input< typeof ListAccountTradesRequestSchema >; @@ -303,27 +311,28 @@ export function listAccountTrades( ListAccountTradesRequestSchema, ); - return paginate( - (nextCursor) => - client.secureClob - .get('/data/trades', { - params: toSearchParams( - { ...params, nextCursor }, - snakeCase({ tokenId: 'asset_id' }), - ), - }) - .andThen(validateWith(ClobTradesPageSchema)) - .map((response) => ({ - items: response.data, - hasMore: response.nextCursor !== END_CURSOR, - nextCursor: - response.nextCursor === END_CURSOR - ? undefined - : toPaginationCursor(response.nextCursor), - totalCount: response.count, - })), - cursor, - ); + return paginate((nextCursor) => { + const decoded = decodeOffsetCursor(nextCursor, ACCOUNT_TRADES_PAGE_SIZE); + + return client.secureClob + .get('/v1/account/trades', { + params: toSearchParams( + { ...params, offset: decoded.offset }, + snakeCase({ market: 'market_id', tokenId: 'token_id' }), + ), + }) + .andThen(validateWith(ClobTradesPageSchema)) + .map((response) => ({ + items: response.data, + hasMore: response.hasMore, + nextCursor: response.hasMore + ? encodeOffsetCursor({ + offset: decoded.offset + ACCOUNT_TRADES_PAGE_SIZE, + pageSize: ACCOUNT_TRADES_PAGE_SIZE, + }) + : undefined, + })); + }, cursor); } export type FetchNotificationsError = From a3213b094dfdb55895f02180c300653a574c15b3 Mon Sep 17 00:00:00 2001 From: Cesare Naldi <3353250+cesarenaldi@users.noreply.github.com> Date: Thu, 4 Jun 2026 15:12:29 +0200 Subject: [PATCH 3/6] clarify account trades backend limit --- packages/client/src/actions/account.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/client/src/actions/account.ts b/packages/client/src/actions/account.ts index 31252b9..56a08e0 100644 --- a/packages/client/src/actions/account.ts +++ b/packages/client/src/actions/account.ts @@ -246,7 +246,7 @@ const ListAccountTradesRequestSchema = z .object(ListAccountTradesRequestFields) .default({}); -const ACCOUNT_TRADES_PAGE_SIZE = 300; +const ACCOUNT_TRADES_BACKEND_LIMIT = 300; export type ListAccountTradesRequest = z.input< typeof ListAccountTradesRequestSchema @@ -312,7 +312,10 @@ export function listAccountTrades( ); return paginate((nextCursor) => { - const decoded = decodeOffsetCursor(nextCursor, ACCOUNT_TRADES_PAGE_SIZE); + const decoded = decodeOffsetCursor( + nextCursor, + ACCOUNT_TRADES_BACKEND_LIMIT, + ); return client.secureClob .get('/v1/account/trades', { @@ -327,8 +330,8 @@ export function listAccountTrades( hasMore: response.hasMore, nextCursor: response.hasMore ? encodeOffsetCursor({ - offset: decoded.offset + ACCOUNT_TRADES_PAGE_SIZE, - pageSize: ACCOUNT_TRADES_PAGE_SIZE, + offset: decoded.offset + ACCOUNT_TRADES_BACKEND_LIMIT, + pageSize: ACCOUNT_TRADES_BACKEND_LIMIT, }) : undefined, })); From 9972b088233aac63da29e04b054908693465d182 Mon Sep 17 00:00:00 2001 From: Cesare Naldi <3353250+cesarenaldi@users.noreply.github.com> Date: Thu, 4 Jun 2026 15:15:46 +0200 Subject: [PATCH 4/6] remove account trades transport test --- packages/client/src/actions/account.test.ts | 91 --------------------- 1 file changed, 91 deletions(-) delete mode 100644 packages/client/src/actions/account.test.ts diff --git a/packages/client/src/actions/account.test.ts b/packages/client/src/actions/account.test.ts deleted file mode 100644 index 9014780..0000000 --- a/packages/client/src/actions/account.test.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { HttpResponse, http } from 'msw'; -import { setupServer } from 'msw/node'; -import { afterAll, afterEach, beforeAll, describe, expect, it } from 'vitest'; -import type { BaseSecureClient } from '../clients'; -import { ServiceClient } from '../ServiceClient'; -import { listAccountTrades } from './account'; - -const clobRoot = 'http://localhost:4020'; -const server = setupServer(); - -const trade = { - id: 'trade-1', - taker_order_id: 'order-1', - market_id: `0x${'aa'.repeat(32)}`, - token_id: '1', - side: 'BUY', - size: '1', - fee_rate_bps: '0', - price: '0.5', - status: 'TRADE_STATUS_CONFIRMED', - match_time: 1_777_996_829_000, - last_update: 1_777_996_840_000, - outcome: 'Yes', - bucket_index: 7, - owner: 'owner-1', - maker_address: `0x${'bb'.repeat(20)}`, - transaction_hash: `0x${'cc'.repeat(32)}`, - maker_orders: [ - { - order_id: 'maker-order-1', - owner: 'owner-2', - maker_address: `0x${'dd'.repeat(20)}`, - matched_amount: '1', - price: '0.5', - fee_rate_bps: '0', - token_id: '1', - outcome: 'Yes', - side: 'SELL', - }, - ], - trader_side: 'TAKER', -}; - -describe('listAccountTrades', () => { - beforeAll(() => { - server.listen({ onUnhandledRequest: 'bypass' }); - }); - - afterEach(() => { - server.resetHandlers(); - }); - - afterAll(() => { - server.close(); - }); - - it('uses the unified account trades endpoint with offset pagination', async () => { - const requests: URL[] = []; - const client = { - secureClob: new ServiceClient({ root: clobRoot }), - } as BaseSecureClient; - - server.use( - http.get(`${clobRoot}/v1/account/trades`, ({ request }) => { - const url = new URL(request.url); - requests.push(url); - - return HttpResponse.json({ - data: [trade], - has_more: url.searchParams.get('offset') === '0', - }); - }), - ); - - const trades = listAccountTrades(client, { - market: trade.market_id, - tokenId: trade.token_id, - }); - const firstPage = await trades.firstPage(); - const secondPage = await trades.from(firstPage.nextCursor).firstPage(); - - expect(firstPage.hasMore).toBe(true); - expect(secondPage.hasMore).toBe(false); - expect(requests).toHaveLength(2); - expect(requests[0]?.pathname).toBe('/v1/account/trades'); - expect(requests[0]?.searchParams.get('market_id')).toBe(trade.market_id); - expect(requests[0]?.searchParams.get('token_id')).toBe(trade.token_id); - expect(requests[0]?.searchParams.get('offset')).toBe('0'); - expect(requests[1]?.searchParams.get('offset')).toBe('300'); - }); -}); From d39b5f20c305ab8c76453bf0846356c20dcf7bc0 Mon Sep 17 00:00:00 2001 From: Cesare Naldi <3353250+cesarenaldi@users.noreply.github.com> Date: Thu, 4 Jun 2026 15:17:38 +0200 Subject: [PATCH 5/6] set account trades sdk page size --- packages/client/src/actions/account.ts | 32 ++++++++++++++------------ 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/packages/client/src/actions/account.ts b/packages/client/src/actions/account.ts index 56a08e0..86d23e4 100644 --- a/packages/client/src/actions/account.ts +++ b/packages/client/src/actions/account.ts @@ -246,7 +246,7 @@ const ListAccountTradesRequestSchema = z .object(ListAccountTradesRequestFields) .default({}); -const ACCOUNT_TRADES_BACKEND_LIMIT = 300; +const ACCOUNT_TRADES_PAGE_SIZE = 50; export type ListAccountTradesRequest = z.input< typeof ListAccountTradesRequestSchema @@ -312,10 +312,7 @@ export function listAccountTrades( ); return paginate((nextCursor) => { - const decoded = decodeOffsetCursor( - nextCursor, - ACCOUNT_TRADES_BACKEND_LIMIT, - ); + const decoded = decodeOffsetCursor(nextCursor, ACCOUNT_TRADES_PAGE_SIZE); return client.secureClob .get('/v1/account/trades', { @@ -325,16 +322,21 @@ export function listAccountTrades( ), }) .andThen(validateWith(ClobTradesPageSchema)) - .map((response) => ({ - items: response.data, - hasMore: response.hasMore, - nextCursor: response.hasMore - ? encodeOffsetCursor({ - offset: decoded.offset + ACCOUNT_TRADES_BACKEND_LIMIT, - pageSize: ACCOUNT_TRADES_BACKEND_LIMIT, - }) - : undefined, - })); + .map((response) => { + const hasMore = + response.hasMore || response.data.length > decoded.pageSize; + + return { + items: response.data.slice(0, decoded.pageSize), + hasMore, + nextCursor: hasMore + ? encodeOffsetCursor({ + offset: decoded.offset + decoded.pageSize, + pageSize: decoded.pageSize, + }) + : undefined, + }; + }); }, cursor); } From 2315dc1c1f93eedcca68b9ede2bff32026221fa4 Mon Sep 17 00:00:00 2001 From: Cesare Naldi <3353250+cesarenaldi@users.noreply.github.com> Date: Thu, 4 Jun 2026 16:38:31 +0200 Subject: [PATCH 6/6] advance account trades cursor by returned items --- packages/client/src/actions/account.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/client/src/actions/account.ts b/packages/client/src/actions/account.ts index 86d23e4..cbd3ef0 100644 --- a/packages/client/src/actions/account.ts +++ b/packages/client/src/actions/account.ts @@ -323,15 +323,17 @@ export function listAccountTrades( }) .andThen(validateWith(ClobTradesPageSchema)) .map((response) => { + const items = response.data.slice(0, decoded.pageSize); const hasMore = - response.hasMore || response.data.length > decoded.pageSize; + items.length > 0 && + (response.hasMore || response.data.length > decoded.pageSize); return { - items: response.data.slice(0, decoded.pageSize), + items, hasMore, nextCursor: hasMore ? encodeOffsetCursor({ - offset: decoded.offset + decoded.pageSize, + offset: decoded.offset + items.length, pageSize: decoded.pageSize, }) : undefined,