Problem
loans.service.createLoan() reads available pool liquidity during credit
assessment, then builds the funding XDR for the user to sign. Nothing
reserves that liquidity between the check and on-chain settlement, so two
concurrent loan requests can each pass the availability check against the
same funds. The second fund_loan then reverts on-chain with
InsufficientLiquidity after the user has already signed — wasting fees
and leaving a dangling provisional loan. There is no distributed lock or
reservation around the assess → build → submit sequence.
Before Starting
Read ALL of these before writing any code:
- context/architecture-context.md
- context/code-standards.md
- context/progress-tracker.md
What To Build
A liquidity reservation layer that serializes commitment of pool funds:
- A Redis-backed distributed lock (or reservation ledger) keyed to the pool
so concurrent loan creations cannot over-commit available liquidity.
- Reserve the assessed amount atomically before returning the funding XDR;
release the reservation on confirmed settlement, on failure, or on TTL
expiry so a signed-but-never-submitted loan cannot lock funds forever.
- Reconcile reservations against on-chain
locked_liquidity so reservations
never drift from reality.
Files To Touch
- src/modules/loans/loans.service.ts
- src/modules/liquidity/* (reservation ledger)
- src/common/* (Redis lock utility)
- corresponding *.spec.ts
Acceptance Criteria
Mandatory Checks Before Opening PR
Problem
loans.service.createLoan()reads available pool liquidity during creditassessment, then builds the funding XDR for the user to sign. Nothing
reserves that liquidity between the check and on-chain settlement, so two
concurrent loan requests can each pass the availability check against the
same funds. The second
fund_loanthen reverts on-chain withInsufficientLiquidityafter the user has already signed — wasting feesand leaving a dangling provisional loan. There is no distributed lock or
reservation around the assess → build → submit sequence.
Before Starting
Read ALL of these before writing any code:
What To Build
A liquidity reservation layer that serializes commitment of pool funds:
so concurrent loan creations cannot over-commit available liquidity.
release the reservation on confirmed settlement, on failure, or on TTL
expiry so a signed-but-never-submitted loan cannot lock funds forever.
locked_liquidityso reservationsnever drift from reality.
Files To Touch
Acceptance Criteria
Mandatory Checks Before Opening PR
anytypes introduced