Skip to content

fix(price): widen gRPC rate fields to double (#283) - #523

Closed
nul-quill wants to merge 1 commit into
lnflash:mainfrom
nul-quill:price-proto-double-283
Closed

nul-quill wants to merge 1 commit into
lnflash:mainfrom
nul-quill:price-proto-double-283

Conversation

@nul-quill

Copy link
Copy Markdown

protobuf float is 32-bit IEEE 754 (~7 significant digits). JMD/NGN rates (157.xx, 392.xx) combined with 8-decimal sat precision exceed that, so every conversion through the gRPC price service was silently rounded inside the wire layer.

  • PriceResponse.price and Tick.price: float -> double
  • stubs are loaded at runtime from the .proto files (src/services/price/grpc.ts), so there is no separate generated-stub step; reading side only widens precision for already-deployed consumers
  • new test/flash/unit/services/price/price-proto-double.spec.ts asserts both fields are double, encodes/decodes >7-significant-digit rates through the loaded types and compares bit-for-bit, plus a float32 contrast case

Consumers audited: src/services/price/index.ts (getPrice / listPrices) is the only importer of these descriptors; callers in src/app/prices and src/graphql/public/root/query/btc-price-list.ts consume plain JS numbers.

Tests: jest test/flash/unit/services/price test/flash/unit/app test/flash/unit/graphql -> 118 suites / 1431 tests pass; tsc --noEmit shows only the two pre-existing Express/Application errors.

`float` in protobuf is 32-bit IEEE 754: about 7 significant digits. A JMD or
NGN rate (157.xx, 392.xx) carried through the 8-decimal sat math in
`getRealTimePrice` exceeds that, so the value was silently rounded inside the
wire layer - invisible to every caller, since each one receives an already
truncated JS number.

- price.proto: PriceResponse.price float -> double
- price_history.proto: Tick.price float -> double
- the stubs are loaded at runtime from these files (src/services/price/grpc.ts),
  so no generated code needs a separate regen step
- wire-compatible for any already-deployed consumer: both float and double use
  the protobuf varint/fixed wire kinds protobufjs already decodes into a JS
  number, and reading side only widens precision
- add test/flash/unit/services/price/price-proto-double.spec.ts: asserts both
  fields are declared `double`, encodes/decodes rates with more than 7
  significant digits through the loaded types and compares bit-for-bit, and
  shows the same rate losing precision through a 32-bit float view
@nul-quill

Copy link
Copy Markdown
Author

Handle: nul-quill. Payout wallets: Solana USDC BdznDjc4xwt5Y6WJT5UnrFQzDptka8YnC9oqmmkKpwkd, TRC20 TNEHCVwR2aPMrj5AKfWCQ2rFL3bEDQmsg7. Shipped in PR #523: PriceResponse.price and Tick.price widened from float to double, so rates with more than 7 significant digits survive the gRPC round trip instead of being rounded inside the wire layer. Stubs load at runtime from the .proto files in src/services/price/grpc.ts, so no regen step is needed; the only consumers are src/services/price/index.ts and the price queries in src/app/prices. New spec test/flash/unit/services/price/price-proto-double.spec.ts covers the encode/decode bit-equality cases plus a float32 contrast. 118 suites / 1431 tests pass.

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