Skip to content

Both SDKs type PaginatedMarketsResult.total/PaginatedEventsResult.total as optional; core always populates it and declares it required #2365

Open

Description

@realfishsam

Gap

Core's PaginatedMarketsResult and PaginatedEventsResult interfaces declare total: number as a required field, and every code path in fetchMarketsPaginated/fetchEventsPaginated always populates it (there is no branch that omits or nulls it). Both SDKs instead type total as optional/nullable (total?: number in TypeScript, total: Optional[int] = None in Python), which is a narrower/weaker contract than what core actually guarantees. This is the same class of type-narrowing bug already tracked for UnifiedMarket.description (#1397) and UnifiedEvent.volume24h (#1398), but for a different pair of types that neither of those issues covers.

Core

core/src/BaseExchange.ts:417-423:

export interface PaginatedMarketsResult {
    /** The page of unified markets */
    data: UnifiedMarket[];
    /** Total number of markets in the snapshot */
    total: number;
    /** Cursor to pass to the next call, or undefined if this is the last page */
    nextCursor?: string;
}

and :427-433 for the near-identical PaginatedEventsResult. Every return site in fetchMarketsPaginated (BaseExchange.ts:805,824,829) and fetchEventsPaginated (:874,893,898) always sets total: markets.length / total: events.length — there is no code path that returns these types without total.

TypeScript SDK

sdks/typescript/pmxt/models.ts:254-257 and :268-271:

export interface PaginatedMarketsResult {
    data: UnifiedMarket[];
    /** Total number of markets (if available) */
    total?: number;
    nextCursor?: string;
}

(same optional total?: number pattern for PaginatedEventsResult).

Python SDK

sdks/python/pmxt/models.py:424-434:

class PaginatedMarketsResult:
    data: "List[UnifiedMarket]"
    total: Optional[int] = None
    """Total number of markets in the snapshot"""
    next_cursor: Optional[str] = None

(same Optional[int] = None pattern for PaginatedEventsResult, models.py:437-447).

Evidence

Grepped total in core/src/BaseExchange.ts and confirmed the interface declares total: number (required) while every constructing call site always assigns it a real value (markets.length/events.length, never omitted or undefined). Grepped total in sdks/typescript/pmxt/models.ts and read sdks/python/pmxt/models.py:424-447 directly — both SDKs declare the field optional/nullable, which is strictly weaker than what core guarantees.

Impact

Consumers of both SDKs must null-check result.total (TypeScript: result.total ?? 0, Python: if result.total is not None) even though it is always present in practice, adding unnecessary defensive code and hiding a reliable field behind an inaccurate optional type. This is minor on its own but is the same avoidable-narrowing pattern already flagged for other fields (#1397, #1398), and consistency here would let SDK consumers drop the same null-guard everywhere pagination results are used.


Found by automated Core-to-SDK surface coverage audit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions