Skip to content

Perf/lending pool optimizations#646

Merged
Smartdevs17 merged 5 commits into
Smartdevs17:mainfrom
Joycejay17:perf/lending-pool-optimizations
Jun 28, 2026
Merged

Perf/lending pool optimizations#646
Smartdevs17 merged 5 commits into
Smartdevs17:mainfrom
Joycejay17:perf/lending-pool-optimizations

Conversation

@Joycejay17

Copy link
Copy Markdown
Contributor

perf(lending): pool performance optimization suite (#631 #632 #633 #634)

Summary

Implements four performance optimizations for the lending pool contract
(stellar-lend/contracts/lending), each as a focused, self-contained module
with pure, unit-tested core logic and contract entry points wired into
lib.rs.

Closes #631
Closes #632
Closes #633
Closes #634

Note on paths: the issues reference contracts/lending-pool/src/.... This
repository's lending pool actually lives at
stellar-lend/contracts/lending/src/, so the work landed there using the
module names from each issue's technical scope (interest.rs,
liquidation.rs, storage.rs, lazy.rs).


What's included

#631 — Incremental interest calculation with caching — interest.rs

  • Cached cumulative interest index advanced incrementally:
    index_n = index_{n-1} + index_{n-1} * rate * dt / (BPS * SECONDS_PER_YEAR).
  • Cache record holds last_update_block, last_update_time,
    cumulative_index, last_cached_rate.
  • Batching: multiple operations in the same ledger observe dt == 0 and
    skip the write — interest is charged once per block.
  • Invalidation: invalidate closes the open segment at the old rate, then
    re-anchors the cached rate (call on rate-model / parameter / oracle change).
  • Read optimization: current_index computes the index for view calls
    without writing storage.
  • Reorg safety: index is monotonic; interest_for flags a position whose
    entry index is newer than a rewound global index (StaleSnapshot).
  • Entry points: interest_index, accrue_interest, invalidate_interest_cache.

#632 — Gas-optimized liquidation — liquidation.rs

  • plan_liquidation validates cheapest-first and returns before any state
    mutation: amount → health factor → close-factor clamp → oracle freshness →
    gas-vs-profit.
  • Batched read: a single PositionSnapshot replaces per-check reads.
  • abort_if_unprofitable rejects when the seize bonus can't cover estimated gas.
  • Pure pricing helpers (health_factor_bps, max_repay_value, seize_value,
    is_oracle_fresh) for reuse by an off-chain benchmark harness.
  • Entry point: plan_liquidation.

#633 — Storage slot packing — storage.rs

  • Packs config into two words (was 5+ slots): a u128 rate word
    (LTV ∥ liq-threshold ∥ reserve-factor ∥ close-factor ∥ liq-incentive, five
    16-bit bps fields) and a u64 status word (40-bit timestamp ∥ 8 flag bits).
  • Overflow guards (BpsFieldOverflow, TimestampOverflow) before any field can
    corrupt a neighbour. Unpack is shift+mask — no extra read gas.
  • Idempotent migrate_from_legacy repacks a pool's current loose values.
  • Entry points: get_packed_config, migrate_packed_config.

#634 — Lazy state initialization — lazy.rs

  • Defers storage allocation for non-essential fields (reserves, fees,
    liquidation counter, total reserves, borrow-index snapshot) until first use.
  • Check-exists reads return default_for with no allocation;
    ensure_initialized is idempotent (safe under concurrent first-use);
    add front-loads cost to the first real accrual.
  • migrate_initialize_all eagerly materializes fields for pre-existing pools.
  • Entry points: get_lazy_field, migrate_lazy_fields.

Benchmarks

  • stellar-lend/contracts/lending/docs/PERF_OPTIMIZATION_BENCHMARKS.md
    gas-diff and storage-rent reports for all four optimizations, including the
    documented edge cases (no-op update, reorg consistency, failed-liquidation
    early exit, packed-field overflow, concurrent first-use).

Testing

Each module ships a #[cfg(test)] mod unit covering the core logic and edge
cases. The pure cost-driving logic (bit-packing, index math, liquidation
pricing/ordering) was additionally verified in isolation — 20/20 standalone
tests pass
.

cd stellar-lend
cargo test -p stellarlend-lending interest::unit
cargo test -p stellarlend-lending liquidation::unit
cargo test -p stellarlend-lending storage::unit
cargo test -p stellarlend-lending lazy::unit

⚠️ Pre-existing breakage (out of scope): the stellarlend-lending crate
currently fails cargo check due to 14 errors in unrelated modules that
predate this branch (e.g. token_adapter* super::TokenAdapterTrait
resolution, an over-length event name in events, a token import in
data_store). These were intentionally not touched. The four new modules
add zero new compile errors (verified: error count unchanged at 14, none
referencing the new files); the full in-crate test suite will run end-to-end
once the unrelated errors are fixed.


Acceptance criteria

Issue Criterion Status
#631 Cache: lastUpdateBlock, cumulativeInterestIndex, lastCachedRate InterestCache
#631 Incremental delta-only update advance_index
#631 Batch update (charge once per block) ✅ same-block no-op
#631 Invalidation on rate/param/oracle change invalidate
#631 Read-function optimization current_index (no write)
#631 Gas benchmark + reorg/no-op edge cases ✅ docs + tests
#632 Early validation (HF, profit, oracle) plan_liquidation
#632 Batched storage read PositionSnapshot
#632 Cheapest validation first ✅ ordered checks
#632 Gas estimate before execution / abort abort_if_unprofitable
#632 Gas benchmark + scale edge cases ✅ docs + tests
#633 Pack LTV+threshold+reserve into one slot u128 rate word
#633 Pack timestamp + status flags u64 status word
#633 Bit flags for booleans FLAG_*
#633 Migration to repack migrate_from_legacy
#633 Rent comparison + no read overhead ✅ docs
#633 Overflow / upgrade-compat edge cases ✅ guards + tests
#634 Identify deferrable fields LazyField
#634 Check-exists default pattern get
#634 On-first-use initialization ensure_initialized
#634 Gas front-loading add
#634 Migration path migrate_initialize_all
#634 Rent savings + concurrent/failure edge cases ✅ docs + tests

…artdevs17#631)

Add interest.rs implementing a cached cumulative interest index advanced
incrementally instead of recomputing the full accrual each interaction.

- Cache: last_update_block, last_update_time, cumulative_index, last_cached_rate
- Incremental delta accrual via advance_index (pure, unit-tested)
- Batch: same-block operations skip the write (charged once per ledger)
- Invalidation hook on rate/parameter/oracle change
- Read-optimised current_index for view calls (no storage write)
- Reorg safety: monotonic index, StaleSnapshot guard on rewound positions
…7#632)

Add liquidation.rs that front-loads validation cheapest-first so doomed
liquidations abort before any storage write or token transfer.

- Batched PositionSnapshot read instead of per-check reads
- Checks ordered ascending by gas cost: amount, health factor,
  close-factor clamp, oracle freshness, gas-vs-profit guard
- abort_if_unprofitable rejects when bonus < estimated gas cost
- Pure pricing/validation helpers, unit-tested
Add storage.rs packing pool configuration into two words to cut storage
rent (~5+ slots -> 2) with no read-gas overhead.

- Rate word (u128): LTV, liq threshold, reserve factor, close factor,
  liq incentive as five 16-bit bps fields
- Status word (u64): 40-bit timestamp + 8 status-flag bits
- Overflow guards: BpsFieldOverflow / TimestampOverflow before any corruption
- Idempotent migrate_from_legacy from existing loose values
- Pure pack/unpack, heavily unit-tested for field independence
)

Add lazy.rs deferring storage allocation for non-essential pool fields
until first use, reducing storage rent over a pool's lifetime.

- Deferrable fields: reserves, fees, liquidation counter, borrow index
- Check-exists reads return default_for without allocating storage
- ensure_initialized is idempotent (safe under concurrent first-use)
- add() front-loads cost to first real accrual
- migrate_initialize_all eagerly materialises fields for existing pools
…martdevs17#631 Smartdevs17#632 Smartdevs17#633 Smartdevs17#634)

- Register interest/liquidation/storage/lazy modules in lib.rs
- Expose entry points: interest_index, accrue_interest,
  invalidate_interest_cache, plan_liquidation, get/migrate packed config,
  get/migrate lazy fields
- Add PERF_OPTIMIZATION_BENCHMARKS.md with gas-diff and storage-rent reports
@vercel

vercel Bot commented Jun 28, 2026

Copy link
Copy Markdown

@Joycejay17 is attempting to deploy a commit to the smartdevs17's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Jun 28, 2026

Copy link
Copy Markdown

@Joycejay17 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Smartdevs17
Smartdevs17 merged commit 52b2b45 into Smartdevs17:main Jun 28, 2026
4 of 13 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

2 participants