Skip to content

M-of-N threshold controller so no single key can rewrite a split #349

Description

@grantfox-oss

Difficulty: Expert. Scope: multi-week epic. Contract + SDK + dashboard. Security-critical.

Problem

A split's controller is a single Option<Address>:

pub struct Split {
    pub recipients: Vec<Recipient>,
    pub shares: Vec<u32>,
    pub controller: Option<Address>,
}

That single address can unilaterally rewrite recipients and shares (update_split) and hand off or lock control (transfer_control). For a shared arrangement (a DAO treasury split, a band's royalty split, a co-founder split) that is exactly the wrong trust model: any one keyholder can redirect everyone else's money, and if that key is lost or compromised the split is either frozen or hijacked. The single-key redirect risk is also what makes the escrow-redirection issue (#253) sharp.

Proposal

Allow a split's controller to be an M-of-N policy: a set of signer addresses and a threshold. Controller actions (update_split, transfer_control, and any future controller-gated action) require at least M of the N to authorize.

Why this is hard

  • The clean design leverages Soroban's account abstraction: a controller can already be any address, including a custom account contract that implements __check_auth with M-of-N logic. The hard, valuable deliverable is deciding between (a) requiring users to deploy a separate multisig account contract and just documenting it, versus (b) building threshold policy into the splitter itself, and justifying the choice. Each has real tradeoffs in composability, storage, and auth-context handling.
  • If built in: representing a pending multi-party action (propose/approve/execute), preventing replay, handling signer set changes, and doing it all within Soroban's auth model and resource limits.
  • require_auth semantics for a multi-address threshold are subtle; get the auth-context handling right or you get either footguns or unauthorized execution.
  • Backward compatibility: existing single-address controllers must keep working unchanged.

Deliverables

  • Design RFC that picks an approach (account-contract vs built-in) with justification.
  • Implementation of the chosen approach, with signer-set management if built-in.
  • SDK support for constructing and authorizing threshold actions.
  • Dashboard: create a threshold-controlled split and collect approvals.
  • Adversarial tests: below-threshold rejection, replay, signer removal mid-flight.

Acceptance criteria

  1. Maintainer-approved RFC with the approach decision justified before implementation.
  2. Controller actions require M-of-N; below-threshold attempts are rejected, proven by test.
  3. Existing single-address controllers remain fully backward compatible.
  4. Signer-set changes (if in scope) cannot be used to bypass the threshold.
  5. Interaction with transfer_control and the two-step transfer (Make transfer_control two-step so control cannot be lost to a mistyped address #254) is defined and tested.

Related

Directly mitigates #253 (single controller can redirect escrow). Should inform the upgrade-authority model in the upgradeability epic.

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial Campaign | FWC26Campaign: Official Campaign | FWC26enhancementNew feature or requesthelp wantedExtra attention is neededrustPull requests that update rust codesecurityFunds safety and hardening

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions