Add time-based interest accrual and debt indexes - #235
Merged
Cedarich merged 1 commit intoJul 23, 2026
Conversation
Introduces index-based accounting (Aave/Compound-style) so borrow and supply balances grow over time instead of remaining static. A new InterestState (supply_index/borrow_index/last_accrual_timestamp) is tracked per asset, with per-position index snapshots realized into Position.deposited/borrowed on every touch. The rate model is a simple, deterministic linear function of utilization (derived from the existing TotalDeposited/TotalBorrowed totals), with supply_rate = borrow_rate * utilization so interest accrued to borrowers always equals interest credited to suppliers (no protocol fee skim). All accrual math lives in interest.rs as pure, storage-free functions with dedicated unit tests; deposit/borrow/repay/withdraw/record_protocol_fee accrue before their own effects so caps and balances stay accurate, and get_position/ get_asset_reserve reflect live simulated values without persisting. Bumps CONTRACT_VERSION/STORAGE_SCHEMA_VERSION to 2 (VLENDV2) per the project's own versioning convention, since storage layout changed. Along the way, fixed two pre-existing bugs blocking this work: - tests/integration.rs was configured with `harness = false` and an empty main(), silently disabling all 10 integration tests (they never compiled or ran, and used an incorrect contract-registration pattern that wouldn't have compiled anyway). - configure_asset() wrote deposit/borrow caps and totals as untyped integer literals, which Rust defaults to i32, while every reader expects i128 - any configured asset's caps/totals panicked with a storage type mismatch as soon as they were read back. Closes Zyntarivoid#174
Cedarich
approved these changes
Jul 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Introduces index-based accounting (Aave/Compound-style) so borrow and supply balances grow over time instead of remaining static. A new InterestState (supply_index/borrow_index/last_accrual_timestamp) is tracked per asset, with per-position index snapshots realized into Position.deposited/borrowed on every touch. The rate model is a simple, deterministic linear function of utilization (derived from the existing TotalDeposited/TotalBorrowed totals), with supply_rate = borrow_rate * utilization so interest accrued to borrowers always equals interest credited to suppliers (no protocol fee skim). All accrual math lives in interest.rs as pure, storage-free functions with dedicated unit tests; deposit/borrow/repay/withdraw/record_protocol_fee accrue before their own effects so caps and balances stay accurate, and get_position/ get_asset_reserve reflect live simulated values without persisting. Bumps CONTRACT_VERSION/STORAGE_SCHEMA_VERSION to 2 (VLENDV2) per the project's own versioning convention, since storage layout changed.
Along the way, fixed two pre-existing bugs blocking this work:
harness = falseand an empty main(), silently disabling all 10 integration tests (they never compiled or ran, and used an incorrect contract-registration pattern that wouldn't have compiled anyway).Closes #174