What a throttle is, and why it is not a quorum
Most DAO design attention goes to how votes are counted — quorum and threshold design, token weighting, quadratic schemes. A throttle acts one stage earlier: it decides which proposals get to exist. Quorum rules answer "did enough weight participate?"; throttles answer "may this proposal be put in front of anyone at all?"
The distinction matters because the two failure modes are different. A badly-set quorum produces the wrong outcome. A missing throttle produces no outcome at all: an open proposal queue is a channel any address can write to, and a governance system whose voters are exhausted has effectively lost quorum without ever changing the number. The proposal lifecycle describes the stages a proposal passes through; this page covers the gates on the entrance.
Four costs are being rationed, and a given mechanism usually targets one of them:
- Attention — voters and delegates can only read so much. This is the cost holographic consensus attacks by making prediction markets triage the queue.
- Gas and settlement work — someone has to pay to conclude every proposal, whether or not it passes.
- Storage — proposal metadata is written to a substate or contract that later operations must traverse.
- Legitimacy — a queue full of unserious proposals makes the serious ones harder to see, and makes low turnout look normal.
Sponsor thresholds: who may open a proposal
The oldest throttle is a floor on the proposer. Compound's Governor Bravo — the template most token-weighted DAOs inherited — gates propose() on comp.getPriorVotes(msg.sender, block.number - 1) > proposalThreshold, measured one block back so the threshold cannot be met with a flash loan taken in the same block. The threshold is itself bounded: governance may set it anywhere between MIN_PROPOSAL_THRESHOLD of 1,000 COMP and MAX_PROPOSAL_THRESHOLD of 100,000 COMP, so no vote can raise the drawbridge past a hard ceiling or lower it to zero.
Bravo also ships the exemption that every threshold eventually needs. isWhitelisted(account) returns true while whitelistAccountExpirations[account] > block.timestamp, letting governance grant a named address time-limited permission to propose below the threshold — the standard remedy for the case where the people best placed to write proposals are not the people holding the most tokens. See voting power activation and delegation thresholds for how that floor interacts with delegation.
The Moloch lineage draws the line at membership rather than magnitude. In Moloch v2 any address can submit a proposal, but it sits inert until a member sponsors it into the voting queue — submitProposal and sponsorProposal are separate functions, the second carrying an onlyDelegate modifier, and the proposal struct records the sponsor's address alongside a sponsored flag. The queue is member-curated by construction. Baal, the v3 rewrite, makes the same idea numeric: sponsorThreshold is documented as a "minimum number of shares to sponsor a proposal (not %)", and a submitter above it self-sponsors, skipping the queue and starting its own voting clock in the same transaction.
Off-chain governance reaches the same design by social means. Long COVID Labs' own governance framework, LCL DP-1, requires a proposal to spend four days in the DAO's public Telegram and collect at least ten 👍 reactions including at least one from a named core-team member before it may go to a binding Snapshot vote. That is a sponsor threshold with a human quorum and a core-team veto, implemented entirely in emoji.
Deposits, offerings, and who is really being charged
A price on proposing is the throttle most often reached for and most often mis-specified, because two different things get called the same thing.
A refundable deposit prices bad faith, not proposing. Moloch v2 holds a proposalDeposit — the deployed default was 10 ETH, roughly $1,000 at the time — and returns it when the proposal is processed. What it does not return is the processingReward (default 0.1 ETH), which _returnDeposit pays out of escrow to whoever calls the processing function, with the remainder going back to the sponsor. The contract enforces the relationship at construction: require(_proposalDeposit >= _processingReward). The deposit exists to fund the conclusion of the proposal, and only the leftover is a returnable bond.
A non-refundable offering prices access. Baal's proposalOffering is charged only to submitters below the sponsor threshold — the code comments call it an "Optional anti-spam gas token tribute" — so members propose free and outsiders pay. That is a deliberate two-tier entrance, and worth naming as such: a fee framed as anti-spam is frequently a membership boundary wearing a price tag.
The distinction has a practical test. Ask what the money is for. If it funds the work of concluding the proposal, it is a settlement pre-payment and it should be sized to that work. If it is returned on good behaviour, it is a bond and should be sized to the harm. If it is neither returned nor spent on the proposal, it is a toll, and the honest question is who it is meant to keep out.
Concurrency, size, and expiry caps
Thresholds bound who; the rest of the throttle family bounds how much.
One proposal at a time. Governor Bravo enforces a per-proposer concurrency cap of exactly one, and does it twice — propose() reverts with "one live proposal per proposer" if the caller's latest proposal is in either the Active or the Pending state. Checking both matters: a cap that only looked at Active could be defeated by queueing proposals during the voting delay.
A cap on the whole queue. A per-proposer limit does nothing against many proposers, so systems that automate proposal creation tend to add a global one. DAOhaus's agent runbook, AGENT_TASKS.md, instructs an autonomous member to open no new proposal while three are already in voting — a queue-depth cap chosen because the constraint being protected is human review capacity, not chain capacity. The same document tells the agent to read process-readiness from the contract's own state(id) rather than an indexer's flag, which is the operational half of the same discipline.
Payload caps. Bravo sets proposalMaxOperations = 10, bounding how many actions one vote can authorize — a limit on blast radius as much as on cost, and a close relative of typed versus arbitrary execution. Baal takes the storage-side route and persists only hashOperation(proposalData), keeping the payload off-chain entirely and the hash as the commitment.
Expiry. Baal proposals carry an expiration field, required to be either zero or later than block.timestamp + votingPeriod + gracePeriod, so a proposal can be written to die rather than linger. An expiring queue is self-cleaning; a permanent one accumulates.
Throttles that reach backwards
The subtle members of the family apply after a proposal is already live, and they exist because eligibility can change mid-flight.
Governor Bravo lets anyone cancel a live proposal once its proposer's voting power has fallen below proposalThreshold — for a whitelisted proposer, only the whitelistGuardian may do it. The effect is that the threshold is a continuing requirement, not an entry test: a proposer who borrows or is delegated enough weight to propose and then gives it up loses the proposal too.
Moloch's jailed field is the membership analogue. A member with a passing guild-kick proposal against them is barred from both voting and sponsoring, and several code paths refuse to act on a jailed applicant at all — the throttle prevents a member on the way out from filling the queue on the way.
Baal's minRetentionPercent is the most interesting of the three because it throttles on the voters' behaviour rather than the proposer's: a proposal auto-fails if more than (1 − minRetentionPercent) of total shares exit before it is processed. It is a rate limit on governing a membership that is leaving, and a structural answer to the ragequit-then-execute problem that governance timelocks address from the other end.
The trade-off nobody escapes
Every throttle listed here works, and every one of them raises the floor on who can participate. A 100,000 COMP proposal threshold makes spam impossible and makes independent proposing the preserve of large holders and whitelist grantees. A member-sponsorship gate keeps the queue serious and makes the member set the gatekeeper of what the DAO is allowed to consider. A non-refundable offering deters drive-by proposals and charges exactly the people who are not yet inside.
Two rules of thumb survive contact with the implementations above. First, price the work, not the person: a charge sized to the cost of concluding a proposal is defensible at any wealth level, while a charge sized to deter is a wealth test by construction. Second, cap the queue, not the proposer, where you can — a depth cap on proposals in voting protects reviewer attention without asking who wrote them, whereas a per-proposer cap is trivially defeated by using two addresses.
The honest reading of the record is that most DAOs adopt throttles reactively, after a queue fills or a treasury is griefed, and inherit whichever numbers their framework shipped with. The parameters are rarely revisited even as the token distribution that made them reasonable changes underneath them.
How Caper approaches this
A caper carries four throttles, and the interesting one is a fee that is explicitly not an anti-spam price.
Opening a proposal requires an exact XRD payment equal to the caper's proposal_fee, 500 XRD by default — exact, so an over-payment aborts rather than tipping the treasury — and there is no refund path: the payment is banked by the caper it was proposed to. The fee has a floor written into the fee-setting function itself, proposal_fee >= SETTLEMENT_GAS_BUDGET, with the reason stated in the source: so that "the permissionless settle path can never draw more treasury than the proposal itself banked." That is Moloch's require(_proposalDeposit >= _processingReward) invariant reached independently — a proposal must pre-fund the work of concluding it — and it means the fee's size is derived from settlement cost rather than chosen to deter.
The proposer must also hold at least one of the caper's own tokens, checked as a proof at creation, which is a sponsor threshold set to the minimum non-zero value: membership, not magnitude. Metadata is capped at 512 bytes of title and 16,384 of description, and the source names the reason plainly — unbounded, the meta blob "is a free griefing lever on every write that touches its substate."
The fourth is a throttle deliberately left off. A caper sets no cap on the number of voters in a proposal, because settlement is chunked across transactions rather than iterating every ballot in one, so a large turnout cannot brick the settle path. It is worth stating as its own point: several throttles in this family exist only because concluding a proposal is a single unbounded loop, and making that loop resumable removes the need for the limit rather than tuning it.