fix: enforce exact invoice amount precision and overflow bounds (#2432) - #2551
Merged
Baskarayelu merged 1 commit intoAug 30, 2026
Conversation
…kLendX#2432) Centralise invoice amount validation - sign, overflow ceiling, configured minimum, and currency scale - in a documented, tested module and route the invoice lifecycle entrypoints (store_invoice, Invoice::new) through it. Rejected amounts fail before any state change, and the i128::MAX / 10_000 ceiling guarantees downstream bps fee math cannot overflow. Public behavior and error codes are unchanged. Also removes the duplicate ed25519-dalek dev-dependency that broke `cargo build` on main. Closes QuickLendX#2432
|
@vrse-vrde Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2432
Summary
Implements and verifies exact amount precision and overflow guarantees for the invoice lifecycle (creation → amendment → cancellation → completion) per #2432. All amount rules are consolidated into one documented, tested enforcement point that the invoice lifecycle entrypoints route through, so zero/negative, below-minimum, above-ceiling, and over-precision (scale) inputs are rejected before any state change.
What changed
quicklendx-contracts/src/invoice_amount.rs(new) — single enforcement point for the exact integer rules:amount <= 0→InvalidAmountamount > MAX_INVOICE_AMOUNT(=i128::MAX / 10_000) →InvalidAmount, with the ceiling chosen so every downstream bps computation (amount * bps / 10_000) is overflow-free forbps <= 10_000amount < min_invoice_amount→InvalidAmount(inclusive boundary), mirroringprotocol_limits::validate_invoicedecimals() > 18→InvalidCurrency, mirroringpayments::require_matching_currency_precisionchecked_fee_amountpins thefloor(amount * bps / 10_000)formula with checked arithmeticquicklendx-contracts/src/test_invoice_amount_precision.rs(new) — 17 focused tests mirroring the repo's existing test style (#![cfg(test)]module wired from the crate root), covering success path, every failure path, and all acceptance-criteria boundaries, validated against an independent oraclequicklendx-contracts/src/lib.rs— wireserrors+invoice_amount(+ the test module) into the crate root so the rules are compiled and tested in CIquicklendx-contracts/src/contract.rs/invoice.rs—store_invoiceandInvoice::newnow route throughvalidate_invoice_amount_ceiling(semantically identical predicate; no behavior change)quicklendx-contracts/Cargo.toml— removed the duplicateed25519-dalekdev-dependency key that breakscargo buildon mainKey design decisions
i128smallest-units; "fractional" values are exact integers (e.g.1.5tokens @ 6dp =1_500_000). Bps math floors toward zero exactly like the existing fee pipeline.MAX_INVOICE_AMOUNT * 10_000fitsi128;(MAX + 1) * 10_000does not. A test locks this so a silent constant change is caught.InvalidAmount/InvalidCurrency/ArithmeticOverflow/InvalidFeeBasisPoints), same boundaries, no ABI or response-shape changes; no migration or rollback required.Acceptance-criteria checklist
invoice_amount.rs(sign, ceiling, minimum, scale); entrypoints route through it before writes.test_validation_is_pure_and_repeatable; entrypoint ordering documented.test_invoice_amount_precision.rs+ crate-root wiring (lib.rs); boundary/random sweeps against an independent oracle (zero, minimum, maximum, near-overflow, fractional, conversion-boundary values).Validation notes (honest)
cargonot installed). Exact commands are below; I have not claimed a green run or a coverage number I did not observe.cargo buildfails on main witherror: duplicate keyinquicklendx-contracts/Cargo.toml(fixed here), and (2) after that,cargo testfails to compile ungated legacy integration tests inquicklendx-contracts/tests/against the current stub crate root (lib.rswas replaced by a minimal stub in feat(security): KYC participant amount precision and overflow bounds (#2472) #2538). The full legacy suite is not wired into the build on main; restoring it is out of scope for this issue.cargo test --lib(they do not depend on the legacy tree) and are covered bycargo llvm-cov --lib.Commands to verify
Follow-ups (out of scope here)
lib.rsand repairing the ungated integration tests so the fullcargo testsuite is green again.payments.rs,transfer_funds,allocate_repayment) through the same module.Security note
No floating-point or unchecked arithmetic is introduced; all math is
checked_*and fails closed. The amount ceiling guarantees fee/settlement bps math cannot overflowi128for any accepted invoice. Validation is side-effect free and runs before any storage write, so malformed amounts cannot leave partial or unauthorized state. This change adds no new privileged entrypoints, secrets, or trust assumptions; it trusts the currencydecimals()report exactly as the existing funding-path guard does.