Skip to content

fix: reject initiate_recovery while a recovery is already pending (#468) - #639

Open
Seunfunmi-319509 wants to merge 9 commits into
Betta-Pay:mainfrom
Seunfunmi-319509:fix/468-initiate-recovery-overwrite-guard
Open

fix: reject initiate_recovery while a recovery is already pending (#468)#639
Seunfunmi-319509 wants to merge 9 commits into
Betta-Pay:mainfrom
Seunfunmi-319509:fix/468-initiate-recovery-overwrite-guard

Conversation

@Seunfunmi-319509

Copy link
Copy Markdown

Summary

Fixes #468initiate_recovery silently overwrites an in-flight pending recovery.

Problem

Both governance_contract and settlement_contract allowed the recovery address to call initiate_recovery while a PendingRecovery was already stored, silently overwriting the original target with no event distinguishing the overwrite:

  • No has(&CommonDataKey::PendingRecovery) guard — the recovery address could replace a pending recovery mid-window, discarding the original target.
  • No distinct event for the overwrite case.

Solution

Reject a new recovery initiation while one is already pending, with a new shared error code RecoveryAlreadyPending (code 15).

Changes

File Change
bettapay_common/src/error_codes.rs Add RECOVERY_ALREADY_PENDING = 15 shared constant
settlement_contract/src/errors.rs Add RecoveryAlreadyPending = 15 variant + compile-time assertion
governance_contract/src/lib.rs Add RecoveryAlreadyPending = 15 variant + compile-time assertion
settlement_contract/src/admin.rs Guard initiate_recovery with PendingRecovery existence check
governance_contract/src/lib.rs Guard initiate_recovery with PendingRecovery existence check
settlement_contract/src/tests/admin_tests.rs Add initiate_recovery_rejects_overwrite_while_pending test
governance_contract/src/lib.rs (tests) Add initiate_recovery_rejects_overwrite_while_pending test
settlement_contract/src/tests/conformity_tests.rs Add RecoveryAlreadyPending to both error-code tables

Acceptance Criteria

  • Double-initiation is rejected with RecoveryAlreadyPending (error code 15)
  • Tests cover the pending-overwrite case in both contracts
  • cargo test --workspace passes (149/149)
  • cargo fmt --all --check passes
  • cargo clippy --workspace --all-targets --all-features -- -D warnings passes

Error Flow

recovery_address.call(initiate_recovery, new_target_A)  →  Ok (stores PendingRecovery)
recovery_address.call(initiate_recovery, new_target_B)  →  Err(RecoveryAlreadyPending #15)

The recovery address must first call cancel_recovery (requires admin threshold) before initiating a new recovery.

…tta-Pay#468)

Both governance_contract and settlement_contract allowed the recovery
address to call initiate_recovery while a PendingRecovery was already
stored, silently overwriting the original target with no distinguishing
event.

Changes:
- Add shared error code RECOVERY_ALREADY_PENDING (= 15) in bettapay_common
- Add RecoveryAlreadyPending variant to both SettlementError and GovernanceError
- Guard both initiate_recovery functions with a PendingRecovery existence check
- Update conformity tests to cover the new shared error code
- Add initiate_recovery_rejects_overwrite_while_pending tests in both contracts
- Apply cargo fmt fixes for CI compliance
@drips-wave

drips-wave Bot commented Aug 25, 2026

Copy link
Copy Markdown

@Seunfunmi-319509 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

Seunfunmi-319509 and others added 8 commits August 27, 2026 15:39
Resolve duplicate imports in admin.rs, unused variables, duplicate
discriminant values (AlreadyPaused 15→17), missing deployer/executor
args in tests, Symbol→IntoVal conversion, and test snapshot updates
across governance and settlement contracts.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
- timelock tests: re-enable mock_all_auths before execute calls since
  execute now requires executor auth (issue Betta-Pay#561)
- payments proptests: account for network_fee clamping when fees exceed
  gross amount (issue Betta-Pay#683)
- reregistered_merchant test: accept that re-registration clears the
  ArchivedMerchant tombstone (issue Betta-Pay#685)
- set_settlement_rule event test: remove incorrect bootstrap_fallback
  assertion since _set_settlement_rule does not emit that event

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
…ly path

calculate_fee_split is a read-only path and does not emit events
(issue Betta-Pay#691). Verify fee values directly instead of checking for
BOOTSTRAP_FALLBACK_EVENT.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
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.

initiate_recovery silently overwrites an in-flight pending recovery

1 participant