Repository navigation
fix(multisig): parse decimal amounts exactly, not via f64 - #179
Conversation
multisig's parse_amount was the only amount parser in the CLI still going through f64: '2.01' lost a planck, 13-decimal inputs silently became 0, and '1e3' was read as 1000 QUAN. Route decimal inputs through send::parse_amount_with_decimals like every other command; whole-number and raw base-unit paths are unchanged. Regression tests cover the discriminating cases.
n13
left a comment
There was a problem hiding this comment.
Reviewer model: GPT-6.1 Sol
APPROVE — no blocking findings at c0d7cd8f6ed50ed2d01e601b92e7c6b345636071 (base 413a6e23f7fc9ebbe8145d9cd887cd52a70cc933).
The change reuses the shared checked integer parser for decimal multisig amounts, fixes the demonstrated precision loss, and rejects unsupported fractional precision. Standard and high-security transfer proposals both use this parser; whole-number and raw-base-unit handling remain unchanged.
Non-blocking test suggestion: at src/cli/multisig.rs:3577-3579, add 1.0e3 to exercise scientific notation through the changed decimal branch. 1e3 has no decimal point and was already rejected by the unchanged integer branch, so the current assertion does not demonstrate that regression.
Validation:
SKIP_CIRCUIT_BUILD=1 cargo test --locked --lib cli::multisig— 20 passed, including all three new regression tests.SKIP_CIRCUIT_BUILD=1 cargo test --locked --lib cli::send— 10 passed, including malformed inputs and u128 boundaries.cargo +nightly-2026-08-31 fmt --all -- --check— passed.git diff --check 413a6e23f7fc9ebbe8145d9cd887cd52a70cc933...HEAD— passed.
Validation limits: circuit generation was deliberately skipped for these focused tests. GitHub formatting and dependency-cooldown checks passed; build/test, analysis, security audit, and examples jobs were still running when reviewed.
Bug
parse_amountinsrc/cli/multisig.rsis the one amount parser in the CLI that goes throughf64: it parses the input as a float, multiplies by 10^12 as a float, and truncates tou128. Every other entry point (send,multisend, NEAR) uses the exact string parserparse_amount_with_decimalsinsrc/cli/send.rs. The float path is wrong on ordinary inputs:"2.01"→2_009_999_999_999plancks instead of2_010_000_000_000(−1 planck). Sampling two-decimal amounts, roughly 6% come out short by a few plancks (e.g."66240.40"is −8)."0.0000000000001"(13 decimal places) →Ok(0): an amount the chain cannot represent is silently turned into a zero transfer instead of being refused."1e3"→ read as 1000 QUAN. Scientific notation is not a plain decimal string, and nothing else in the CLI accepts it.This parser feeds multisig proposal amounts (
src/cli/multisig.rs, the propose flow), so a proposal can be created for a slightly different amount than the proposer typed — and the other approvers see the on-chain amount, not the typed one.Fix
Route decimal inputs through the existing exact parser:
parse_amount_with_decimals(amount, 12). That parser validates digit-only input, rejects more fractional digits than the chain supports, and uses checked integer math. The no-decimal-point paths (whole QUAN, and the documented raw base-units format for values ≥ 10^10) are unchanged.Three regression tests: exactness on the discriminating amounts (
2.01,66240.40, plus guards), refusal of the inputs float would silently mangle (13 decimal places,1e3, negatives, double dots), and the unchanged whole-number paths.Verification
SKIP_CIRCUIT_BUILD=1 cargo test --lib parse_amount— 2 of 3 new tests fail on the unpatched code with the exact wrong values above; 3/3 pass with the fix. (SKIP_CIRCUIT_BUILDis build.rs's documented flag for jobs that don't need the generated circuit binaries.)cargo test --lib cli::multisig: 20/20. Fullcargo test --lib: 424 passed; the only 2 failures (batch-verifier loading, one keystore migration test) fail identically on the unpatched tree in this environment and are unrelated to this change.@Quantus-Network — flagging for the team.
Built by @Kshot9000 (https://x.com/kshot9000) · QTC donations: qznY8nwuvWcCCVys4da1oQdysyh8YUZYRjRqgk3S8Wos8kbau