All articles
solanametadaofutarchygovernancedefi

MetaDAO: how futarchy on Solana actually works (three programs, two markets, one TWAP)

MetaDAO runs Solana governance through prediction markets. Three programs, conditional tokens, dual AMMs, TWAP settlement — the technical reference.

Most DAOs vote with tokens. MetaDAO bets with them. It's the only production-grade implementation of futarchy — Robin Hanson's "vote on values, bet on beliefs" mechanism — and it runs on Solana as three cooperating open-source programs.

Per proposal: spin up two conditional markets, let traders price the protocol's expected metric under each outcome, take the time-weighted average, and execute whichever side's market is priced higher. The proposal's executable Solana instruction fires automatically. No token-weighted vote, no quorum gymnastics.

This is the technical reference for how that's wired.

The three programs

MetaDAO is metaDAOproject/programs — Anchor-style Rust programs:

  • autocrat — orchestrates futarchy. Anyone creates a proposal containing an executable SVM instruction. Autocrat owns the lifecycle: spin up conditional vaults & markets, monitor, finalise or revert.
  • conditional_vault — mints the conditional tokens (pass and fail) against a deposit of the underlying asset. Owns settlement: redeem to the winning side after autocrat reports which side won.
  • amm — a constant-product AMM (Uniswap-V2-shape) with a hardened on-chain TWAP oracle. Two AMM instances per proposal — one for the pass market, one for the fail market.

The conditional vault

Per proposal, autocrat creates two vaults: one for the governance token (META) and one for the quote token (USDC). Each vault accepts deposits and mints two conditional tokens 1:1:1:

text
deposit 10 USDC →
  + 10 USDC-on-pass    (redeemable for USDC iff vault finalises)
  + 10 USDC-on-fail    (redeemable for USDC iff vault reverts)

Both tokens are real SPL mints. Both are fully transferable. One of them will eventually be worth the underlying; the other will be worth zero.

rust
// Sketch of the deposit instruction's effects, per metaDAOproject/programs
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
    // 1. Pull underlying into the vault's escrow ATA
    token::transfer(ctx.accounts.transfer_underlying_to_vault(), amount)?;

    // 2. Mint amount of pass-conditional + amount of fail-conditional
    //    to the user, both authorised by the vault PDA
    token::mint_to(ctx.accounts.mint_pass_conditional(),  amount)?;
    token::mint_to(ctx.accounts.mint_fail_conditional(),  amount)?;

    Ok(())
}

The two markets

Once both vaults exist, autocrat opens two AMM pools — one per conditional outcome:

  • Pass market: META-on-pass / USDC-on-pass
  • Fail market: META-on-fail / USDC-on-fail

Traders take a position by depositing into the vault to mint the conditional pair, then trading one leg on the relevant market. Example flow for a trader who believes META is worth $112 if the proposal passes and $105 if it fails:

text
1. Deposit 1,000 USDC into the USDC vault
   → 1,000 USDC-on-pass + 1,000 USDC-on-fail
2. Deposit 10 META into the META vault
   → 10 META-on-pass + 10 META-on-fail
3. On the pass-market AMM:
   → swap USDC-on-pass for META-on-pass at the current $112 price
4. On the fail-market AMM:
   → swap META-on-fail for USDC-on-fail at the current $105 price
5. Wait for proposal finalisation

After finalisation, the conditional tokens of the winning side redeem 1:1 for the underlying. The losing side's tokens evaporate. The trader's realised PnL is the spread between their conditional fills and the eventual outcome.

The TWAP oracle

The AMM exposes a time-weighted average price oracle modelled after Uniswap V2's, with extra manipulation guards (the original V2 oracle was famously cheap to skew on low-liquidity pairs). On each swap the AMM accumulates price × Δtime; the TWAP for a window is the difference of two accumulators divided by the window duration.

text
// Approximate read pattern (off-chain client)
const cumulNow   = await readAmmAccumulator(passMarket)        // accumulator + ts
const cumulStart = await readAmmAccumulator(passMarket, atSlot)  // at proposal open

const twapPass = (cumulNow.value - cumulStart.value) / (cumulNow.ts - cumulStart.ts)
const twapFail = /* same on the fail market */

// Whichever is higher wins:
const passes = twapPass > twapFail

Autocrat reads both TWAPs on finalisation, sets the winning vault's settlement authority to Finalised and the loser's to Reverted. The conditional tokens of each vault now have a fixed payoff.

Proposals and execution

A proposal is a Solana instruction wrapped in metadata. The instruction is anything you could put in a regular Solana transaction — a treasury transfer, a program upgrade, a fee parameter change, a vote in another DAO. Autocrat stores it; the market decides whether it runs.

typescript
// Conceptual shape (the real type comes from @metadaoproject/futarchy-sdk)
type Proposal = {
  number: u64
  descriptionUrl: string         // IPFS, Arweave, or HTTPS markdown
  instruction: {
    programId: Pubkey
    accounts:  { pubkey: Pubkey; isSigner: boolean; isWritable: boolean }[]
    data:      Uint8Array
  }
  // Created at the same time, owned by the proposal:
  passMarket:        Pubkey      // AMM
  failMarket:        Pubkey      // AMM
  baseConditional:   { passMint: Pubkey, failMint: Pubkey, vault: Pubkey }
  quoteConditional:  { passMint: Pubkey, failMint: Pubkey, vault: Pubkey }
  slotEnacted:       Option<Slot>
}

When the proposal's market window expires and pass wins, anyone can call autocrat's execute to invoke the wrapped instruction with autocrat as the signer authority. The DAO's decision is also the on-chain action.

SDK usage

Most app developers don't talk to the programs directly — they use the TypeScript SDK at metaDAOproject/futarchy-sdk:

sh
pnpm install @metadaoproject/futarchy-sdk
typescript
import { FutarchyClient } from "@metadaoproject/futarchy-sdk"
import { Connection } from "@solana/web3.js"

const conn = new Connection("https://api.mainnet-beta.solana.com")
const client = new FutarchyClient(conn, wallet)

// List active proposals for a DAO:
const proposals = await client.daos.fetchProposals(daoAddress, { status: "pending" })

// Read live TWAPs for a proposal:
const twap = await client.proposals.fetchTwap(proposalAddress)
console.log("pass twap:", twap.pass, "fail twap:", twap.fail)

// Mint conditional tokens by depositing into a vault:
await client.vaults.deposit(quoteVault, BigInt(1_000_000_000)) // 1,000 USDC (6 decimals)

Local development

Spinning up the full futarchy stack against a localsolana-test-validator is fiddly because three programs need to be present with matching IDs. The community helper jshiohaha/local-futarchy scripts the setup — clones autocrat, conditional_vault, and amm at the right versions and loads them into a fresh validator.

Why builders should care

Three concrete reasons MetaDAO's primitives matter beyond the governance use case:

  1. Conditional tokens are a general primitive. Any time you need to express "A pays out iff X, B pays out iff not-X", the conditional vault is the right tool. Useful for insurance, derivatives, options, settlement disputes.
  2. The TWAP AMM is reusable. The hardened Uniswap-V2-shape TWAP oracle is a clean dependency for any Solana protocol that needs manipulation-resistant price feeds without an off-chain oracle.
  3. Token launches as decisions. Several Solana projects in 2024-2026 launched via MetaDAO — letting the market decide whether to issue the token, rather than the team announcing it. A pattern that turns "should we launch?" into a tradeable question.

What it doesn't do

  • It doesn't enforce a one-tx execution. Autocrat's wrapped instruction is one Solana instruction. For multi-step changes you need a proxy program or a wrapper contract that the single instruction calls into via CPI.
  • It doesn't fix uninformed markets. If nobody trades, the TWAP is meaningless and the proposal's outcome reflects no real information. Liquidity bootstrapping per proposal is a non-trivial UX problem MetaDAO has spent real effort on.
  • It doesn't generalise to off-chain decisions. The framework decides "should this on-chain instruction execute?" — not "should we hire this person?". Off-chain decisions still need traditional voting layered on top.

References

Futarchy is one of the oldest unexplored mechanism-design ideas in crypto. MetaDAO is the first time it's actually shipped at production scale on a real chain. The conditional-vault primitive and the hardened TWAP AMM are both worth reading even if you never intend to run a proposal through them.

MetaDAO: how futarchy on Solana actually works (three programs, two markets, one TWAP) | devrels.xyz