Skip to content

fix(creditline): propagate reputation contract call failures to enforce atomic state-reputation invariant - #104

Merged
EmeditWeb merged 2 commits into
StepFi-app:mainfrom
sublime247:fix/reputation-call-error-handling
Aug 29, 2026
Merged

fix(creditline): propagate reputation contract call failures to enforce atomic state-reputation invariant#104
EmeditWeb merged 2 commits into
StepFi-app:mainfrom
sublime247:fix/reputation-call-error-handling

Conversation

@sublime247

Copy link
Copy Markdown
Contributor

Summary of Changes

Closes #86

Problem

In contracts/creditline-contract/src/lib.rs, cross-contract calls to the reputation contract in mark_defaulted() (decrease_score) and handle_reputation_increase() (increase_score) used fire-and-forget let _ = env.try_invoke_contract(...) statements. If the reputation contract reverted (e.g. revoked updater status, TTL expiry, or WASM mismatch), the loan would default or settle while the reputation score mutation silently failed, creating state-reputation divergence.

Policy Decision: Option (a) — Propagate Failure

Chosen policy: Option (a) — Propagate failure to enforce atomic loan state and reputation score consistency.

  • Matching the error handling pattern in vouching-contract (add_reputation_boost), both invocation and execution results of try_invoke_contract are strictly checked.
  • If a reputation contract call fails when configured (Some(reputation_contract)), the contract emits a ScoreUpdateFailed event and panics with panic_with_error!(&env, CreditLineError::ReputationCallFailed).
  • This reverts the surrounding transaction, guaranteeing that loan status (Defaulted/Paid) and borrower reputation scores can never diverge.
  • If no reputation contract is configured (None), score updates are intentionally skipped with documented rationale, as the protocol is operating without on-chain reputation integration.

Implementation Details

  • contracts/creditline-contract/src/errors.rs: Added ReputationCallFailed = 32 error variant.
  • contracts/creditline-contract/src/events.rs: Added emit_score_update_failed(&env, borrower, is_increase, amount) helper emitting ScoreUpdateFailed topic.
  • contracts/creditline-contract/src/lib.rs: Removed bare let _ = discards in mark_defaulted() and handle_reputation_increase(), enforcing strict result handling, event emission, and atomic panic on failure.
  • contracts/creditline-contract/src/tests.rs: Updated test_reputation_call_failure_reverts_repayment and added test_reputation_call_failure_reverts_default simulating reputation contract failure for both increase and decrease paths.
  • context/progress-tracker.md: Documented security fix and Policy Option (a) decision under Recently Fixed.

Verification Results

  • cargo test -p creditline-contract: 141 passed; 0 failed
  • cargo test (full workspace): 389 passed; 0 failed across all 6 contracts.

@sublime247
sublime247 requested a review from EmeditWeb as a code owner August 29, 2026 22:46
EmeditWeb

This comment was marked as off-topic.

@EmeditWeb

Copy link
Copy Markdown
Member

⚠️ @sublime247 this PR now has merge conflicts with the base branch (likely because another PR was merged first).

Please rebase/merge the base branch into your branch and resolve the conflicts — a fresh audit will run automatically once new commits land.

EmeditWeb
EmeditWeb previously approved these changes Aug 29, 2026

@EmeditWeb EmeditWeb left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Automated Audit: solves

@sublime247 Excellent work, thank you! 🎉

The PR genuinely fixes issue #86 by replacing fire-and-forget let _ = discards with strict result handling in both mark_defaulted() and handle_reputation_increase(). On reputation contract failure, it emits ScoreUpdateFailed event and panics with CreditLineError::ReputationCallFailed, atomicating the revert so loan state and scores never diverge. New tests (test_reputation_call_failure_reverts_repayment, test_reputation_call_failure_reverts_default) verify the revert behavior for both paths. All 389 workspace tests pass.


CI checks: ✅ PASSED: Build and Test Contracts
Merge conflicts: ⚠️ YES — this PR has conflicts with the base branch and cannot be merged. Please resolve the conflicts before this PR can be approved.

Audited by stepfi-audit-bot 🤖

@sublime247

Copy link
Copy Markdown
Contributor Author

@EmeditWeb review

@EmeditWeb
EmeditWeb merged commit c418bcd into StepFi-app:main Aug 29, 2026
1 check 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

Development

Successfully merging this pull request may close these issues.

hard: swallowed reputation-call failures let defaulters keep scores and good payers lose boosts

2 participants