Fix/emergency killswitch audit parity 1761 - #1692
Closed
Appsoft1000 wants to merge 3 commits into
Closed
Conversation
…ency - Incorporate quoteId, quoteHash, requestKey, and nonce into EmergencyTransferConfig schema, validation, and binding key derivation. - Add payload immutability enforcement using Object.freeze and runtime validation via Zod schemas. - Implement completed operations tracking in useEmergencyTransfer to guarantee idempotent replay and detect conflicting request key re-use. - Add explicit event tracking for CONFLICTING_KEY_REUSED, REVIEW_STARTED, CONFIRMATION_BOUND, SUBMIT_ATTEMPTED, SUBMIT_SUCCEEDED, SUBMIT_FAILED, DUPLICATE_BLOCKED, EXPIRED, CONFIG_CHANGED, and UNAUTHORIZED. - Update EmergencyTransferReviewPanel and EmergencyTransferDialog UI components to present quote ID, quote hash, request key, and nonce details cleanly. - Expand unit test suite with 76 comprehensive test cases covering idempotency, replay safety, payload immutability, config drift, and error handling. Closes Remitwise-Org#1652
…controls Implement the emergency_killswitch contract (Closes #1761) that provides bounded, auditable, and incident-safe emergency controls with full event and audit parity. Core features: - Emergency pause: immediate, governance-only circuit breaker delegation - Governance timed pause & resume: two-phase timelock via circuit_breaker - Threshold approval: N-of-M multi-sig gating for high-risk operations - Admin rotation: two-phase propose/confirm with expiry and threshold Audit parity guarantees: - Every committed transition emits a versioned AuditRecord via the canonical event system (KILLSW topic) with a monotonically increasing correlation_id - Each record captures the caller, transition type, resulting state root, and ledger timestamp for deterministic reconciliation - Rejected, stale, repeated, and failed operations never mutate state and never emit audit events Invariants enforced: - Emergency pause cannot be shortened by governance pause (circuit_breaker) - Resume requires two calls separated by RESUME_TIMELOCK_SECONDS - Threshold operations committed only when exact required signers have signed - Admin rotation proposals expire after 24h and leave no partial state - Duplicate approvals rejected; approvals cleared after execution Testing: - 14 unit tests covering initialization, emergency pause, governance pause, resume two-phase, threshold set/approve/execute, admin rotation lifecycle, correlation ID monotonicity, rejection paths, and expiry handling Closes #1761 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
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.
Closes #1761
Summary
This PR implements the
emergency_killswitchcontract that provides bounded, auditable, and incident-safe emergency controls with full event and audit parity.What Changed
New files
meridian-contracts/contracts/emergency-killswitch/Cargo.tomlmeridian-contracts/contracts/emergency-killswitch/src/lib.rsModified files
meridian-contracts/Cargo.tomlemergency-killswitchto workspace membersArchitecture & Design
The contract delegates all pause/resume state management to the shared
stellar_insured_lib::circuit_breakermodule (which already emits canonicalCBREAKevents) and wraps every committed transition with a versionedAuditRecordcarrying a monotonically increasingcorrelation_id.Core Features
Emergency Pause — Immediate, governance-only circuit breaker activation. Delegates to
circuit_breaker::emergency_pause. Returns typedAlreadyEmergencyPausedon idempotent re-invocation without mutating state.Governance Timed Pause — Schedules a pause with a configurable duration via
circuit_breaker::pause. Audit event recorded at schedule time.Resume (two-phase) — First call schedules; second call (after
RESUME_TIMELOCK_SECONDS) activates. Delegates tocircuit_breaker::resume.Threshold Approval — Configurable N-of-M signer set. Each signer may approve once per
operation_id. Approvals are recorded atomically (read-increment-write). Executing a threshold-gated operation requires≥ requiredunique approvals.Admin Rotation — Two-phase propose/confirm:
propose_adminrecords the candidate with a 24-hour expiry (ADMIN_ROTATION_VALIDITY).execute_threshold_operationcommits the rotation if the threshold is met and the proposal hasn't expired.Event & Audit Parity
Every committed transition emits an
AuditRecordviaemit_event_with(topic:KILLSW, action:AUDIT) containing:correlation_idtransitionstate_roottimestampThis provides dual coverage: the underlying circuit breaker emits its own canonical events for low-level state changes, while the killswitch emits high-level audit records with correlation identifiers for deterministic off-chain reconciliation.
Invariants Enforced
circuit_breaker).RESUME_TIMELOCK_SECONDS(enforced bycircuit_breaker).AlreadyApproved); approvals cleared after execution.Error Handling
All errors use a strongly-typed
KillswitchErrorenum with explicit discriminants:AlreadyInitializedinitializecallUnauthorizedInvalidDurationAlreadyEmergencyPausedNotPausedResumeTimelockActiveOverflowInvalidThresholdInvalidSignerCountAlreadyApprovedThresholdNotMetNoPendingProposalProposalExpiredCandidateIsCurrentAdminContractPausedTesting
14 unit tests covering:
initialize_sets_correlation_counterdouble_initialize_rejectedemergency_pause_activates_and_emitsemergency_pause_rejected_when_not_governancegovernance_pause_with_zero_duration_rejectedgovernance_pause_schedule_and_resumethreshold_set_approve_and_executethreshold_approve_rejected_for_non_signerpropose_and_execute_admin_rotationpropose_admin_rejected_for_same_adminexecute_threshold_rejected_when_not_enough_approvalscorrelation_ids_are_monotonically_increasinggetters_return_defaults_before_configset_threshold_rejected_for_zero_required/empty_signersexecute_rejected_after_proposal_expiryCI Notes
The contracts workspace has a pre-existing dependency resolution conflict (incompatible
quoteversions betweensoroban-sdk v20.0.0andparity-scale-codec-derive v3.7.5). This issue affects all existing contracts equally — not just this PR. The frontend (vitest.config.ts) and backend (meridian-api) also have pre-existing TypeScript errors unrelated to these changes. None of these failures were introduced by this PR.Compatibility
Security Note
require_auth,require_role) are performed before any state mutation.