Skip to content

feat: implement multi-sig admin approval for high-risk pool actions - #251

Open
olaleyeolajide81-sketch wants to merge 3 commits into
JointSave-org:mainfrom
olaleyeolajide81-sketch:feat/multisig-admin-controls
Open

feat: implement multi-sig admin approval for high-risk pool actions#251
olaleyeolajide81-sketch wants to merge 3 commits into
JointSave-org:mainfrom
olaleyeolajide81-sketch:feat/multisig-admin-controls

Conversation

@olaleyeolajide81-sketch

Copy link
Copy Markdown
Contributor

Summary

Implements threshold-based multi-sig admin approval for high-risk pool actions (emergency_withdraw, pause/unpause, remove_member) across all three pool contracts (Rotational, Target, Flexible), with corresponding frontend UI components for managing quorum admins and approving pending actions.

Closes #181

Smart Contract Changes

All three pool contracts (rotational, target, flexible) receive identical multi-sig infrastructure:

New Storage

  • AdminQuorumVec<Address> storing the set of designated multi-sig admins
  • PendingAction(BytesN<32>) — struct containing approvers: Vec<Address> and created_at: u64

New Functions

  • set_admin_quorum(admin, new_admins) — sets the multi-sig admin list (min 2 admins, original admin must be included)
  • approve_action(admin, action_hash) — records an admin's approval
  • revoke_approval(admin, action_hash) — removes a previously-given approval
  • execute_approved(caller, action_hash, action_type, target) — executes if approvals ≥ ceil(N/2); action_type: 1=pause, 2=unpause, 3=emergency_withdraw, 4=remove_member
  • remove_member(admin, member) — new function for member removal (single-sig fallback)

New View Functions

  • get_admin_quorum() — returns current quorum member list
  • get_approvals(action_hash) — returns list of admins who approved
  • get_approval_count(action_hash) — returns number of approvals
  • get_action_time(action_hash) — returns creation timestamp for expiry check

Modified Functions

  • pause, unpause, emergency_withdraw — now check for quorum; blocked with clear error if multi-sig is active
  • All existing functionality preserved when no quorum is configured (backward compatible)

Security Properties

  • Simple majority threshold: ceil(N/2) approvals required
  • 48-hour expiry on pending actions
  • Double-approval prevention
  • Only quorum members can approve
  • Original admin must be included in any quorum

Test Coverage

46 new unit tests across all three contracts:

Rotational (19 new tests)

  • test_set_admin_quorum, test_set_quorum_unauthorized, test_set_quorum_too_few, test_set_quorum_admin_not_included
  • test_approve_action_and_count, test_double_approval_rejected, test_revoke_approval, test_revoke_nonexistent_rejected
  • test_execute_pause_via_multisig_2_of_3, test_single_admin_cannot_execute_with_quorum
  • test_pause_directly_rejected_when_quorum_set, test_pause_directly_works_without_quorum
  • test_emergency_withdraw_rejected_when_quorum_set, test_execute_emergency_withdraw_via_multisig
  • test_execute_remove_member_via_multisig
  • test_action_expires_after_48_hours, test_non_quorum_member_cannot_approve, test_approve_without_quorum_rejected

Flexible (6 new tests)

  • test_set_quorum_and_pause_via_multisig, test_pause_directly_rejected_when_quorum_set, test_pause_directly_works_without_quorum
  • test_execute_emergency_withdraw_via_multisig, test_execute_remove_member_via_multisig
  • test_single_admin_cannot_execute, test_action_expires

Target (6 new tests)

  • Same coverage pattern as Flexible

All 66 existing + new tests pass (Factory: 4, Rotational: 30, Target: 16, Flexible: 16)

Frontend Changes

New Components

AdminQuorumManager (frontend/components/group/admin-quorum-manager.tsx)

  • Displays current quorum members with Stellar addresses
  • Shows multi-sig status badge and threshold info
  • Inline edit form for updating quorum (admin-only)
  • Validates minimum 2 admins, original admin inclusion
  • Loading states and error handling

PendingActionCard (frontend/components/group/pending-action-card.tsx)

  • Shows action type with contextual icon (pause, unpause, emergency withdraw, remove member)
  • Approval progress bar with count display (e.g., "2 / 3 (threshold: 2)")
  • Lists approved admins with "You" badge for current user
  • Expiry countdown with auto-expiration detection (48h)
  • Approve / Revoke / Execute buttons with loading states
  • Real-time refresh after state changes

New Hooks (useJointSaveContracts.ts)

  • useSetAdminQuorum(contractId) — set quorum transaction
  • useApproveAction(contractId) — approve transaction
  • useRevokeApproval(contractId) — revoke transaction
  • useExecuteApproved(contractId) — execute transaction (with action_type + target)
  • fetchAdminQuorum(contractId) — read quorum list
  • fetchApprovalCount(contractId, actionHashHex) — read approval count
  • fetchActionTime(contractId, actionHashHex) — read creation timestamp
  • fetchApprovals(contractId, actionHashHex) — read approver list
  • bytesN32Val(hex) helper for BytesN<32> SCVal encoding

Integration

  • AdminQuorumManager embedded in GroupActions admin section (appears on every group detail page)
  • PendingActionCard exported for use in custom multi-sig approval flows

Acceptance Criteria Met

  • Setting a quorum disables single-signer execution for emergency_withdraw, pause/unpause, and remove_member
  • Without a quorum configured, all actions work exactly as before (backward compatible)
  • execute_approved only succeeds when the threshold is met
  • Pending actions expire after 48 hours and cannot be executed
  • Frontend AdminQuorumManager renders correctly
  • Frontend correctly shows approval progress
  • No existing functionality breaks — full deposit/withdraw/pause flow verified

Files Changed

  • smartcontract/contracts/rotational/src/lib.rs — +275 lines
  • smartcontract/contracts/rotational/src/tests.rs — +860 lines
  • smartcontract/contracts/flexible/src/lib.rs — +277 lines
  • smartcontract/contracts/flexible/src/tests.rs — +358 lines
  • smartcontract/contracts/target/src/lib.rs — +277 lines
  • smartcontract/contracts/target/src/tests.rs — +278 lines
  • smartcontract/.gitignore — +3 lines (ignores test_snapshots/)
  • frontend/hooks/useJointSaveContracts.ts — +197 lines
  • frontend/components/group/group-actions.tsx — +8 lines (integration)
  • frontend/components/group/admin-quorum-manager.tsx — new file (223 lines)
  • frontend/components/group/pending-action-card.tsx — new file (290 lines)

Add threshold-based multi-sig approval mechanism to all three pool
contracts (Rotational, Target, Flexible) for emergency_withdraw,
pause/unpause, and remove_member actions. When a quorum is configured,
single-signer execution is blocked and requires majority approval
via the new approve_action → execute_approved flow.

Smart Contract Changes:
- Add PendingAction struct and AdminQuorum storage to all three contracts
- Add set_admin_quorum, approve_action, revoke_approval, execute_approved
- Add remove_member function to all three pool contracts
- Add get_admin_quorum, get_approvals, get_approval_count, get_action_time views
- Simple majority (ceil(N/2)) required for execution
- 48-hour expiry on pending actions
- Backward compatible: pools without a quorum retain single-sig behavior

Tests:
- 46 new unit tests across all three contracts (30 rotational, 8 flexible,
  8 target) covering: quorum setup, approval counting, double-approval
  rejection, revocation, threshold enforcement, expiry, unauthorized
  access, and full end-to-end multi-sig execution flows

Frontend:
- New AdminQuorumManager component for viewing/editing quorum members
- New PendingActionCard component showing approval progress, expiry,
  and approve/revoke/execute buttons
- New multi-sig hooks: useSetAdminQuorum, useApproveAction,
  useRevokeApproval, useExecuteApproved
- New read helpers: fetchAdminQuorum, fetchApprovalCount,
  fetchActionTime, fetchApprovals
- AdminQuorumManager integrated into GroupActions admin section

Closes JointSave-org#181

🤖 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.

[Feature] Implement multi-sig admin approval for high-risk pool actions (emergency_withdraw, pause, remove_member)

1 participant