Skip to content

fix(common): don't mutate the caller's options in decimalize()/undecimalize() - #233

Open
Kshot3000 wants to merge 1 commit into
fleet-sdk:masterfrom
Kshot3000:fix/bigint-options-mutation
Open

Kshot3000 wants to merge 1 commit into
fleet-sdk:masterfrom
Kshot3000:fix/bigint-options-mutation

Conversation

@Kshot3000

Copy link
Copy Markdown

Summary

decimalize() and undecimalize() in @fleet-sdk/common (packages/common/src/utils/bigInt.ts) wrote their resolved defaults back into the caller's options object:

options.decimals = options.decimals || 0;
options.decimalMark = options.decimalMark || ".";

Two observable effects:

  • The caller's object comes back changed. Passing { decimals: 2 } returns with a decimalMark: "." the caller never set. These helpers are exactly the kind that get called with shared or reused option objects — the spec's own roundtrip test passes one options object to both functions — so the writes leak resolved defaults into caller state.
  • A frozen options object throws. decimalize(1763874n, Object.freeze({ decimals: 2 })) throws TypeError: Cannot assign to read only property 'decimals', and undecimalize("1.23", Object.freeze({})) throws TypeError: Cannot add property decimals, object is not extensible — even though both functions only ever read from the object.

Fix

Resolve decimals/decimalMark into local variables (keeping the exact same || default semantics, including an explicitly-undefined field falling back to the default) and pass a fresh object to buildFormattedDecimal. The caller's object is never written to. All outputs are byte-identical — every pre-existing vector passes unchanged.

Tests

Five new cases in bigInt.spec.ts, all failing on pristine master:

  • decimalize: should not mutate the caller's options object — deep-equal mismatch on pristine ({ decimals: 2 } gained decimalMark).
  • decimalize: should accept a frozen options object — previously threw TypeError.
  • undecimalize: should not mutate the caller's options object — same deep-equal mismatch.
  • undecimalize: should accept a frozen options object — previously threw TypeError.
  • undecimalize: should accept frozen options relying on defaults — previously threw TypeError (adding a property to a non-extensible object).

Results: bigInt spec 21/21; full monorepo suite 1137/1137 (66 files); biome clean on the changed files. Changeset included (@fleet-sdk/common: patch).


Independent community contribution — @Kshot9000 (https://x.com/kshot9000). If this work is useful, tips are welcome: ERG 9fcM5RWnAjmP4vx5bnW6yohB6H9bLq8sJbaPLHtwZLtQPB32Pvy

@changeset-bot

changeset-bot Bot commented Oct 9, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b207c86

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@fleet-sdk/common Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

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