Skip to content

hard: creditline user-loan index lives in instance storage — unbounded growth bricks accounts and risks ledger-limit DoS #88

Description

@EmeditWeb

Problem

The creditline contract tracks user_active_debt, loan counters, and per-user loan indexes in instance storage (see contracts/creditline-contract/src/storage.rs). Instance entries have a hard ledger footprint ceiling and a shared budget per contract instance. Every create_loan() appends to the borrower's paginated loan index and mutates debt counters; repay_loan() and repay_installment() mutate the same entries plus the loan body on every payment.

As a borrower's loan count grows, the instance entry holding their index grows linearly: read cost grows, and eventually the entry approaches Soroban's max instance size — at which point create_loan() (which writes the index) and repay_installment() (which writes loan + counters) start failing outright. A borrower who cannot repay is frozen mid-loan; a malicious actor can deliberately fragment many loans to hit the ceiling, and because mark_defaulted() also writes these entries, default handling can be made to fail — leaving defaulted principal locked in the pool forever with absorb_loss() unreachable.

TTL handling compounds it: verify whether every instance/persistent write in the repay/create paths extends TTL appropriately; an expired index entry mid-flow yields silent index loss (loan exists, invisible in listings, unreachable by the indexer).

Ground Rules

  1. Read context/architecture-context.md, context/code-standards.md, context/progress-tracker.md in full
  2. Read contracts/creditline-contract/src/storage.rs in full and map every key to its storage class (instance vs persistent)
  3. Compare with liquidity-pool-contract/src/storage.rs:123–139 which demonstrates the correct persistent-key + extend_ttl pattern

What To Build

  1. Move per-user loan indexes and debt counters from instance storage to persistent per-borrower keys with extend_ttl after every write, mirroring the LP-shares pattern.
  2. Cap or chunk the index (e.g. fixed-size pages keyed (borrower, page)) so no single entry can grow unbounded; document the pagination contract for consumers.
  3. Audit every write site in lib.rs for a paired extend_ttl.
  4. Add a storage-layout regression test asserting entry classes and that a 200-loan borrower can still create and repay loans within footprint budgets.

Files To Touch

  • contracts/creditline-contract/src/storage.rs
  • contracts/creditline-contract/src/lib.rs
  • contracts/creditline-contract/src/tests.rs
  • context/progress-tracker.md

Acceptance Criteria

  • No unbounded instance-storage entry remains on the hot loan paths
  • Every persistent write is followed by extend_ttl
  • High-loan-count stress test passes
  • Suite green

Mandatory Checks Before Opening PR

Standard Grantfox checklist applies.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions