Skip to content

fix: catch fetch errors in ensureBuilderFeeRateCached for browser compatibility - #96

Open
osr21 wants to merge 2 commits into
Polymarket:mainfrom
osr21:fix/browser-cors-builder-fee-fetch
Open

fix: catch fetch errors in ensureBuilderFeeRateCached for browser compatibility#96
osr21 wants to merge 2 commits into
Polymarket:mainfrom
osr21:fix/browser-cors-builder-fee-fetch

Conversation

@osr21

@osr21 osr21 commented Jul 24, 2026

Copy link
Copy Markdown

Problem

@polymarket/clob-client-v2 v1.0.1+ calls GET /fees/builder-fees/<code> inside ensureBuilderFeeRateCached on every createOrder() and createMarketOrder() call. This endpoint returns 404 with no CORS headers, which causes an immediate network/CORS error in any browser environment (Next.js, React, Vite, etc.) — before any order is signed or submitted.

The result: order creation is completely broken in browsers for any user on v1.0.1+, even if they never set a builderCode. This is because the method is also invoked via getBuilderTakerFeeRate on the createMarketOrder path.

Root cause

private async ensureBuilderFeeRateCached(builderCode?: string): Promise<void> {
    if (!builderCode || builderCode === bytes32Zero) return; // ← guards undefined/zero
    if (builderCode in this.builderFeeRates) return;        // ← cache hit

    // ↓ throws CORS error in browsers — endpoint has no Access-Control-Allow-Origin
    const result = await this.get(`${this.host}${GET_BUILDER_FEES}${builderCode}`);
    ...
}

Fix

Wrap the fetch in try/catch. On failure, default to { maker: 0, taker: 0 }. Builder fees are additive — defaulting to zero is safe and means order creation is not gated on a non-critical endpoint.

try {
    const result = await this.get(`${this.host}${GET_BUILDER_FEES}${builderCode}`);
    this.builderFeeRates[builderCode] = {
        maker: result.builder_maker_fee_rate_bps / BUILDER_FEES_BPS,
        taker: result.builder_taker_fee_rate_bps / BUILDER_FEES_BPS,
    };
} catch {
    // Endpoint returns 404 with no CORS headers in browser environments.
    // Default to zero so order creation is not blocked. Fixes #51.
    this.builderFeeRates[builderCode] = { maker: 0, taker: 0 };
}

Closes #51.


Note

Low Risk
Small defensive change on a non-critical fee lookup; worst case is underestimating builder fees in the browser when the API is unreachable.

Overview
ensureBuilderFeeRateCached no longer lets a failed GET /fees/builder-fees/<code> abort order flows. The fetch is wrapped in try/catch, and on error the client caches { maker: 0, taker: 0 } so createMarketOrder / buy-balance paths that call this helper can continue when the endpoint errors (e.g. 404 without CORS in the browser).

The catch path only writes that zero fallback if the cache slot is still empty, so a concurrent successful fetch is not overwritten.

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

GET /fees/builder-fees/<code> returns 404 with no CORS headers. In browser
environments (Next.js, React, Vite etc.) every call to createOrder() or
createMarketOrder() therefore throws a CORS/network error before any order
is built, regardless of whether the user has a builderCode configured.

Fix: wrap the fetch in a try/catch. On failure default to {maker:0, taker:0}
so order creation is not blocked. The builder fee lookup is best-effort;
a non-fatal network or 404 error should not gate trading. Fixes Polymarket#51.
@osr21
osr21 requested a review from a team as a code owner July 24, 2026 13:44

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit 7c68f68. Configure here.

Comment thread src/client.ts Outdated
…all race

If two callers invoke ensureBuilderFeeRateCached for the same builderCode
concurrently, one fetch may succeed while the other fails. The original
catch path unconditionally wrote { maker:0, taker:0 }, so whichever
settled last would win — the failure could silently replace real rates
with zeros for the rest of the client lifetime.

Fix: only write the zero fallback when the cache slot is still empty,
i.e. the successful path has not already populated it. Addressed feedback
from Cursor Bugbot review on PR Polymarket#96.
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.

Bug Report: @polymarket/clob-client-v2ensureBuilderFeeRateCached breaks browser-based order creation

1 participant