A non-custodial, Sybil-resistant governance bootstrap for Percolator markets. Depositors put capital at risk in a Percolator market's insurance to earn time-weighted voting power over how a fixed, pre-existing COIN supply is distributed. The winning distribution is the MetaDAO token; control of the market keys then transfers to it through a time-locked Squads handover. No program here ever custodies user funds or sits in the withdrawal path beyond a tightly-constrained, time-locked authority.
Status. Experimental, educational-use-only, provided AS IS with no warranties (see LICENSE). Participants put real capital at risk in a live market and can lose it to market losses.
- Depositing stakes capital to earn voting power. The cost of a vote is the capital put
at risk in the market's insurance — that real downside is what makes votes expensive to
Sybil. The genesis pool is share-based: on exit a depositor redeems shares at the live
insurance balance, recovering principal plus a pro-rata slice of any market surplus, and
pro-rata less under a loss. A deployer may instead configure a principal-only pool
(
POLICY_PRINCIPAL), where surplus is retained in insurance as the DAO's buy/burn fuel. Because surplus is distributable it is also winnable — a deliberate governance tradeoff: it gives participants an incentive to compete for a winning COIN distribution. - COIN is a fixed supply with no mint authority. Genesis does not mint — it allocates a pre-existing pool. No inflation, dilution, or mint-to-drain vector exists.
- The DAO cannot take a user's principal. User capital lives in Percolator insurance, never in a genesis-owned vault. The genesis programs do attribution/accounting only; the one path to unconstrained authority is a key rotation that runs through a 1-week Squads timelock, giving every depositor a pre-announced window to exit first.
How they fit: a depositor's stake is recorded by subledger; genesis-vote (or the alternative residual-distributor) reads that stake to decide a winner and seals it into distribution, which pays out the fixed COIN pool; post-mint, Squads rotates the market's insurance authority to twap-program, which buys and burns COIN from surplus. The two deciders are interchangeable behind the same distribution seam.
| Crate | Role |
|---|---|
subledger/ |
The market's asset-0 insurance operator during genesis (a role granted by Squads). Mediates deposits (signs Percolator TopUpInsurance as the insurance authority) and owner-authorized exits, tracking per-owner attribution (owner, principal, start_slot). Genesis pools are share-based (ERC4626-style): exiting redeems shares at the live balance, returning principal plus any surplus, pro-rata under loss. Never rotates keys — accept_operator only consents to receive the role Squads grants. Also provides reusable owner-bound pools for assets 1..N. |
genesis-vote/ |
The vote decider. Runs a log-time quorum vote weighted by each voter's subledger attribution (floor(log2(hold_time)) × principal), one voter → one proposal. Seals the winner into distribution by CPI. Holds no funds. |
residual-distributor/ |
The deterministic decider — a pluggable alternative to genesis-vote behind the same seam. Awards points across 4 cohorts (insurance/backing = subledger share value; LP/trader = Percolator residual counters) via self-service register → crystallize → freeze → claim. Requires a market allow-list (see below). |
distribution/ |
Holds the fixed COIN pool in a vault. A proposal is one on-chain account of up to ~10k (pubkey, amount) entries; the sealed winner's recipients claim permissionlessly, unclaimed is burned. Never mints. The authority (whichever decider PDA) is bound into the config seed, making it decider-pluggable. |
twap-program/ |
Deployable BPF for the authority chain and the post-mint uniform-price (Dutch) buy/burn auction. After the mint, Squads rotates the asset-0 insurance operator to its PDA; it then runs permissionless rounds that pull the burn-share of insurance surplus, clear a ranked, uncancellable bid book at one marginal price, and burn (or treasury-send) the bought COIN. Never reaches principal. |
twap/ |
Reference library for the buy/burn (schedule + bid book); only its overflow-safe rate comparator is reused on-chain. |
setup/ |
Host-side helper: init the fixed-supply 42M COIN mint and revoke the mint authority. |
- Deposit through the subledger (the insurance authority) into market-0 insurance; it signs the
Percolator top-up and records
owner, principal, start_slot(last-write-time, so topping up resets the vote clock). Stake is held as shares. - Vote —
genesis-votereads the attribution. Weight =floor(log2(hold_time)) × principal, resolved at vote time. Backing a different proposal requires retracting first. Quorum =total_voted_principal × 2 > outstanding; winner =support_weight × 2 > total_cast_weight. - Exit / veto (any time) — redeem shares through the subledger for principal + surplus (pro-rata
under loss). A live voter must retract first; the vote-lock blocks any withdraw not preceded by
a retract, so a voter exits via a single atomic
[retract, withdraw]transaction. Exiting shrinksoutstanding, recomputing quorum against whoever stays — those who stay decide. This makes leaving the depositor's veto on a capture attempt. - Trigger (permissionless) — the first proposal to clear quorum + weighted majority is sealed into
distributionby CPI. No mint. - Claim / burn — winning recipients claim their entry from the fixed COIN vault; unclaimed is burned.
- Handoff (post-mint) — control rotates
DAO → Squads (1-week timelock) → twap-program → Percolator; the insurance authority moves from the principal-safe subledger to the surplus-only twap-program. - Buy/burn (permissionless, repeating) — each round, anyone
place_bids (escrow COIN, offer it for USD at a limit rate; a flat anti-spam fee is burned per bid). Bids can't be yanked to spoof a pending execute — early they can only be evicted by a strictly-better bid. When the round's slots expire, anyone callsexecute: it pulls the burn-share (DAO-set, default 80%) of the current surplus, ratchets the retained share into the protected principal counter (so it compounds in insurance), clears the book at one marginal price (every winner pays the same; better bidders give less COIN, surplus refunded), and burns the bought COIN (or sends it to a DAO sink). Winners thenclaimtheir USD.
DAO → Squads (1/1, 1-week timelock) → {subledger | twap-program} → Percolator.
A program-created Squads v4 1/1 multisig holds the market's asset-0 asset_admin
and is the sole key-rotator. At genesis it grants the insurance operator role to the subledger; post-mint
it rotates it to the twap-program — both via UpdateAssetAuthority{asset_index:0}, and Percolator requires the
incoming key to co-sign (the powerless accept_operator hooks). Every power-expanding rotation passes through
the one-week timelock, in the clear, with the old constrained authority still live — which is the user-exit
backstop: it bounds the blast radius of any bug in genesis-vote/distribution/chain to "users get a one-week,
pre-announced exit window."
The LP/trader cohorts award points from Percolator portfolio counters that anyone who controls a market's
oracle can manufacture for free (stand up an auth-mark market, self-trade delta-neutral, push the mark →
arbitrary crystallized_loss/received for the price of fees). So a portfolio counts only if its market is
on an orchestrator-vetted allow-list of trusted-Pyth markets (market_group + up to 9 extras, bound at init).
Setup: the creator holds the markets' authority key locally, stands up and vets N Pyth markets, then transfers
that key to the PDA that rotates it to the DAO via the same 1-week Squads timelock — so listed markets can never
be repointed at an attacker oracle once points accrue. The allow-list bounds who can mint points at all, not
wash-farming among already-trusted markets; see residual-distributor/DESIGN.md and sim/ for that analysis.
# build the deployable BPF programs (each self-contained)
cargo build-sbf --manifest-path subledger/Cargo.toml
cargo build-sbf --manifest-path distribution/Cargo.toml
cargo build-sbf --manifest-path genesis-vote/Cargo.toml
cargo build-sbf --manifest-path residual-distributor/Cargo.toml
cargo build-sbf --manifest-path twap-program/Cargo.toml
# tests (RUST_MIN_STACK is needed for the deep nested-CPI e2e)
RUST_MIN_STACK=8388608 cargo test --manifest-path subledger/Cargo.toml
RUST_MIN_STACK=8388608 cargo test --manifest-path genesis-vote/Cargo.toml
cargo test --manifest-path distribution/Cargo.toml
RUST_MIN_STACK=8388608 cargo test --manifest-path twap-program/Cargo.toml
# whole lifecycle across all six real binaries in one litesvm instance —
# deposit -> vote -> distribute -> claim -> DAO/Squads handoff -> buy/burn auction:
RUST_MIN_STACK=8388608 cargo test --manifest-path twap-program/Cargo.toml \
--test chain e2e_full_genesis_to_buy_burnTests load the real binaries (Percolator at ../percolator-prog/target/deploy/percolator_prog.so,
real Squads v4 at program/tests/fixtures/squads_v4.so, plus the locally-built crates) — CPIs run against
the actual programs, not mocks. The e2e needs those .so files prebuilt and ../percolator-prog built.
Apache License 2.0. Provided "as is", educational use only — see the disclaimer above.