fix(vault): enforce CEI ordering in withdraw and release_payment - #77
Open
divinemike019 wants to merge 1 commit into
Open
fix(vault): enforce CEI ordering in withdraw and release_payment#77divinemike019 wants to merge 1 commit into
divinemike019 wants to merge 1 commit into
Conversation
Reorder both fund-moving functions so every storage write and TTL extension completes before the token::Client::transfer call: withdraw() - asset_account.balance -= amount - env.storage().persistent().set(&asset_key, &asset_account) - extend_persistent_ttl (asset key) - extend_instance_ttl - token_client.transfer(...) ← final interaction release_payment() - task.spent += amount - env.storage().persistent().set(&task_key, &task) - extend_persistent_ttl (task key) - token_client.transfer(...) ← final interaction The transfer now happens last. Because Soroban transactions are atomic, a panicking transfer reverts the whole transaction without leaving any state change behind. Whitelisted assets are still admin-controlled today, so this is not currently exploitable, but ordering writes first removes the bug class entirely and is required practice ahead of the multi-asset roadmap. Each function now carries a doc-comment that calls out the required CEI ordering so a future edit cannot silently reintroduce the bug. All 80 tests pass unchanged (happy-path behavior is identical). cargo clippy --all-targets -- -D warnings reports zero warnings. Closes clevercon-protocol#68
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe vault now persists withdrawal and payment accounting changes, including TTL extensions, before calling external token transfers. Documentation on both functions records this checks-effects-interactions ordering. Public signatures and return types remain unchanged. ChangesVault transfer ordering
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
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.
Summary
Fixes the checks-effects-interactions (CEI) violations in the two fund-moving functions identified in #68.
Both
withdraw()andrelease_payment()previously executed thetoken::Client::transfercall before writing updated state to storage — a classic CEI violation where an external interaction could observe stale contract state.Changes
withdraw()Before (violation):
After (correct):
release_payment()Before (violation):
After (correct):
CEI doc-comments
Each function now carries a
# Checks-Effects-Interactions orderingdoc-comment explaining the required ordering, so a future edit cannot silently reintroduce the bug.Revert-safety reasoning
Soroban transactions are fully atomic. If
token_client.transferpanics, the entire transaction reverts — including the storage writes that now precede it. So decrementing balance without moving funds is impossible: either both the write and the transfer succeed, or neither does.This also means that even if a whitelisted SAC token were replaced in future by a third-party token whose transfer re-entered the contract, the vault's accounting would already reflect the correct post-withdrawal state at the point of re-entry, eliminating the double-spend/double-release class of bug entirely.
Testing
cargo clippy --all-targets -- -D warningsreports zero warnings.Closes #68
Summary by CodeRabbit