Skip to content

Solizardking/percolator-meta

 
 

Repository files navigation

Percolator Meta

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.

Premise

  • 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.

Modules

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.

Lifecycle

  1. 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.
  2. Votegenesis-vote reads 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.
  3. 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 shrinks outstanding, recomputing quorum against whoever stays — those who stay decide. This makes leaving the depositor's veto on a capture attempt.
  4. Trigger (permissionless) — the first proposal to clear quorum + weighted majority is sealed into distribution by CPI. No mint.
  5. Claim / burn — winning recipients claim their entry from the fixed COIN vault; unclaimed is burned.
  6. 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.
  7. 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 calls execute: 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 then claim their USD.

Authority chain & the 1-week timelock

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."

Market allow-list (residual-distributor)

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 & test

# 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_burn

Tests 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.

License

Apache License 2.0. Provided "as is", educational use only — see the disclaimer above.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages