Skip to content

Fix CI failures: remove stray file and duplicate module declaration - #1

Open
QwinDivy wants to merge 37 commits into
mainfrom
feature/rate-model-doc
Open

Fix CI failures: remove stray file and duplicate module declaration#1
QwinDivy wants to merge 37 commits into
mainfrom
feature/rate-model-doc

Conversation

@QwinDivy

@QwinDivy QwinDivy commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Summary

Type of change

  • Bug fix
  • New feature / functionality
  • Refactor (no functional change)
  • Documentation only
  • Contract storage / upgrade change

Contracts Release Checklist

Full checklist: docs/release_checklist.md
Skip sections that do not apply and note why.

Functional tests

  • New public functions have success-path and failure-path tests
  • All new error codes are reachable through a test
  • Zero/negative/boundary values tested for numeric inputs
  • cargo test passes — no new failures beyond the known baseline

Invariants

  • Cross-asset view guarantees G-1..G-10 hold (if cross_asset touched)
  • Repay semantics preserved: borrow system errors on overpay; cross-asset clamps
  • Interest ceiling division unchanged (interest ≥ 1 for any principal > 0 && elapsed > 0)

Upgrade safety (skip if no storage / signature changes)

  • No storage key renamed or removed without a migration path
  • New persistent entries documented in docs/storage.md
  • initialize still idempotent (second call → AlreadyInitialized)

Monitoring / events (skip if no event changes)

  • New operations emit an event with topic + data
  • No existing topic string renamed silently

Security notes

Auth / access control

  • require_auth() called for every entry point that modifies user state
  • No new function bypasses the pause guard without justification

Arithmetic

  • No unchecked arithmetic on untrusted values
  • No new division site can produce divide-by-zero

Reentrancy (skip if no cross-contract calls)

  • State updated before external call (Checks-Effects-Interactions)

Rounding

  • Floor for collateral capacity; ceiling for interest owed

Docs

  • Public functions have a doc comment (error codes, params, return)
  • Relevant docs sections updated (CROSS_ASSET_RULES.md, REPAY_SEMANTICS.md, storage.md)

CI

  • cargo fmt --check passes
  • cargo clippy -- -D warnings passes
  • No secrets or key material committed

Stellar Intel Dev and others added 30 commits June 30, 2026 09:08
…ding

- Add comprehensive RATE_MODEL.md documenting piecewise formula, parameters, and worked examples
- Document RateParams struct with detailed field descriptions
- Add extensive doc comments to compute_borrow_rate() with formula, examples, and cross-links
- Add default configuration documentation with interpretation table
- Include ASCII curve sketch showing pre-kink and post-kink slopes
- Provide worked rate computations at 0%, kink, 50%, 95%, and 100% utilization
- Cross-link from docs/INDEX.md under Lending & Risk section
- Cross-link from stellar-lend/contracts/lending/README.md in Documentation section
- All parameters validated against RateParams::default()

Implements issue StellarLend#1057 requirements:
✓ Clear, reviewer-friendly documentation matching rate_model.rs exactly
✓ Piecewise borrow-rate formula with full derivation
✓ Parameter reference with default values
✓ ASCII curve sketch
✓ Worked rate computations at representative utilizations
✓ Cross-linked from lending README and docs/INDEX.md
…S.md (StellarLend#1588)

Replaces all three references to the nonexistent get_debt_balance()
with get_debt_position(), noting that callers must derive the
interest-inclusive effective balance via debt::effective_debt.

Closes StellarLend#1554
…StellarLend#1587)

Closes: docs/multisig.md described a completely fictional API that had
zero overlap with the actual MultisigContract shipped in
stellar-lend/contracts/multisig/src/lib.rs.

--- Issue being closed ---

The old docs/multisig.md documented the following names that do not
exist anywhere in the real contract codebase:

  Functions:
    ms_set_admins, ms_propose_set_min_cr, ms_approve, ms_execute
    get_ms_admins, get_ms_threshold, get_ms_proposal, get_ms_approvals
    cleanup_expired, get_default_expiry_ledgers

  Events:
    proposal_created, proposal_approved, proposal_executed

These ms_-prefixed identifiers match stale references in the
hello-world placeholder crate (stellar-lend/contracts/hello-world/src/
multisig.rs), which is a one-line stub (// Stub module) and does not
expose any entrypoints at all.  The documentation was therefore wrong
for both possible subjects: it did not describe the real contract, and
the hello-world module it appears to have been copied from does not
implement anything either.

--- What was done ---

The full source of MultisigContract was read (lib.rs, ~350 lines).
The real public API was established from the #[contractimpl] block:

  Public entrypoints (on-chain callable):
    initialize(env, signers, threshold)
    create_proposal(env, caller, action, payload_hash, ttl_ledgers) -> u64
    approve_proposal(env, caller, id)
    execute_proposal(env, caller, id, payload_hash)
    cancel_proposal(env, caller, id)

  Types used by the API:
    ProposalAction   — SetThreshold | RotateSigners | InvokeContract
    ProposalStatus   — Active | Passed | Executed | Expired | Cancelled
    Proposal struct  — id, proposer, action, payload_hash, approvals,
                       status, expires_at
    MultisigError    — 12 variants mapped to panic strings
    ProposalExecutedEvent — id, action_kind, ok

  Storage keys (MultisigDataKey):
    Threshold, Signers, ProposalCount, Proposal(u64)

  Events:
    Only one event: ProposalExecutedEvent published by execute_proposal
    with topics ("multisig", "executed").  No events on create/approve/
    cancel.

  Test-only helpers (inside #[cfg(test)] mod tests, NOT on-chain):
    get_threshold(env), get_signers(env), get_proposal(env, id)

  No cleanup_expired entrypoint exists.  Proposal records persist in
  storage after execution/cancellation for auditability.

--- How the rewrite was structured ---

docs/multisig.md was replaced in full with a document that covers:

  1. Overview + scope note (clarifies hello-world stub vs real contract)
  2. Proposal flow diagram (initialize → create → approve → execute)
  3. All five public entrypoints with parameter tables, auth requirements,
     return values, and panic conditions
  4. execute_proposal action-dispatch table (SetThreshold / RotateSigners /
     InvokeContract effects and failure modes)
  5. All types: ProposalAction, ProposalStatus, Proposal, MultisigError
  6. Storage layout table (MultisigDataKey variants)
  7. Events section (single ProposalExecutedEvent, topics, payload)
  8. Test-only helpers clearly marked as NOT on-chain callable
  9. Security model threat/mitigation table
  10. Test coverage table listing all six #[cfg(test)] modules and their scope
  11. Extension guide: how to add a new ProposalAction variant
  12. Failure recovery scenarios (deadlock, malicious proposal, key loss)

All references to ms_-prefixed functions, get_ms_admins, cleanup_expired,
get_default_expiry_ledgers, the old three-event model, the GovernanceDataKey
storage table, the SignersChange timelock section, and the hello-world
integration snippets have been removed, as none of those reflect code that
exists in the stellarlend-multisig crate.
Co-authored-by: kingsley <ogbukingsley166@gmail.com>
StellarLend#1585)

* Add: added missing return type to AMM reentrancy guard helper so its body now correctly matches all existing call sites

* Fix: Repaired the malformed closure in the lendin contract and fixed the missing closing parenthesis in the reentrancy tests call so the rust delimiters are balanced again
…age() (StellarLend#1582)

The validator-rotation section of contracts/bridge/src/lib.rs used
self.validators, self.paused_validators, self.epoch, self.bridge_id,
self.guardian, self.max_churn and related window fields — none of which
exist on the unit struct Bridge{}, and which also relied on non-Soroban
types (ed25519-dalek PublicKey/Signature, std HashSet, anyhow, bincode)
that are unavailable in a no_std Soroban environment.

Changes:
- Rewrite every &self / &mut self method to take env: Env and read/write
  all state through env.storage().persistent() via named BridgeDataKey
  variants (Validators, PausedValidators, Epoch, BridgeId, Guardian,
  MaxChurn, and all window fields).
- Replace HashSet duplicate-detection with soroban_sdk::Map<BytesN<32>, bool>.
- Replace ed25519-dalek signature verification with env.crypto().ed25519_verify().
- Replace bincode serialization with a manual Bytes builder hashed via
  env.crypto().sha256(), preserving the same domain-separation structure
  (QUORUM_PROOF_DOMAIN tag || bridge_id || validators || epoch).
- Replace anyhow::Result with Result<T, BridgeError>; add new error
  variants for every rejection path.
- Remove the fourteen standalone *_test.rs modules that used Bridge::new()
  and ed25519-dalek; replace with a single inline #[cfg(test)] mod tests
  block using soroban_sdk testutils.
- Add contracts/bridge to the workspace members list in stellar-lend/Cargo.toml
  so cargo check -p stellarlend-bridge is reachable.
…racle.rs broken import (StellarLend#1581)

* centralize admin authorization checks

* fix(StellarLend#1454): consolidate require_admin into admin.rs; fix oracle.rs broken import

oracle.rs: replace broken use crate::risk_management::get_admin with
use crate::admin::get_admin. The risk_management module is a stub and
never defined get_admin; admin::get_admin returns Option<Address> and
is the correct shared source for admin lookups across the crate.

lib.rs: move require_admin import from the stub crate::risk_management
to crate::admin (where pub fn require_admin already lives). Update all
four call sites to use require_admin(...).map_err(|_| RiskManagementError::Unauthorized)?
for correct error-type conversion without requiring a From impl.

admin.rs, bridge.rs, and cross_asset.rs were already correct.
Every admin authorization check in the crate now resolves to the single
shared crate::admin::require_admin.

---------

Co-authored-by: samuelaladesiun <samuelaladesiun2005@gmail.com>
Co-authored-by: Developer <developer@teachlink.com>
Replace stub flash_loan.rs with a real implementation exporting all
six symbols lib.rs expects:
  - FlashLoanConfig / FlashLoanError types
  - configure_flash_loan, set_flash_loan_fee (admin-gated)
  - execute_flash_loan (treasury check, invoke_contract callback,
    post-callback balance verification)
  - repay_flash_loan (payer-authorised treasury credit)

Uses Symbol-keyed instance storage for FlashFeeBps/FlashActive and
a per-asset FlashLoanDataKey::Treasury for treasury balances,
matching the lending contract's design.

Also fix a malformed doc-comment/function-signature line in
governance.rs that prevented compilation.
…(compute_health_factor, compute_borrow_rate, compute_supply_rate, compute_utilization, etc.) is dead code never called by the production contract (StellarLend#1576)

* fix: add missing borrow_index_snapshot field in settle_accrual_split

- Fixed missing required field in DebtPosition struct literal
- Addresses issue StellarLend#1504: settle_accrual_split() was missing borrow_index_snapshot
- Now preserves borrow_index_snapshot from original position, consistent with settle_accrual()

* JSON

* fix(lending): remove dead duplicate math
…egistration logic (StellarLend#1574)

Co-authored-by: I-am-Byte <victor.olaomo@outlook.com>
…1523)

Co-authored-by: laxjovial <laxjovial@users.noreply.github.com>
…ructs DebtPosition without the required borrow_index_snapshot field (StellarLend#1522)

* fix: add missing borrow_index_snapshot field in settle_accrual_split

- Fixed missing required field in DebtPosition struct literal
- Addresses issue StellarLend#1504: settle_accrual_split() was missing borrow_index_snapshot
- Now preserves borrow_index_snapshot from original position, consistent with settle_accrual()

* JSON
…sal_threshold gate (Closes StellarLend#1480) (StellarLend#1521)

- vote(): replaces hardcoded weight=1 with TokenClient::balance(&voter)
  so voting power is proportional to vote_token holdings
- create_proposal(): adds proposal_threshold check — non-admin
  proposers must hold at least config.proposal_threshold vote tokens

Co-authored-by: Carlys17 <carlys17@users.noreply.github.com>
…tic (Closes StellarLend#1426) (StellarLend#1520)

The vested_at() function cast total_amount (i128) to u64 via 'as',
which silently truncates amounts exceeding u64::MAX (~1.8e19).
For token amounts with high decimals this is a real truncation risk.

Fix: compute vested = total_amount * elapsed / duration_secs entirely
in i128 using checked_mul/checked_div, preserving full precision.
On overflow, return total_amount (conservative — user keeps tokens).

Co-authored-by: Carlys17 <carlys17@users.noreply.github.com>
…tellarLend#1493)

Both checked_sub calls in LendingContract::withdraw were using .expect()
which would abort the transaction with an opaque panic if TotalDeposits
ever drifted below the withdrawn amount (e.g. due to a prior accounting
bug). This is inconsistent with every other checked-arithmetic call in
the function, which already uses .ok_or(LendingError::Overflow)?.

Changes:
- current.checked_sub(amount).expect("withdraw: underflow")
  → .ok_or(LendingError::Overflow)?
- total_deposits.checked_sub(amount).expect("withdraw: total deposits underflow")
  → .ok_or(LendingError::Overflow)?

Also adds withdraw_overflow_test.rs with three tests:
- Simulates corrupt TotalDeposits (drift below user balance) and asserts
  LendingError::Overflow is returned instead of a panic
- Confirms a valid withdrawal still succeeds
- Confirms withdrawing over the user balance returns InvalidAmount
Co-authored-by: Lumina Developer <developer@lumina.market>
* test(lending): cover liquidate close-factor cap and seizure clamp branches

Five tests in liquidation_branch_test.rs pin every arithmetic branch
in the liquidate function:

- test_close_factor_cap_applied_when_amount_exceeds_half_debt
  amount > max_repay → actual_repay capped at debt * 5000 / 10000

- test_seizure_clamp_when_incentive_exceeds_available_collateral
  seized_collateral > collateral → final_seized clamped to collateral

- test_sequential_partial_liquidations_reduce_debt_cumulatively
  two consecutive liquidations on same borrower; cumulative debt assert

- test_healthy_position_rejected_with_position_healthy_error
  hf >= 10000 → PositionHealthy error

- test_zero_debt_rejected_with_position_healthy_error
  debt == 0 → PositionHealthy error

Also registers the module in lib.rs and cross-links from
liquidation_events.md.

* test(lending): fix fmt - rewrite liquidation_branch_test in clean rustfmt style

* Guard flash_loan with check_emergency_status

Add missing check_emergency_status(&env, ProtocolAction::FlashLoan)
at the top of flash_loan, consistent with deposit, withdraw, borrow,
and repay which all guard against emergency state before executing.

* Replace .expect() with .ok_or(LendingError::Overflow)? in withdraw

Both checked_sub calls in LendingContract::withdraw were using .expect()
which would abort the transaction with an opaque panic if TotalDeposits
ever drifted below the withdrawn amount (e.g. due to a prior accounting
bug). This is inconsistent with every other checked-arithmetic call in
the function, which already uses .ok_or(LendingError::Overflow)?.

Changes:
- current.checked_sub(amount).expect("withdraw: underflow")
  → .ok_or(LendingError::Overflow)?
- total_deposits.checked_sub(amount).expect("withdraw: total deposits underflow")
  → .ok_or(LendingError::Overflow)?

Also adds withdraw_overflow_test.rs with three tests:
- Simulates corrupt TotalDeposits (drift below user balance) and asserts
  LendingError::Overflow is returned instead of a panic
- Confirms a valid withdrawal still succeeds
- Confirms withdrawing over the user balance returns InvalidAmount
…point (StellarLend#1396)

Add 
equire_initialized guard to every state-mutating entry point in
the StellarLend lending contract so that callers receive a typed
LendingError::NotInitialized instead of an opaque unwrap panic when
the contract has not been initialized yet.

## Changes

### src/lib.rs
- Add pub(crate) fn require_initialized(env) — checks DataKey::Admin
  presence and returns Err(LendingError::NotInitialized) when absent.
- Guard added at the top of: deposit, withdraw, �orrow, 
epay,
  �orrow_against_collateral, 
epay_against_collateral, liquidate,
  lash_loan, 
epay_flash_loan, set_price, set_oracle_pubkey,
  set_max_move_bps, set_max_flash_bps, set_price_bounds,
  propose_admin, �ccept_admin, set_guardian, set_emergency_state,
  set_pause, set_min_borrow, set_asset_isolation,
  set_collateral_asset, set_close_factor_bps,
  set_liquidation_incentive_bps, set_debt_ceiling, set_flash_fee,
  und_insurance, set_insurance_share, credit_insurance_fund,
  write_off_bad_debt, set_asset_params, deposit_collateral_asset,
  �orrow_asset, 
epay_asset, withdraw_asset.
- initialize changed from -> () (panic on double-init) to
  -> Result<(), LendingError> returning AlreadyInitialized.
- Add LendingError::InvalidIsolationCeiling = 7003 and
  LendingError::SelfLiquidation = 7004 (referenced but undeclared).
- Fix pre-existing corrupted lines: stray grep fragment in
  
epay_flash_loan, stray supply_cap guards in liquidate /
  lash_loan, duplicate pub mod rounding_strategy / mod
  repay_overpay_test / mod effective_supply_rate_test declarations.

### src/initialization_guard_test.rs (new)
- 41 tests covering every guarded entry point pre-init, double-init edge
  cases, view-function safety before init, and post-init happy paths.

### docs/INITIALIZATION_TESTS.md
- Updated to document the new guard, protected entry point table, and
  updated run commands.

### stellar-lend/contracts/hello-world/INITIALIZATION_SECURITY_NOTES.md
- Added '✅ Initialization Guard (implemented)' section at the top with
  code snippet and updated testing-coverage checklist.

Co-authored-by: Muhammadcodes112 <funuyallen@gmail.com>
…llarLend#1388)

- Add SwapQuote struct (#[contracttype]) with amount_out, fee,
  reserve_a_after, reserve_b_after fields
- Add get_swap_quote(env, amount_in, fee_bps, a_for_b) to AmmContract
  using the identical constant-product formula and compute_fee as the
  live swap paths; no storage writes, no events emitted
- Returns Err(AmmPoolError::EmptyPool) on zero reserves instead of panic
- Supports both swap directions via the a_for_b flag
- Add swap_quote_test.rs covering: quote matches live swap to the unit
  (both directions), zero reserves safe error, large amount near depletion,
  fee matches compute_fee, no state mutation
- Add SWAP_QUOTE.md with rationale, worked numeric example, and edge-case notes

Co-authored-by: David Nkwazema <NKWA@Davids-MacBook-Air.local>
…tellarLend#1387)

- Add CROSS_ASSET_HEALTH.md with the full aggregation formula, every
  scaling constant (PRICE_DIVISOR, HEALTH_FACTOR_SCALE,
  HEALTH_FACTOR_NO_DEBT), rationale for why PRICE_DIVISOR cancels in
  the HF path, rounding direction (floor), no-debt sentinel, and a
  two-collateral two-debt worked example (XLM + USDC collateral /
  XLM + USDC debt → HF = 36 666).

- Add cross_asset_health_doctest.rs with five independent tests:
    · test_two_collateral_two_debt_health_factor  (spec §5)
    · test_no_debt_saturated_sentinel             (spec §3)
    · test_empty_position_returns_sentinel        (spec §3)
    · test_single_collateral_single_debt_boundary (spec §6.1)
    · test_floor_rounding_direction               (spec §4/§6.3)
    · test_usd_view_functions_match_spec          (spec §9)

Closes #<issue>
Co-authored-by: Hintents Developer <dev@hintents.io>
Co-authored-by: 1nonlypiece <jagadeesh26062002@gmail.com>
Devadakene and others added 7 commits July 24, 2026 20:41
* Add trivial main function to scaling_demo example (fix Cargo example build)

* Add missing oracle_payload_binding_test module and fix duplicate cfg attribute

---------

Co-authored-by: 1nonlypiece <jagadeesh26062002@gmail.com>
Add #[cfg(test)] mod missing_price_test; to the test module block in
lending/src/lib.rs so the existing missing_price_test.rs file is compiled
and its tests execute under cargo test -p stellarlend-lending.

Co-authored-by: David Nkwazema <NKWA@Davids-MacBook-Air.local>
Co-authored-by: 1nonlypiece <jagadeesh26062002@gmail.com>
* fix: remove orphaned contracts/lending/scr dead code (StellarLend#1442)

The contracts/lending/scr/ directory was unreachable dead code:
- 'scr' is a typo of 'src' and not part of any mod tree
- No Cargo workspace claims this directory
- test.rs called LendingContract APIs that don't exist in adjacent lib.rs
- lib.rs only contained scale_bps/unscale_bps helpers (now in stellar-lend-common)
- README.md explicitly marked it as a 'misnamed reference tree'

All three test scenarios from the deleted test.rs are fully covered by
canonical tests in stellar-lend/contracts/lending/src/:

1. Fresh price valuation → oracle_staleness_test::borrow_accepts_price_exactly_at_max_age
2. Stale price rejection → oracle_staleness_test::borrow_rejects_when_*_price_is_just_stale
3. Decimal normalization → hello-world/normalize_price_test::test_scale_{up,down}

The canonical tests are more comprehensive: they test both collateral and
debt price staleness, cover borrow + liquidate operations, and test both
floor and ceiling rounding for decimal conversion.

Closes StellarLend#1442

* fix: repair corrupted liquidate function and reentrancy test

Fixes CI build failures caused by malformed code:

1. stellar-lend/contracts/lending/src/lib.rs (liquidate function):
   - Removed stale draft code blocks that were merged into the canonical
     implementation (lines referencing undefined get_close_factor_bps,
     get_liquidation_incentive_bps, and threshold_bps calculation before
     variables were defined)
   - Added missing col_key and debt variable definitions
   - Added missing zero-debt check
   - Removed injected supply_cap guard fragment
   - Removed duplicated bad-debt event publish and orphaned else branch

2. stellar-lend/contracts/lending/tests/reentrancy_guard_test.rs:
   - Added missing closing parenthesis on line 309 in
     test_borrow_blocked_during_flash_loan

These errors existed on main and were not introduced by any recent PR.

* fix: remove additional syntax corruption in flash_loan and tests

- Line 1746: Remove spurious 'if supply_cap < 0' block injected into
  flash_loan's treasury update (should be simple set call)
- Line 1683: Remove corrupted grep command in check_emergency_status call
- reentrancy_guard_test.rs: Remove extra blank lines after
  Bytes::from_slice calls (lines 288, 326, 345, 364, 382)
- Fix indentation on params declaration in test_deposit_blocked

* fix: use XDR encoding for Address in reentrancy tests

Replace Address::from_string_bytes (which doesn't exist) with
Address::from_xdr for proper deserialization of contract addresses
passed via flash loan params.

Also update params encoding to use contract_id.to_xdr() instead of
contract_id.to_string().to_bytes() for consistency.

---------

Co-authored-by: 1nonlypiece <jagadeesh26062002@gmail.com>
…Soroban's 9-character limit (StellarLend#1488)

* Fix hello-world TWAP fallback event symbol

* Fix lending CI parse and build failures

---------

Co-authored-by: 1nonlypiece <jagadeesh26062002@gmail.com>
…llarLend#1402)

* feat: add batch_execute to multisig contract with tests and docs

* fix: resolve mismatched delimiter and merge-artifact errors in lending lib.rs and reentrancy_guard_test.rs

* .

---------

Co-authored-by: 1nonlypiece <jagadeesh26062002@gmail.com>
# Conflicts:
#	stellar-lend/contracts/lending/src/lib.rs
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.