Skip to content

apportionBasisPoints doesn't validate that its own input sums to ~100 before force-normalizing the output — and has no test for that scenario #169

Description

@chonilius

apportionBasisPoints(percentages: number[]) in src/escrow/split-math.util.ts rounds each percentage to basis points, then always redistributes TOTAL_BASIS_POINTS - sum(bps) (the "delta") across recipients until the output sums to exactly 10,000 — regardless of what the input summed to. Unlike splitStroops in the same file, which explicitly validates its own precondition (if (bpsTotal !== TOTAL_BASIS_POINTS) throw new BadRequestException(...)), apportionBasisPoints has no equivalent guard on its own input.

In production this is masked by EscrowService.assertValidSplits() always running first and rejecting a bad sum before apportionBasisPoints is ever called — but as a standalone exported utility with a doc comment implying general correctness ("the integer vector handed to the contract always represents exactly 100%"), it will silently "fix" an arbitrarily wrong input into a valid-looking 10,000-bps output for any future caller that doesn't happen to pre-validate, rather than failing loudly. It's also an O(delta) loop (for (let i = 0; i < delta; i++)) rather than O(n) — a badly wrong input (e.g. percentages summing to only 20) produces a delta of ~8000, iterated one basis point at a time. src/escrow/split-math.util.spec.ts has no test for a not-summing-to-100 input either, so this is untested as well as unguarded. Consider validating Math.abs(sum(percentages) - 100) <= tolerance at the top of the function, matching splitStroops's own defensive pattern in the same file.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdocumentationImprovements or additions to documentationgood first issueGood for newcomersperformancePerformance/optimization issuetestingTesting/QA infrastructure

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions