Skip to content

Add fixed-point string and number conversions#1567

Merged
lorisleiva merged 1 commit into
mainfrom
04-24-add_fixed-point_string_and_number_conversions
May 5, 2026
Merged

Add fixed-point string and number conversions#1567
lorisleiva merged 1 commit into
mainfrom
04-24-add_fixed-point_string_and_number_conversions

Conversation

@lorisleiva
Copy link
Copy Markdown
Member

This PR adds binaryFixedPointToString, decimalFixedPointToString, binaryFixedPointToNumber, and decimalFixedPointToNumber to @solana/fixed-points. The string variants accept an optional FixedPointToStringOptions bag (decimals, padTrailingZeros, rounding) and throw SOLANA_ERROR__FIXED_POINTS__STRICT_MODE_PRECISION_LOSS (with operation: 'toString') when capping requires a lossy rescale under the default 'strict' mode.

The number variants are lossy escape hatches bounded by IEEE 754's ~53-bit mantissa. binaryFixedPointToNumber splits the raw value into integer and fractional parts before coercing, preserving exactness whenever the result magnitude fits Number.MAX_SAFE_INTEGER even if the raw bigint does not.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 24, 2026

⚠️ No Changeset found

Latest commit: da94b9b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

This was referenced Apr 24, 2026
@bundlemon
Copy link
Copy Markdown

bundlemon Bot commented Apr 24, 2026

BundleMon

Files updated (4)
Status Path Size Limits
fixed-points/dist/index.browser.mjs
3.88KB (+548B +15.99%) -
fixed-points/dist/index.native.mjs
3.88KB (+547B +15.97%) -
fixed-points/dist/index.node.mjs
3.88KB (+547B +15.97%) -
@solana/kit production bundle
kit/dist/index.production.min.js
50.56KB (+360B +0.7%) -
Unchanged files (143)
Status Path Size Limits
errors/dist/index.node.mjs
20.44KB -
errors/dist/index.browser.mjs
20.42KB -
errors/dist/index.native.mjs
20.41KB -
rpc-graphql/dist/index.browser.mjs
18.82KB -
rpc-graphql/dist/index.native.mjs
18.81KB -
rpc-graphql/dist/index.node.mjs
18.81KB -
wallet-account-signer/dist/index.node.mjs
17.29KB -
wallet-account-signer/dist/index.browser.mjs
17.27KB -
wallet-account-signer/dist/index.native.mjs
17.27KB -
transaction-messages/dist/index.browser.mjs
11.32KB -
transaction-messages/dist/index.native.mjs
11.32KB -
transaction-messages/dist/index.node.mjs
11.32KB -
instruction-plans/dist/index.browser.mjs
6.58KB -
instruction-plans/dist/index.native.mjs
6.58KB -
instruction-plans/dist/index.node.mjs
6.58KB -
codecs-data-structures/dist/index.browser.mjs
5.04KB -
codecs-data-structures/dist/index.native.mjs
5.03KB -
codecs-data-structures/dist/index.node.mjs
5.03KB -
offchain-messages/dist/index.browser.mjs
4.89KB -
offchain-messages/dist/index.native.mjs
4.89KB -
offchain-messages/dist/index.node.mjs
4.89KB -
transactions/dist/index.browser.mjs
4.07KB -
transactions/dist/index.native.mjs
4.07KB -
transactions/dist/index.node.mjs
4.07KB -
kit/dist/index.browser.mjs
3.72KB -
kit/dist/index.native.mjs
3.72KB -
kit/dist/index.node.mjs
3.72KB -
codecs-core/dist/index.browser.mjs
3.62KB -
codecs-core/dist/index.native.mjs
3.62KB -
codecs-core/dist/index.node.mjs
3.62KB -
webcrypto-ed25519-polyfill/dist/index.node.mj
s
3.61KB -
webcrypto-ed25519-polyfill/dist/index.browser
.mjs
3.59KB -
webcrypto-ed25519-polyfill/dist/index.native.
mjs
3.57KB -
rpc-subscriptions/dist/index.browser.mjs
3.37KB -
rpc-subscriptions/dist/index.node.mjs
3.34KB -
rpc-subscriptions/dist/index.native.mjs
3.31KB -
signers/dist/index.browser.mjs
3.26KB -
signers/dist/index.native.mjs
3.26KB -
signers/dist/index.node.mjs
3.26KB -
rpc-transformers/dist/index.browser.mjs
3.16KB -
rpc-transformers/dist/index.native.mjs
3.16KB -
rpc-transformers/dist/index.node.mjs
3.16KB -
react/dist/index.browser.mjs
3.09KB -
react/dist/index.native.mjs
3.09KB -
react/dist/index.node.mjs
3.09KB -
keys/dist/index.node.mjs
3.06KB -
addresses/dist/index.browser.mjs
2.93KB -
addresses/dist/index.native.mjs
2.92KB -
addresses/dist/index.node.mjs
2.92KB -
keys/dist/index.browser.mjs
2.85KB -
keys/dist/index.native.mjs
2.85KB -
codecs-strings/dist/index.browser.mjs
2.55KB -
codecs-strings/dist/index.node.mjs
2.51KB -
codecs-strings/dist/index.native.mjs
2.47KB -
transaction-confirmation/dist/index.node.mjs
2.41KB -
sysvars/dist/index.browser.mjs
2.37KB -
sysvars/dist/index.native.mjs
2.37KB -
sysvars/dist/index.node.mjs
2.37KB -
transaction-confirmation/dist/index.native.mj
s
2.36KB -
transaction-confirmation/dist/index.browser.m
js
2.35KB -
rpc-subscriptions-spec/dist/index.node.mjs
2.21KB -
rpc-subscriptions-spec/dist/index.native.mjs
2.17KB -
rpc-subscriptions-spec/dist/index.browser.mjs
2.16KB -
subscribable/dist/index.node.mjs
1.97KB -
rpc/dist/index.node.mjs
1.95KB -
codecs-numbers/dist/index.browser.mjs
1.95KB -
codecs-numbers/dist/index.native.mjs
1.95KB -
codecs-numbers/dist/index.node.mjs
1.94KB -
subscribable/dist/index.native.mjs
1.92KB -
subscribable/dist/index.browser.mjs
1.91KB -
rpc-transport-http/dist/index.browser.mjs
1.91KB -
rpc-transport-http/dist/index.native.mjs
1.9KB -
rpc/dist/index.native.mjs
1.81KB -
rpc/dist/index.browser.mjs
1.8KB -
rpc-transport-http/dist/index.node.mjs
1.72KB -
rpc-types/dist/index.browser.mjs
1.53KB -
rpc-types/dist/index.native.mjs
1.53KB -
rpc-types/dist/index.node.mjs
1.53KB -
rpc-subscriptions-channel-websocket/dist/inde
x.node.mjs
1.33KB -
rpc-subscriptions-channel-websocket/dist/inde
x.native.mjs
1.27KB -
rpc-subscriptions-channel-websocket/dist/inde
x.browser.mjs
1.26KB -
program-client-core/dist/index.browser.mjs
1.21KB -
program-client-core/dist/index.native.mjs
1.21KB -
program-client-core/dist/index.node.mjs
1.21KB -
options/dist/index.browser.mjs
1.18KB -
options/dist/index.native.mjs
1.18KB -
options/dist/index.node.mjs
1.17KB -
accounts/dist/index.browser.mjs
1.17KB -
accounts/dist/index.native.mjs
1.17KB -
accounts/dist/index.node.mjs
1.16KB -
rpc-api/dist/index.browser.mjs
976B -
rpc-api/dist/index.native.mjs
975B -
rpc-api/dist/index.node.mjs
973B -
compat/dist/index.browser.mjs
969B -
compat/dist/index.native.mjs
968B -
compat/dist/index.node.mjs
966B -
rpc-spec-types/dist/index.browser.mjs
962B -
rpc-spec-types/dist/index.native.mjs
961B -
rpc-spec-types/dist/index.node.mjs
959B -
rpc-subscriptions-api/dist/index.native.mjs
870B -
rpc-subscriptions-api/dist/index.node.mjs
869B -
rpc-subscriptions-api/dist/index.browser.mjs
868B -
rpc-spec/dist/index.browser.mjs
852B -
rpc-spec/dist/index.native.mjs
851B -
rpc-spec/dist/index.node.mjs
850B -
promises/dist/index.native.mjs
841B -
promises/dist/index.node.mjs
840B -
promises/dist/index.browser.mjs
839B -
plugin-core/dist/index.browser.mjs
820B -
plugin-core/dist/index.native.mjs
819B -
plugin-core/dist/index.node.mjs
817B -
assertions/dist/index.browser.mjs
783B -
instructions/dist/index.browser.mjs
771B -
instructions/dist/index.native.mjs
770B -
instructions/dist/index.node.mjs
768B -
fast-stable-stringify/dist/index.browser.mjs
726B -
fast-stable-stringify/dist/index.native.mjs
725B -
assertions/dist/index.native.mjs
724B -
fast-stable-stringify/dist/index.node.mjs
724B -
assertions/dist/index.node.mjs
723B -
programs/dist/index.browser.mjs
329B -
programs/dist/index.native.mjs
327B -
programs/dist/index.node.mjs
325B -
fs-impl/dist/index.browser.mjs
245B -
event-target-impl/dist/index.node.mjs
230B -
functional/dist/index.browser.mjs
154B -
functional/dist/index.native.mjs
152B -
text-encoding-impl/dist/index.native.mjs
152B -
functional/dist/index.node.mjs
151B -
codecs/dist/index.browser.mjs
145B -
codecs/dist/index.native.mjs
144B -
codecs/dist/index.node.mjs
142B -
event-target-impl/dist/index.browser.mjs
133B -
ws-impl/dist/index.node.mjs
131B -
text-encoding-impl/dist/index.browser.mjs
122B -
fs-impl/dist/index.node.mjs
120B -
text-encoding-impl/dist/index.node.mjs
119B -
ws-impl/dist/index.browser.mjs
113B -
crypto-impl/dist/index.node.mjs
111B -
crypto-impl/dist/index.browser.mjs
109B -
rpc-parsed-types/dist/index.browser.mjs
66B -
rpc-parsed-types/dist/index.native.mjs
65B -
rpc-parsed-types/dist/index.node.mjs
63B -

Total files change +1.96KB +0.38%

Final result: ✅

View report in BundleMon website ➡️


Current branch size history | Target branch size history

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 24, 2026

Documentation Preview: https://kit-docs-fnq3cvfoh-anza-tech.vercel.app

@lorisleiva lorisleiva force-pushed the 04-24-add_fixed-point_string_and_number_conversions branch from dec9bf6 to 8e377fb Compare April 24, 2026 16:17
@lorisleiva lorisleiva force-pushed the 04-24-add_fixed-point_rescaling branch from 888f715 to 5612ac9 Compare April 24, 2026 16:17
@lorisleiva lorisleiva marked this pull request as ready for review April 24, 2026 16:41
@lorisleiva lorisleiva requested a review from mcintyre94 April 24, 2026 16:41
@lorisleiva lorisleiva force-pushed the 04-24-add_fixed-point_rescaling branch from 5612ac9 to d29dae8 Compare April 29, 2026 00:30
@lorisleiva lorisleiva force-pushed the 04-24-add_fixed-point_string_and_number_conversions branch from 8e377fb to 89cd89f Compare April 29, 2026 00:30
return `${sign}${integerPart}`;
}
return `${sign}${integerPart}.${fractionalPart}`;
}
Copy link
Copy Markdown
Member

@mcintyre94 mcintyre94 May 4, 2026

Choose a reason for hiding this comment

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

I think we could use Intl.NumberFormat here

return new Intl.NumberFormat('en-US', {
  minimumFractionDigits: padTrailingZeros ? decimals : 0, 
  maximumFractionDigits: decimals, 
  useGrouping: false
}).format(`${raw}E-${decimals}`)

should be equivalent to this I think.

Edit: Confirmed this passes all tests

I also wonder if we should expose a function to get from a fixed point to {raw, decimals} (ie everything before the call to this function) so that apps can add their own Intl.NumberFormat call with custom locale and formatting. Could be added later though.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

That's not a bad idea but we would need a cast because NumberFormat technically only works on number types.

interface NumberFormat {
    format(value: number): string;
    resolvedOptions(): ResolvedNumberFormatOptions;
}

I went down a small rabbit hole on this. I was initially worried that providing a string as argument would internally transform it to a number and therefore lose precision when reaching the boundaries of JavaScript numbers. Turns out since ES2023, the spec actually does say string arguments are parsed as a StringNumericLiteral and stored as an exact "mathematical value", so precision is preserved in fully-compliant environments. That said, I still think an explicit homemade solution might be worth keeping mainly due to inconsistencies between environments. For instance, (according to Claude) Hermes / React Native added string-arg support much later and therefore we may run into some issues when running in older environments. I also think this custom solution should be faster (not that it matters a lot) since it doesn't need to account for all the formatting logic that NumberFormat provides.

This is why I thought of offering lossy toNumber helpers so apps can explicitly rely on NumberFormat when they want locale-aware output and have accepted the precision tradeoff. And as you suggested, they can even use strings now if they are in the correct environments (although they will need a type-cast because TypeScript hasn't caught up with the new API yet).

Regarding the function that outputs { raw, decimals }, am I right to say this would be for binary fixed-point only (since decimal fixed-points are already described as such) and it would wrap the following conversion?

// Convert the base-2 representation to an exact base-10 representation:
// raw / 2 ** F === (raw * 5 ** F) / 10 ** F, which terminates cleanly.
// The transformed raw carries exactly F decimal digits of precision.
const base10Decimals = value.fractionalBits;
const base10Raw = base10Decimals === 0 ? value.raw : value.raw * 5n ** BigInt(base10Decimals);

If so, I'm happy to add a binaryFixedPointToBase10 function (name TBD) that returns { raw, decimals }. I initially wanted to suggest a decimalFixedPointToBinaryFixedPoint/binaryFixedPointToDecimalFixedPoint duo but turns out this is a bit more complicated than that because you will likely need to adjust the totalBits/fractionalBits to keep the range of values intact (or throw arithmetic overflows).

Let me know what you think and I can push a new PR on top of that stack.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yea it's weirdly missing from Typescript still, but I learnt about it from Steve's issue about adding math way back: #29. I've used it a bunch since and find it really nice.

I definitely think Intl.NumberFormat with string scientific notation is the most flexible API for display rather than going through number there, but having toNumber conversions is still worth it for other use cases where you need a number IMO.

Agree the custom solution should be faster, and if Intl.NumberFormat doesn't have the support yet then I'm good to keep it as-is.

On the function for {raw, decimals}, the only other thing the base10 one would give us is the rounding - but NumberFormat has a lot of rounding modes and I think it's a superset of ours. So probably not worth adding anything there. I think just adding binary -> base10 like you said is the way to go there. Then anyone who wants to use Intl.NumberFormat with either decimal or binary fixed points can easily do so, with whatever locale and formatting suit them.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

That's a really good shout, I had forgotten about this part of the original issue. How about on top of the toNumber and toString helpers, I provide the following helpers in a subsequent PR in the stack:

  • formatDecimalFixedPoint(formatter: Intl.NumberFormat, value: DecimalFixedPoint): string
  • formatBinaryFixedPoint(formatter: Intl.NumberFormat, value: BinaryFixedPoint): string
  • binaryFixedPointToBase10(value: BinaryFixedPoint): { raw: bigint, decimals: number } (used internally by the binary fixed-point helpers)

That way, people can mostly rely on the format helpers when they need to display values but the toString helpers stay lossless and environment-safe. Wdyt?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That sounds perfect!

@lorisleiva lorisleiva force-pushed the 04-24-add_fixed-point_string_and_number_conversions branch from 89cd89f to f97f875 Compare May 4, 2026 03:59
@lorisleiva lorisleiva force-pushed the 04-24-add_fixed-point_rescaling branch from d29dae8 to 89b1755 Compare May 4, 2026 03:59
@lorisleiva lorisleiva force-pushed the 04-24-add_fixed-point_string_and_number_conversions branch from f97f875 to 2031a98 Compare May 5, 2026 11:17
@lorisleiva lorisleiva force-pushed the 04-24-add_fixed-point_rescaling branch 2 times, most recently from 09f7d3d to d77d17f Compare May 5, 2026 13:51
@lorisleiva lorisleiva force-pushed the 04-24-add_fixed-point_string_and_number_conversions branch from 2031a98 to ec8d8d1 Compare May 5, 2026 13:51
Copy link
Copy Markdown
Member Author

lorisleiva commented May 5, 2026

Merge activity

  • May 5, 8:27 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • May 5, 8:48 PM UTC: Graphite couldn't merge this pull request because a downstack PR Add fixed-point types #1560 failed to merge.
  • May 5, 9:18 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • May 5, 10:18 PM UTC: Graphite rebased this pull request as part of a merge.
  • May 5, 10:27 PM UTC: @lorisleiva merged this pull request with Graphite.

lorisleiva added a commit that referenced this pull request May 5, 2026
This PR adds three new public helpers to `@solana/fixed-points`: `formatDecimalFixedPoint` and `formatBinaryFixedPoint` accept any `Intl.NumberFormat` instance and route the underlying raw bigint through ES2023 string scientific notation (`"<raw>E-<decimals>"`), which preserves full precision regardless of the value's magnitude. They give consumers locale-aware output, currency formatting, grouping separators, and any rounding mode supported by `Intl.NumberFormat`, while the existing lossless `*ToString` helpers remain the recommended choice when portability across older runtimes (older Hermes/React Native, etc.) is a concern.

The PR also exposes `binaryFixedPointToBase10`, which returns a binary fixed-point's exact `(raw, decimals)` base-10 representation. It is used internally by `formatBinaryFixedPoint` and by `binaryFixedPointToString` (deduplicating an inline conversion), and it lets consumers plug their own formatter on top of binary fixed-points just as they already can with decimal ones. Decimal fixed-points already expose `(raw, decimals)` directly on the value object so no equivalent helper is needed for them.

Continuation of the discussion on #1567.
@lorisleiva lorisleiva force-pushed the 04-24-add_fixed-point_rescaling branch from d77d17f to a3fa2e7 Compare May 5, 2026 20:53
@lorisleiva lorisleiva force-pushed the 04-24-add_fixed-point_string_and_number_conversions branch from ec8d8d1 to 947f588 Compare May 5, 2026 20:53
lorisleiva added a commit that referenced this pull request May 5, 2026
This PR adds three new public helpers to `@solana/fixed-points`: `formatDecimalFixedPoint` and `formatBinaryFixedPoint` accept any `Intl.NumberFormat` instance and route the underlying raw bigint through ES2023 string scientific notation (`"<raw>E-<decimals>"`), which preserves full precision regardless of the value's magnitude. They give consumers locale-aware output, currency formatting, grouping separators, and any rounding mode supported by `Intl.NumberFormat`, while the existing lossless `*ToString` helpers remain the recommended choice when portability across older runtimes (older Hermes/React Native, etc.) is a concern.

The PR also exposes `binaryFixedPointToBase10`, which returns a binary fixed-point's exact `(raw, decimals)` base-10 representation. It is used internally by `formatBinaryFixedPoint` and by `binaryFixedPointToString` (deduplicating an inline conversion), and it lets consumers plug their own formatter on top of binary fixed-points just as they already can with decimal ones. Decimal fixed-points already expose `(raw, decimals)` directly on the value object so no equivalent helper is needed for them.

Continuation of the discussion on #1567.
@lorisleiva lorisleiva force-pushed the 04-24-add_fixed-point_string_and_number_conversions branch from 947f588 to 9d7fc99 Compare May 5, 2026 20:54
@lorisleiva lorisleiva force-pushed the 04-24-add_fixed-point_rescaling branch from a3fa2e7 to 236f83c Compare May 5, 2026 20:54
@lorisleiva lorisleiva changed the base branch from 04-24-add_fixed-point_rescaling to graphite-base/1567 May 5, 2026 22:05
@lorisleiva lorisleiva changed the base branch from graphite-base/1567 to main May 5, 2026 22:16
This PR adds `binaryFixedPointToString`, `decimalFixedPointToString`, `binaryFixedPointToNumber`, and `decimalFixedPointToNumber` to `@solana/fixed-points`. The string variants accept an optional `FixedPointToStringOptions` bag (`decimals`, `padTrailingZeros`, `rounding`) and throw `SOLANA_ERROR__FIXED_POINTS__STRICT_MODE_PRECISION_LOSS` (with `operation: 'toString'`) when capping requires a lossy rescale under the default `'strict'` mode.

The number variants are lossy escape hatches bounded by IEEE 754's ~53-bit mantissa. `binaryFixedPointToNumber` splits the raw value into integer and fractional parts before coercing, preserving exactness whenever the result magnitude fits `Number.MAX_SAFE_INTEGER` even if the raw bigint does not.
@lorisleiva lorisleiva force-pushed the 04-24-add_fixed-point_string_and_number_conversions branch from 9d7fc99 to da94b9b Compare May 5, 2026 22:17
@lorisleiva lorisleiva merged commit a943a2a into main May 5, 2026
14 checks passed
@lorisleiva lorisleiva deleted the 04-24-add_fixed-point_string_and_number_conversions branch May 5, 2026 22:27
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

🔎💬 Inkeep AI search and chat service is syncing content for source 'Solana Kit Docs'

lorisleiva added a commit that referenced this pull request May 5, 2026
This PR adds three new public helpers to `@solana/fixed-points`: `formatDecimalFixedPoint` and `formatBinaryFixedPoint` accept any `Intl.NumberFormat` instance and route the underlying raw bigint through ES2023 string scientific notation (`"<raw>E-<decimals>"`), which preserves full precision regardless of the value's magnitude. They give consumers locale-aware output, currency formatting, grouping separators, and any rounding mode supported by `Intl.NumberFormat`, while the existing lossless `*ToString` helpers remain the recommended choice when portability across older runtimes (older Hermes/React Native, etc.) is a concern.

The PR also exposes `binaryFixedPointToBase10`, which returns a binary fixed-point's exact `(raw, decimals)` base-10 representation. It is used internally by `formatBinaryFixedPoint` and by `binaryFixedPointToString` (deduplicating an inline conversion), and it lets consumers plug their own formatter on top of binary fixed-points just as they already can with decimal ones. Decimal fixed-points already expose `(raw, decimals)` directly on the value object so no equivalent helper is needed for them.

Continuation of the discussion on #1567.
lorisleiva added a commit that referenced this pull request May 5, 2026
This PR adds three new public helpers to `@solana/fixed-points`: `formatDecimalFixedPoint` and `formatBinaryFixedPoint` accept any `Intl.NumberFormat` instance and route the underlying raw bigint through ES2023 string scientific notation (`"<raw>E-<decimals>"`), which preserves full precision regardless of the value's magnitude. They give consumers locale-aware output, currency formatting, grouping separators, and any rounding mode supported by `Intl.NumberFormat`, while the existing lossless `*ToString` helpers remain the recommended choice when portability across older runtimes (older Hermes/React Native, etc.) is a concern.

The PR also exposes `binaryFixedPointToBase10`, which returns a binary fixed-point's exact `(raw, decimals)` base-10 representation. It is used internally by `formatBinaryFixedPoint` and by `binaryFixedPointToString` (deduplicating an inline conversion), and it lets consumers plug their own formatter on top of binary fixed-points just as they already can with decimal ones. Decimal fixed-points already expose `(raw, decimals)` directly on the value object so no equivalent helper is needed for them.

Continuation of the discussion on #1567.
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.

2 participants