Skip to content

fix(clob): tolerate empty-string Decimals and missing tx_hash when deserializing fills - #65

Open
popoxhb wants to merge 1 commit into
Polymarket:mainfrom
popoxhb:fix/clob-empty-string-fills
Open

fix(clob): tolerate empty-string Decimals and missing tx_hash when deserializing fills#65
popoxhb wants to merge 1 commit into
Polymarket:mainfrom
popoxhb:fix/clob-empty-string-fills

Conversation

@popoxhb

@popoxhb popoxhb commented Jun 7, 2026

Copy link
Copy Markdown

Problem

The live Polymarket CLOB API occasionally serializes Decimal money fields as empty strings ("") and omits transaction_hash for maker fills that are not yet on-chain. With the current strict typing this makes the entire /trades response batch fail to deserialize — a single "" in one record fails the whole Page<TradeResponse> parse, silently dropping every fill in that batch.

Observed in production on GET /trades:

  • TradeResponse.size, TradeResponse.fee_rate_bps, TradeResponse.price → sometimes ""
  • MakerOrder.matched_amount, MakerOrder.price, MakerOrder.fee_rate_bps → sometimes ""
  • TradeResponse.transaction_hash → absent for maker fills not yet settled on-chain

Fix

  • Apply the existing empty_string_as_zero deserializer (already used on PostOrderResponse.making_amount / taking_amount) to the six Decimal fields above, so "" parses as Decimal::ZERO instead of erroring.
  • Mark TradeResponse.transaction_hash as #[serde(default)], so a missing hash deserializes to B256::default() (the zero hash) rather than failing.

Compatibility

Backward compatible: well-formed responses with present, non-empty values deserialize exactly as before. Only the previously-fatal empty/missing cases change — from "whole batch errors out" to "that field is zero / default". empty_string_as_zero already exists in response.rs, so this is attribute-only — no new helpers and no API/signature changes.


Note

Low Risk
Attribute-only serde changes on response DTOs; no API or logic changes, with backward-compatible parsing for well-formed payloads.

Overview
Hardens /trades deserialization so a single malformed field no longer fails an entire Page<TradeResponse> batch from the live CLOB API.

On TradeResponse, size, fee_rate_bps, and price now use the existing empty_string_as_zero deserializer (same pattern as PostOrderResponse), so "" becomes Decimal::ZERO. transaction_hash gets #[serde(default)], so omitted hashes (e.g. maker fills not yet on-chain) deserialize to the default B256 instead of erroring.

On MakerOrder, matched_amount, price, and fee_rate_bps get the same empty_string_as_zero treatment. Normal non-empty values behave unchanged; only previously fatal empty/missing wire shapes are relaxed.

Reviewed by Cursor Bugbot for commit d36cc61. Bugbot is set up for automated code reviews on this repo. Configure here.

The live Polymarket CLOB /trades endpoint occasionally returns empty strings for the Decimal money fields on TradeResponse (size, fee_rate_bps, price) and MakerOrder (matched_amount, price, fee_rate_bps), and omits TradeResponse.transaction_hash for maker fills that are not yet on-chain. Either case makes the whole trades batch fail to deserialize and silently drops every fill.

Reuse the existing empty_string_as_zero deserializer (already applied to PostOrderResponse making/taking amounts) on those fields, and mark transaction_hash #[serde(default)] so a missing hash deserializes to B256::default().

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant