Skip to content

fix(settlement): add cross-contract reentrancy guard (#8)#42

Merged
elizabetheonoja-art merged 1 commit into
Utility-Protocol:mainfrom
real-venus:fix/settlement-reentrancy-guard
Jun 25, 2026
Merged

fix(settlement): add cross-contract reentrancy guard (#8)#42
elizabetheonoja-art merged 1 commit into
Utility-Protocol:mainfrom
real-venus:fix/settlement-reentrancy-guard

Conversation

@real-venus

Copy link
Copy Markdown
Contributor

fix(settlement): cross-contract reentrancy guard

Closes #8

Solution

A strict RAII reentrancy mutex acquired before any external call and released on
scope exit.

  • storage.rs — new DataKey::ReentrancyLock, held in temporary storage.
  • reentrancy.rsReentrancyGuard:
    • new(&env) panics with SettlementError::ReentrantCall if the lock is already
      held, otherwise sets it (TTL 1 ledger).
    • Drop clears the lock on normal return.
    • On a panic the host reverts all storage writes, so the lock is discarded
      automatically — necessary because Wasm builds use panic = "abort", where
      Drop does not run during unwinding.
  • lib.rslet _guard = ReentrancyGuard::new(&env); at the top of settle
    and finalize_settlement; added SettlementError::ReentrantCall = 4.

Invariant: while any external call is in flight, the lock is set; any re-entry
into a guarded entry point aborts the transaction.

Files

  • contracts/settlement/src/storage.rs (new)
  • contracts/settlement/src/reentrancy.rs (new)
  • contracts/settlement/src/lib.rs (guards + error variant)
  • contracts/settlement/src/test.rs (attack + regression tests)

)

Settlement entry points yield control to untrusted contracts at the
cross-contract call boundary (oracle get_price_value, token transfer via
collect_fee and the net transfer). A malicious token or oracle could
re-enter settle/finalize_settlement before the first invocation completes
and manipulate intermediate state.

- Add DataKey::ReentrancyLock in storage.rs (temporary storage)
- Add ReentrancyGuard RAII mutex in reentrancy.rs: acquire-before-call,
  release on Drop; strict (any re-entry panics with ReentrantCall).
  Panic path is covered by the host's storage revert (wasm uses
  panic=abort, so Drop does not run on unwind).
- Acquire the guard at the top of settle() and finalize_settlement()
- Add SettlementError::ReentrantCall
- Tests: malicious-token reentry via settle and via finalize_settlement
  are both rejected; legitimate single settle still succeeds
@elizabetheonoja-art elizabetheonoja-art merged commit 2145c20 into Utility-Protocol:main Jun 25, 2026
2 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

Development

Successfully merging this pull request may close these issues.

Cross-Contract Reentrancy via Settlement Callback Recursion

2 participants