Getting Started
- Fork the repository: https://github.com/JointSave-org/Joint_Save
- Clone your fork:
git clone https://github.com/<your-username>/Joint_Save.git
cd Joint_Save
- Create a new branch:
git checkout -b feat/multisig-admin-controls
Overview
All three pool contracts (Rotational, Target, Flexible) currently require only a single admin signature to execute high-risk actions: emergency_withdraw, pause/unpause, and remove_member. If an admin key is compromised or an admin acts maliciously, there is no check against draining or disrupting a pool holding real funds. The emergency pause infrastructure was added in #168, but it still relies on single-signer trust.
This issue adds a threshold-based multi-sig approval mechanism to these critical actions across all pool contracts, and builds the corresponding frontend UI for managing multi-sig admins and approving pending actions.
Requirements
Smart Contract Changes (all three pool contracts)
- Add a new storage key
admin_quorum storing the set of designated multi-sig admins as a Vec<Address>
- Add a new storage key
pending_approvals mapping a proposed action hash (Bytes) to the list of admins who have approved it
- Add new functions:
set_admin_quorum(admin, new_admins: Vec<Address>) — only callable by the current admin; sets the list of N admins
approve_action(admin, action_hash: Bytes) — records an admin's approval for a specific pending action
revoke_approval(admin, action_hash: Bytes) — removes an admin's approval before execution
execute_approved(action_hash: Bytes, action_data: Vec<u8>) — only succeeds if approvals count >= ceil(N/2) (simple majority), executes the action, then clears the pending record
- Modify
emergency_withdraw, pause/unpause, and remove_member to be callable only via execute_approved when a quorum is configured (i.e., when admin_quorum length > 0); keep single-signer fallback when no quorum is set (for backward compatibility with existing single-admin pools)
- Add view functions:
get_admin_quorum(), get_pending_action(action_hash), get_approval_count(action_hash)
Frontend Changes
- New component:
AdminQuorumManager on the group detail page (admin-only section)
- Display current quorum members with their Stellar addresses
- Form to add/remove quorum members (subject to the contract's
set_admin_quorum)
- Show pending actions awaiting approval with an "Approve" button
- Display approval progress (e.g., "2 of 3 approvals received")
- New component:
PendingActionCard showing each pending multi-sig action with:
- Action type and parameters (decoded from action_data)
- List of admins who have approved/revoked
- Expiry mechanism (pending actions older than 48 hours are automatically expired)
- Update existing admin action buttons (
emergency_withdraw, pause, remove_member) to submit through the multi-sig flow when quorum is configured
Testing
- Unit tests for the new contract functions (approval counting, quorum threshold, backward compatibility)
- Integration test: create a pool with 3 admins, set quorum to 2, verify that single admin cannot execute; verify that 2-of-3 approval succeeds
- Frontend tests for
AdminQuorumManager component rendering and interaction
Acceptance Criteria
Getting Started
Overview
All three pool contracts (Rotational, Target, Flexible) currently require only a single admin signature to execute high-risk actions:
emergency_withdraw,pause/unpause, andremove_member. If an admin key is compromised or an admin acts maliciously, there is no check against draining or disrupting a pool holding real funds. The emergency pause infrastructure was added in #168, but it still relies on single-signer trust.This issue adds a threshold-based multi-sig approval mechanism to these critical actions across all pool contracts, and builds the corresponding frontend UI for managing multi-sig admins and approving pending actions.
Requirements
Smart Contract Changes (all three pool contracts)
admin_quorumstoring the set of designated multi-sig admins as aVec<Address>pending_approvalsmapping a proposed action hash (Bytes) to the list of admins who have approved itset_admin_quorum(admin, new_admins: Vec<Address>)— only callable by the current admin; sets the list of N adminsapprove_action(admin, action_hash: Bytes)— records an admin's approval for a specific pending actionrevoke_approval(admin, action_hash: Bytes)— removes an admin's approval before executionexecute_approved(action_hash: Bytes, action_data: Vec<u8>)— only succeeds if approvals count >= ceil(N/2) (simple majority), executes the action, then clears the pending recordemergency_withdraw,pause/unpause, andremove_memberto be callable only viaexecute_approvedwhen a quorum is configured (i.e., when admin_quorum length > 0); keep single-signer fallback when no quorum is set (for backward compatibility with existing single-admin pools)get_admin_quorum(),get_pending_action(action_hash),get_approval_count(action_hash)Frontend Changes
AdminQuorumManageron the group detail page (admin-only section)set_admin_quorum)PendingActionCardshowing each pending multi-sig action with:emergency_withdraw,pause,remove_member) to submit through the multi-sig flow when quorum is configuredTesting
AdminQuorumManagercomponent rendering and interactionAcceptance Criteria
emergency_withdraw,pause/unpause, andremove_memberexecute_approvedonly succeeds when the threshold is metAdminQuorumManagerrenders correctly for pools with and without a quorum