Skip to content

feat(payouts): deterministic payout engine, service, tests, docs - #224

Merged
Obiajulu-gif merged 5 commits into
Chainmove:mainfrom
muokwejosh-cloud:feat/payout-engine
Aug 27, 2026
Merged

feat(payouts): deterministic payout engine, service, tests, docs#224
Obiajulu-gif merged 5 commits into
Chainmove:mainfrom
muokwejosh-cloud:feat/payout-engine

Conversation

@muokwejosh-cloud

Copy link
Copy Markdown
Contributor

Summary

Implement a deterministic, auditable payout engine and lifecycle for investor distributions.

  • Snapshot-driven allocation engine using integer minor-units and Largest Remainder (Hamilton) rounding policy.
  • Separates calculation, approval (maker-checker), and execution (idempotent) phases.
  • Supports per-recipient failure, retries, holds, and reversals.
  • Exposes explicit feeAmount, reserveAmount, and roundingRemainder for auditability.

Key files:

  • types.ts
  • engine.ts
  • service.ts
  • engine.test.ts
  • docs/payouts.md
  • docs/PR_TEMPLATES/payouts_PR.md

Related Issue

Closes #88

Affected Areas

  • Frontend
  • Backend
  • Authentication
  • Payments
  • Stellar (design notes / future integration surface)
  • Documentation
  • Tests
  • UI/UX

Checklist

  • Code follows project conventions (scoped, typed, minimal changes)
  • npm run lint passes
  • npm run build passes
  • Tests updated where needed (engine.test.ts)
  • No secrets committed
  • No production credentials used
  • Documentation updated (docs/payouts.md)

Additional Notes

Behavior highlights and maintainer guidance:

  • Deterministic allocation:

    • Fees and reserves are computed first (floored).
    • Remaining distributable amount allocated proportionally by snapshot units.
    • Leftover minor units allocated by Largest Remainder with lexicographic tie-break (deterministic).
    • roundingRemainder returned explicitly when present.
  • Lifecycle:

    • draftcalculatedapprovedprocessingpaid / partially_failedreversed / cancelled.
    • Maker-checker enforced: calculator cannot approve their own calculation.
    • Execution idempotent for already-paid allocations; supports per-recipient retry and reversals (paid → held).
    • reverse marks paid allocations as held and sets distribution to reversed.
  • Production considerations:

    • Current execute allows running from calculated to support test/dev flows; enforce approved-only execution in production by changing the guard in service.ts.
    • This PR implements in-memory service & engine; follow-up should persist distributions to DB, add tamper-evident audit writes, and integrate with the ledger/durable job queue.
    • Business policy must decide how to handle roundingRemainder (platform reserve vs treasury); the engine surfaces this explicitly for accounting.
  • Local validation commands:

# Type-check
npm run -s typecheck

# Lint
npm run -s lint

# Run full tests
npm test

# Run payout tests only
npx vitest run __tests__/lib/payouts/engine.test.ts

@Obiajulu-gif
Obiajulu-gif merged commit 96716fd into Chainmove:main Aug 27, 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

Development

Successfully merging this pull request may close these issues.

[HARD][PAYOUTS] Build an investor distribution engine with snapshots, rounding, holds, and reversals

2 participants