Skip to content

getSuggestedFees: decimal pct fields validated with percentageString then passed to BigInt() → SyntaxError #266

Description

@Nexory

Summary

getSuggestedFees validates the four nested pct fields (totalRelayFee.pct, relayerCapitalFee.pct, relayerGasFee.pct, lpFee.pct) using the percentageString Zod validator, whose regex is /^\d+(\.\d+)?$/. This deliberately accepts decimal strings such as "0.0005". Immediately after validation the same strings are passed to BigInt(), which throws a SyntaxError on any value that contains a decimal point. The two contracts are mutually exclusive, so a conforming API response that contains a decimal percentage will crash the function at runtime even though it passed schema validation.

What I observed

packages/sdk/src/api/validators.ts — the validator

// line 24 — regex allows decimals
export const percentageString = z.string().regex(/^\d+(\.\d+)?$/, {
  message: "Invalid percentage string format",
});

packages/sdk/src/api/suggested-fees.ts — schema usage

// lines 27, 31, 35, 39 — all four pct fields typed as percentageString
totalRelayFee:  { pct: percentageString, ... },
relayerCapitalFee: { pct: percentageString, ... },
relayerGasFee:  { pct: percentageString, ... },
lpFee:          { pct: percentageString, ... },

packages/sdk/src/actions/getSuggestedFees.ts — downstream conversion (lines 212–225)

totalRelayFee:     { pct: BigInt(raw.totalRelayFee.pct),     total: ... },
relayerCapitalFee: { pct: BigInt(raw.relayerCapitalFee.pct), total: ... },
relayerGasFee:     { pct: BigInt(raw.relayerGasFee.pct),     total: ... },
lpFee:             { pct: BigInt(raw.lpFee.pct),             total: ... },

BigInt("0.0005")SyntaxError: Cannot convert 0.0005 to a BigInt.

Note that bigNumberString and numericString (also in validators.ts) correctly restrict to integer-only patterns (/^-?\d+$/, /^\d+$/), so this is an inconsistency within the same file.

Impact

Any caller of getSuggestedFees (or the underlying fetchSuggestedFees transform) will receive an unhandled SyntaxError at runtime whenever the Across API returns a decimal string in a pct field. Because the Zod schema accepts such strings without complaint, the error arrives after validation — making it harder to diagnose and impossible to catch at the schema layer. SDK consumers who rely on fee quotes to build bridging transactions will see silent crashes.

Suggested fix

Two clean options:

Option A — tighten the validator (if the API is guaranteed to return integers):

// validators.ts
export const percentageString = z.string().regex(/^\d+$/, {
  message: "Invalid percentage string format",
});

Option B — parse through Number then scale (if the API may legitimately return decimals):

// getSuggestedFees.ts, for each pct field
pct: BigInt(Math.round(Number(raw.totalRelayFee.pct))),

Or use a helper that converts the decimal representation to a fixed-point bigint consistent with the fee precision used elsewhere in the SDK.

Option A is safer if the API contract guarantees integer percentages — it will reject malformed responses at the schema layer instead of crashing downstream. Option B is appropriate only if decimal percentages are semantically meaningful in the fee model.

Notes

The total fields in the same structs are validated with bigNumberString (integer-only) and converted via BigInt() — that path is correct. The mismatch exists only in the pct fields, which alone use percentageString.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    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