Skip to content

Permissions & Threshold ​

Each member of a smart account holds a permission mask — any combination of three independent bits — and the account has a threshold that governs voting.

The three permissions ​

Solace::SquadsSmartAccounts::Permissions defines the bits:

ConstantBitGrants the ability to…
INITIATE0b001Create a transaction and open its proposal.
VOTE0b010Approve, reject, or cancel a proposal.
EXECUTE0b100Execute an approved transaction.
ALL0b111All three.

Build a mask from the constants or with Permissions.mask:

ruby
Solace::SquadsSmartAccounts::Permissions::ALL
Solace::SquadsSmartAccounts::Permissions::INITIATE | Solace::SquadsSmartAccounts::Permissions::VOTE
Solace::SquadsSmartAccounts::Permissions.mask(:vote, :execute)

A member is a SmartAccountSigner — a pubkey plus a mask:

ruby
Solace::SquadsSmartAccounts::SmartAccountSigner.new(
  pubkey:     member.address,
  permission: Solace::SquadsSmartAccounts::Permissions::VOTE
)

Permissions can be split across members — see the separation-of-duties pattern (one member initiates, another votes, another executes).

Invariants ​

The program enforces that every account always has at least one member with each of Initiate, Vote, and Execute. The threshold must be 1 ≤ threshold ≤ num_voters, where num_voters is the number of members holding the Vote permission.

The vote math ​

A proposal's outcome is decided by counting Vote-holders' votes against two cutoffs:

  • Approved when approved.length >= threshold.
  • Rejected when rejected.length >= cutoff, where cutoff = num_voters − threshold + 1.
  • Cancelled when cancelled.length >= threshold (cancellation applies to an already-Approved proposal).

A member can switch their vote: approving removes a prior rejection and vice-versa.

Worked examples:

Configurationnum_votersthresholdcutoff (to reject)
1-of-1111
2-of-3322
3-of-3331

In a 3-of-3, cutoff is 1 — a single rejection vetoes the proposal. In a 2-of-3, it takes two approvals to pass or two rejections to kill it, leaving room to switch votes.

See the async lifecycle for how these states drive execution.

Built on Solace