Skip to content

SDK drift: Escrow.withdraw_tx amount type is narrower in Python (float only) than TypeScript's withdrawTx (number|string|bigint) and Python's own deposit_tx (float|Decimal) #1615

Description

@realfishsam

Drift

Escrow.depositTx/deposit_tx and Escrow.withdrawTx/withdraw_tx are meant to accept the same set of amount representations (both route through the same normalizeUsdcAmount helper in TypeScript). In TypeScript, both entry points accept number | string | bigint. In Python, deposit_tx accepts float | Decimal, but withdraw_tx only accepts float — it is missing Decimal entirely, and neither method accepts a str/int-like precision-safe type. This means Python's own two escrow-amount methods have inconsistent type contracts with each other, and withdraw_tx specifically is the narrowest of all four (TS deposit, TS withdraw, Python deposit, Python withdraw).

TypeScript SDK

sdks/typescript/pmxt/escrow.ts:84

function normalizeUsdcAmount(value: number | string | bigint, field: string = "amount"): number | string {

Used by both:

  • sdks/typescript/pmxt/escrow.ts:139async depositTx(amount: number | string | bigint): Promise<unknown>
  • sdks/typescript/pmxt/escrow.ts:158async withdrawTx(action: "request" | "claim" | "cancel", amount?: number | string | bigint): Promise<unknown>

Both depositTx and withdrawTx accept the identical number | string | bigint union.

Python SDK

sdks/python/pmxt/escrow.py:125

def deposit_tx(self, amount: float | Decimal) -> dict[str, Any]:

sdks/python/pmxt/escrow.py:134-137

def withdraw_tx(
    self,
    action: str,
    amount: float | None = None,
) -> dict[str, Any]:

withdraw_tx's amount parameter is typed float | None only — no Decimal, no str, no int. This is narrower than deposit_tx (which at least accepts Decimal), and narrower still than TypeScript's withdrawTx.

Expected

withdraw_tx's accepted amount type should match deposit_tx's (float | Decimal) at minimum, for internal Python consistency. Beyond that, both Python methods should ideally accept the same precision-safe representations TypeScript's normalizeUsdcAmount supports (string for exact-precision decimal input), matching TypeScript's depositTx/withdrawTx contract.

Impact

A Python caller who successfully passes a Decimal to deposit_tx (to avoid float precision loss) will hit a type-contract violation if they try to do the same for withdraw_tx — the declared type doesn't allow it, and depending on how the value is used downstream, this can silently reintroduce the float-precision-loss problem for withdrawals that Decimal was meant to avoid for deposits. TypeScript callers can safely pass a bigint/decimal string to either depositTx or withdrawTx, but Python callers have no consistent precision-safe path for withdrawals.


Found by automated SDK cross-language drift audit

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions