feat: implement multi-sig admin approval for high-risk pool actions - #251
Open
olaleyeolajide81-sketch wants to merge 3 commits into
Open
Conversation
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>
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
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
AdminQuorum—Vec<Address>storing the set of designated multi-sig adminsPendingAction(BytesN<32>)— struct containingapprovers: Vec<Address>andcreated_at: u64New 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 approvalrevoke_approval(admin, action_hash)— removes a previously-given approvalexecute_approved(caller, action_hash, action_type, target)— executes if approvals ≥ ceil(N/2); action_type: 1=pause, 2=unpause, 3=emergency_withdraw, 4=remove_memberremove_member(admin, member)— new function for member removal (single-sig fallback)New View Functions
get_admin_quorum()— returns current quorum member listget_approvals(action_hash)— returns list of admins who approvedget_approval_count(action_hash)— returns number of approvalsget_action_time(action_hash)— returns creation timestamp for expiry checkModified Functions
pause,unpause,emergency_withdraw— now check for quorum; blocked with clear error if multi-sig is activeSecurity Properties
ceil(N/2)approvals requiredTest 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_includedtest_approve_action_and_count,test_double_approval_rejected,test_revoke_approval,test_revoke_nonexistent_rejectedtest_execute_pause_via_multisig_2_of_3,test_single_admin_cannot_execute_with_quorumtest_pause_directly_rejected_when_quorum_set,test_pause_directly_works_without_quorumtest_emergency_withdraw_rejected_when_quorum_set,test_execute_emergency_withdraw_via_multisigtest_execute_remove_member_via_multisigtest_action_expires_after_48_hours,test_non_quorum_member_cannot_approve,test_approve_without_quorum_rejectedFlexible (6 new tests)
test_set_quorum_and_pause_via_multisig,test_pause_directly_rejected_when_quorum_set,test_pause_directly_works_without_quorumtest_execute_emergency_withdraw_via_multisig,test_execute_remove_member_via_multisigtest_single_admin_cannot_execute,test_action_expiresTarget (6 new tests)
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)PendingActionCard(frontend/components/group/pending-action-card.tsx)New Hooks (
useJointSaveContracts.ts)useSetAdminQuorum(contractId)— set quorum transactionuseApproveAction(contractId)— approve transactionuseRevokeApproval(contractId)— revoke transactionuseExecuteApproved(contractId)— execute transaction (with action_type + target)fetchAdminQuorum(contractId)— read quorum listfetchApprovalCount(contractId, actionHashHex)— read approval countfetchActionTime(contractId, actionHashHex)— read creation timestampfetchApprovals(contractId, actionHashHex)— read approver listbytesN32Val(hex)helper for BytesN<32> SCVal encodingIntegration
AdminQuorumManagerembedded inGroupActionsadmin section (appears on every group detail page)PendingActionCardexported for use in custom multi-sig approval flowsAcceptance Criteria Met
emergency_withdraw,pause/unpause, andremove_memberexecute_approvedonly succeeds when the threshold is metAdminQuorumManagerrenders correctlyFiles Changed
smartcontract/contracts/rotational/src/lib.rs— +275 linessmartcontract/contracts/rotational/src/tests.rs— +860 linessmartcontract/contracts/flexible/src/lib.rs— +277 linessmartcontract/contracts/flexible/src/tests.rs— +358 linessmartcontract/contracts/target/src/lib.rs— +277 linessmartcontract/contracts/target/src/tests.rs— +278 linessmartcontract/.gitignore— +3 lines (ignores test_snapshots/)frontend/hooks/useJointSaveContracts.ts— +197 linesfrontend/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)