Skip to content

core: implement atomic loan funding from liquidity pool #10

Description

@EmeditWeb

Problem

When a loan is approved via approve_loan(), the creditline
contract does not actually pull funds from the liquidity
pool contract. The approval is purely a status change.
There is no atomic linkage between the pool and the loan.
Funds are never actually moved on-chain when a loan is
approved.

Context

In a real BNPL protocol the liquidity pool must lock
capital against approved loans. Without this the pool
balance and loan balances are completely disconnected.
A sponsor could withdraw all funds while loans are
active. This is a critical protocol correctness issue.

Before Starting

Read these context files:

  • context/architecture-context.md
  • context/code-standards.md
  • contracts/creditline-contract/src/lib.rs
  • contracts/liquidity-pool-contract/src/lib.rs

What To Build

  1. Add cross-contract call in approve_loan():
    After transitioning status to Active,
    call liquidity_pool.lock_funds(loan_id, amount)
    This marks that amount as locked in the pool.

  2. Add lock_funds(env, loan_id, amount) to liquidity pool:

    • require_auth() for creditline contract address
    • Verify available_liquidity >= amount
    • Deduct from available_liquidity
    • Add to locked_liquidity
    • Store mapping: loan_id -> locked_amount
  3. Add release_funds(env, loan_id) to liquidity pool:
    Called when loan is fully repaid.
    Moves locked amount back to available plus interest.

  4. Add liquidate_funds(env, loan_id) to liquidity pool:
    Called when loan defaults.
    Distributes locked funds according to loss policy.

  5. Update creditline repay_installment():
    On final installment, call pool.release_funds()

  6. All cross-contract calls must be atomic.
    If pool.lock_funds() fails, approve_loan() must revert.

Files To Touch

  • contracts/creditline-contract/src/lib.rs
  • contracts/liquidity-pool-contract/src/lib.rs
  • contracts/liquidity-pool-contract/src/types.rs
  • contracts/creditline-contract/src/tests.rs
  • contracts/liquidity-pool-contract/src/tests.rs

Acceptance Criteria

  • approve_loan() atomically locks funds in pool
  • available_liquidity decreases on approval
  • locked_liquidity increases on approval
  • Final repayment releases funds back to pool
  • Default triggers liquidation
  • All operations revert if any step fails
  • require_auth() on all mutating functions
  • extend_ttl() after all storage writes
  • All existing 96 tests still pass
  • Minimum 8 new tests covering full lifecycle

Mandatory Checks Before PR

  • cargo build passes with zero errors
  • All tests pass
  • No .unwrap() in user-facing paths
  • PR references this issue

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions