Skip to content

fix(escrow): derive split-release payments from on-chain basis points - #79

Merged
chonilius merged 1 commit into
MergeFi:mainfrom
eulami:fix/43-split-release-basis-point-reconciliation
Aug 17, 2026
Merged

fix(escrow): derive split-release payments from on-chain basis points#79
chonilius merged 1 commit into
MergeFi:mainfrom
eulami:fix/43-split-release-basis-point-reconciliation

Conversation

@eulami

@eulami eulami commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Summary

EscrowService.splitRelease computed each recorded Payment.amount by independently rounding (totalAmount * percentage / 100) in JS floating point, while the contract was instructed with Math.round(percentage * 100) basis points. These are two never-reconciled computations of the same split, so the local ledger could drift from escrow.amount and from what was actually sent on-chain.

Changes

  • Single source of truth — percentages are apportioned into integer basis points that sum to exactly 10,000 (100.00%), and those same basis points are both sent on-chain and used to derive each Payment.amount.
  • Exact total — shares are computed in whole stroops (totalStroops * bps / 10000) with a largest-remainder allocation, so sum(payments.amount) === escrow.amount exactly for every valid split (including uneven thirds).
  • Reconciliation — the split_release result (including returnValue) is recorded in escrow metadata, and a divergence between the contract's returned total and the recorded total is surfaced as a warning rather than silently discarded. Per-recipient reconciliation remains deferred until the deployed contract returns a per-recipient breakdown.

Tests

  • New split-math.util.spec.ts covers basis-point apportionment and exact stroop splitting.
  • escrow.service.spec.ts asserts sum(payments.amount) === escrow.amount via BigInt/stroops comparison and that the basis points sent on-chain sum to 10,000.

Closes #43

splitRelease computed each Payment.amount by independently rounding
(totalAmount * percentage / 100) in JS floats while the contract received
Math.round(percentage * 100) basis points — two never-reconciled
computations of the same split that could drift from escrow.amount and
from what was actually instructed on-chain (MergeFi#43).

- Apportion percentages into basis points that sum to exactly 10,000.
- Derive each Payment.amount in whole stroops from those same basis
  points, allocating the rounding remainder via largest-remainder so
  sum(payments.amount) === escrow.amount exactly.
- Record the split_release result (incl. returnValue) in escrow metadata
  and warn when the contract's returned total diverges from the recorded
  total, deferring per-recipient reconciliation to the reconciliation job.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@vercel

vercel Bot commented Aug 17, 2026

Copy link
Copy Markdown

@eulami is attempting to deploy a commit to the chonilius' projects Team on Vercel.

A member of the Team first needs to authorize it.

@chonilius

Copy link
Copy Markdown
Contributor

nice job

@chonilius
chonilius merged commit ccba5ac into MergeFi:main Aug 17, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants