Skip to content

feat(investments): add transactional pool reservations - #233

Merged
Obiajulu-gif merged 1 commit into
Chainmove:mainfrom
OkeyAmy:implement-concurrent-investment-workflow-fixes
Aug 30, 2026
Merged

feat(investments): add transactional pool reservations#233
Obiajulu-gif merged 1 commit into
Chainmove:mainfrom
OkeyAmy:implement-concurrent-investment-workflow-fixes

Conversation

@OkeyAmy

@OkeyAmy OkeyAmy commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Prevent race conditions that allow oversubscription, double-spending of wallet balance, or partially applied funding totals by introducing an explicit transactional investment command.
  • Provide explicit reservation lifecycle states and idempotency semantics so retries and expiry are handled deterministically.
  • Ensure funding totals and ledger writes are updated atomically and safely under concurrent requests.

Description

  • Add a durable reservation model InvestmentReservation with states PENDING, RESERVED, SETTLED, EXPIRED, CANCELLED, and FAILED and a user-scoped unique idempotencyKey index (models/InvestmentReservation.ts).
  • Rework investInPool in lib/services/investments.service.ts to run the full flow inside a MongoDB transaction: create reservation, conditionally debit and hold wallet funds, require consent, create PoolInvestment (with reservationId), update pool totals atomically, create a Transaction ledger entry, and mark the reservation SETTLED on success.
  • Add idempotency handling so requests with the same Idempotency-Key return the original settled result or prevent duplicate processing; add duplicate-key and transient-transaction retry handling in the service.
  • Add an expiry routine expireInvestmentReservations() and a runnable worker script scripts/expire-investment-reservations.ts that selects only RESERVED reservations and releases held funds (so settled reservations cannot be released).
  • Surface Idempotency-Key from the API route by reading the header in app/api/pools/[poolId]/invest/route.ts and map KYC/permission failures to 403 in the route error mapper.
  • Persist reservationId on PoolInvestment and add an index to prevent duplicate association; update InvestmentPool/funding writes to increment investorCount only when the investor had no prior confirmed investment.
  • Add contributor documentation docs/investment-reservations.md describing the state transitions and expiry-worker invocation and a small unit test for the reservation state machine and deterministic ownership calculation (__tests__/lib/services/investments.service.test.ts).

Testing

  • Ran lint with npm run lint and observed 0 errors (3 unrelated warnings remain); success.
  • Ran npm run typecheck and npm run typecheck:gate; both succeeded.
  • Executed the new unit tests with npx vitest run __tests__/lib/services/investments.service.test.ts and they passed.
  • Built the application with the CI-like environment using npm run build (with CI env vars); the build completed successfully.
  • Note: the repository’s broader API OpenAPI equality test observed a pre-existing OpenAPI drift in __tests__/lib/api/openapi.test.ts (one failing test) that is unrelated to the implemented transactional reservation logic; full integration/load tests that exercise MongoDB transactions require a MongoDB replica set (not available in this environment) and should be run in CI or an integration environment to validate concurrent settlement, rollback, and expiry behaviour under load.

Close #83

@Obiajulu-gif
Obiajulu-gif merged commit de53c9f into Chainmove:main Aug 30, 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][INVESTMENTS] Build concurrency-safe pool reservation and settlement workflow

2 participants