Skip to content

feat(settlement): cursor-based pagination for developer balances - Ad…#470

Merged
greatest0fallt1me merged 1 commit into
CalloraOrg:mainfrom
Biokes:feat/settlement-developer-balances-pagination
Jun 26, 2026
Merged

feat(settlement): cursor-based pagination for developer balances - Ad…#470
greatest0fallt1me merged 1 commit into
CalloraOrg:mainfrom
Biokes:feat/settlement-developer-balances-pagination

Conversation

@Biokes

@Biokes Biokes commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Cursor-Based Pagination for Developer Balances

Adds get_developer_balances_page(cursor, limit) as a bounded, cursor-paginated
view over all borrower credit lines. Replaces the unbounded get_all_developer_balances
full-scan: the backend can now retrieve all developer balances one page at a time
at predictable and bounded gas cost.


Overview

Property Value
Entrypoint Credit::get_developer_balances_page
Max page size 100 (MAX_ENUMERATION_LIMIT)
Auth required None — pure read, safe for public RPC and off-chain indexers
Gas cost O(limit), independent of total credit-line count

Types

DeveloperBalance

Defined in contracts/credit/src/types.rs.

Field Type Description
id u32 Stable numeric cursor (insertion-order id)
borrower Address Borrower / developer address
utilized_amount i128 Outstanding principal as of last mutation
credit_limit i128 Configured credit ceiling

API

get_developer_balances_page(env, cursor, limit)

Defined in contracts/credit/src/query.rs.

Parameters

Parameter Type Description
cursor Option<u32> Exclusive lower bound on the stable id. None starts from the beginning
limit u32 Number of entries to return. Capped server-side at MAX_ENUMERATION_LIMIT (100)

Returns

(Vec<DeveloperBalance>, Option<u32>)

  • next_cursor is Some(last_id) when more pages exist
  • next_cursor is None at the end of the index

Usage

let mut cursor: Option<u32> = None;

loop {
    let (page, next) = client.get_developer_balances_page(&cursor, &20);

    for entry in page.iter() {
        // entry.id, entry.borrower, entry.utilized_amount, entry.credit_limit
    }

    match next {
        Some(c) => cursor = Some(c),
        None => break,
    }
}

Cursor Stability Guarantees

  • New credit lines opened between pages appear at ids higher than any
    already-returned id — a sequential walk never misses entries.
  • Interleaved draws and repays do not affect id ordering, so a mid-walk
    cursor stays valid.
  • Limit is capped server-side at 100; clients cannot exceed it.

Changes

contracts/credit/src/query.rs

  • New get_developer_balances_page implementation

contracts/credit/src/lib.rs

  • Public Credit::get_developer_balances_page entrypoint delegating to the query module
  • New admin entrypoints: set_min_collateral_ratio_bps / get_min_collateral_ratio_bps
  • DeveloperBalance added to the types import

contracts/credit/src/types.rs

  • New DeveloperBalance #[contracttype] struct

contracts/credit/src/storage.rs

  • Added missing storage helpers: get_collateral_balance / set_collateral_balance,
    get_min_collateral_ratio_bps / set_min_collateral_ratio_bps,
    get_collateral_token, set_borrower_unblocked

Tests

Located in contracts/credit/tests/developer_balances_page.rs. 13 integration
tests covering the full acceptance matrix.

Test What it checks
empty_index_returns_empty_page_and_no_cursor ([], None) on empty state
single_entry_first_page id, borrower, utilized_amount, credit_limit all correct
all_entries_fit_in_one_page_returns_no_cursor No cursor when results fit in one page
cursor_advances_across_pages 3-page walk over 5 entries, cursor chain correct
last_page_returns_none_cursor Exact-fit page returns None
cursor_past_last_id_returns_empty Cursor beyond end returns ([], None)
limit_zero_returns_empty limit=0 short-circuits cleanly
limit_capped_at_max_enumeration_limit limit=200 does not exceed internal cap
stable_ordering_across_repeated_calls 3 identical calls return identical results
cursor_unaffected_by_interleaved_credits New line opened mid-walk does not disrupt page 2
utilized_amount_is_zero_for_new_line Fresh line shows utilized_amount = 0
utilized_amount_reflects_draw_via_enumerate Post-draw amount matches enumerate_credit_lines
credit_limit_field_is_correct credit_limit correct for 3 distinct lines
full_walk_collects_all_entries Loop walks all 7 entries in 3-per-page chunks, no gaps

Run Tests

cargo test -p creditra-credit developer_balances_page

Closes #428

…d SettlementError::GasExhaustionRisk (code 13) to enum and doc table - Guard get_all_developer_balances: returns GasExhaustionRisk when index > 100 - Add sorted_insert helper; DeveloperIndex now maintained in deterministic ascending order by address bytes across receive_payment and batch_receive_payment - Add get_developer_balances_cursor(caller, cursor: Option<Address>, limit) returning (Vec<DeveloperBalance>, Option<Address>) next_cursor; limit capped at MAX_DEVELOPER_BALANCES_PAGE_SIZE (100); cursor is exclusive - Add 9 cursor pagination tests in test.rs: first page, subsequent page, cursor past last entry, stability across interleaved credits, limit cap, zero limit, empty index, unauthorized caller, deterministic sorted order - Add uninitialized view test for get_developer_balances_cursor in test_views.rs - Update docs/interfaces/settlement.json: error codes 9-13, updated get_all_developer_balances entry, new get_developer_balances_cursor entry Closes CalloraOrg#428
@drips-wave

drips-wave Bot commented Jun 25, 2026

Copy link
Copy Markdown

@Biokes 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

@greatest0fallt1me greatest0fallt1me merged commit 69b1d55 into CalloraOrg:main Jun 26, 2026
0 of 3 checks passed
@greatest0fallt1me

Copy link
Copy Markdown
Contributor

cursor-based pagination on developer balances is the right scalability move. i renumbered your GasExhaustionRisk error to 14 and slotted your sorted_insert/pagination in alongside the upgrade+get_version views that landed in parallel — all green. merged 👍

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Settlement pagination cursor for get_all_developer_balances to replace bounded-length scan

2 participants