solana-metadao — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited solana-metadao (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
MetaDAO is the production futarchy implementation on Solana. Futarchy — coined by economist Robin Hanson in 2000 — replaces voting with markets: proposals are decided by which conditional token market predicts a higher token price. "Vote values, bet beliefs." Helius CEO @mert has called it a gem, should be 'kingmade' and listed it as a top priority for Solana's capital formation stack.
Two pillars built on the same primitives:
The primitive that makes this work is the conditional vault: deposit 1 META and mint 1 pPASS-META + 1 pFAIL-META. Both tokens trade on their own AMM. After the 3-day trading window, the TWAP oracle of the PASS market is compared to the FAIL market. If the PASS-quote price is at least 3% above the FAIL-quote price (or -3% for team-sponsored proposals), the proposal passes — only PASS holders redeem the underlying; FAIL holders' deposits revert to spot. If it fails, vice versa.
Why this matters for capital formation: the same vault that holds the treasury also gates every withdrawal behind a market. There is no key a founder can lose, no rug a founder can pull, no governance attack via vote buying — to bend the DAO you have to put real capital on a wrong price, and any informed trader can take the other side. See references/futarchy-explainer.md for the full mental model.Not for: generic Solana governance (use Realms / SPL Governance), binary prediction markets on tail-asset events (use the solana-binary-markets skill — Drift BET / DFlow / Hxro), or vanilla token launches (use solana-token-launch).
Verified against mainnet on 2026-05-21. The official SDK was historically published as @metadaoproject/futarchy-sdk but that package was archived May 2025. The current active SDK lives in the metaDAOproject/programs monorepo and is published as @metadaoproject/programs (currently 0.1.0-alpha.2, the canonical client for v0.5/v0.6/v0.7 programs).
{
"dependencies": {
"@metadaoproject/programs": "0.1.0-alpha.2",
"@coral-xyz/anchor": "0.29.0",
"@solana/web3.js": "1.98.0",
"@solana/spl-token": "0.4.14",
"@noble/hashes": "1.4.0",
"bn.js": "5.2.1"
},
"devDependencies": {
"typescript": "5.6.3",
"tsx": "4.19.2"
}
}Anchor must be pinned to 0.29.0 — the published IDLs were generated against that version and newer Anchor will reject the discriminator layout.
metaDAOproject/programs Anchor.toml, May 2026)| Program | Version | Address |
|---|---|---|
| Futarchy (DAO + proposal lifecycle) | v0.6 | FUTARELBfJfQ8RDGhg1wdhddq1odMAJUePHFuBYfUxKq |
| Conditional Vault (mints pPASS/pFAIL) | v0.4 | VLTX1ishMBbcX3rdBWGssxawAo1Q2X2qxYFYqiGodVg |
| AMM (per-market xy=k with TWAP oracle) | v0.5 | AMMJdEiCCa8mdugg6JPF7gFirmmxisTfDJoSNSUi5zDJ |
| Autocrat (legacy DAO controller, v0.5 era) | v0.5 | auToUr3CQza3D4qreT6Std2MTomfzvrEeCC5qh7ivW5 |
| Launchpad (current ICO program) | v0.8 | moonDJUoHteKkGATejA5bdJVwJ6V6Dg74gyqyJTx73n |
| Launchpad | v0.7 | moontUzsdepotRGe5xsfip7vLPTJnVuafqdUWexVnPM |
| Bid Wall (post-launch price support) | v0.7 | WALL8ucBuUyL46QYxwYJjidaFYhdvxUFrgvBxPshERx |
| Mint Governor | v0.7 | gvnr27cVeyW3AVf3acL7VCJ5WjGAphytnsgcK1feHyH |
| META mint (governance token) | — | METAwkXcqyXKy1AtsSgJ8JiUHwGCafnZL38n3vYmeta |
| USDC (quote asset on mainnet) | — | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v |
All addresses are also exported from the SDK as constants — never hardcode, prefer import { FUTARCHY_V0_6_PROGRAM_ID, META_MINT, MAINNET_USDC } from "@metadaoproject/programs".
https://market-api.metadao.fi (60 req/min — tickers, supply, aggregate volume; no per-proposal endpoint yet — on-chain reads are the source of truth)A live MetaDAO proposal is a graph of 7 on-chain accounts:
┌─── Proposal ────┐
│ (futarchy) │
└─────────────────┘
│ │ │
┌──────────────┘ │ └─────────────┐
v v v
┌─────────┐ ┌─────────┐ ┌─────────┐
│baseVault│ │ AMM │ │AMM │
│ (META) │ │ PASS │ │ FAIL │
└─────────┘ │ (v0.5) │ │(v0.5) │
│ └────┬────┘ └────┬────┘
│ │ TWAP oracle │ TWAP oracle
mints + burns │ │
v │ │
pPASS-META │ │
pFAIL-META │ │
│ │
┌─────────┐ │ │
│quoteVault│ │ │
│ (USDC) │ │ │
└─────────┘ │ │
│ v v
pPASS-USDC pPASS-META/pPASS-USDC pFAIL-META/pFAIL-USDC
pFAIL-USDCconditional_vault v0.4): deposit 1 underlying → mint 1 pPASS + 1 pFAIL. There's one vault per (proposal, mint) pair, so a META/USDC proposal has 2 vaults and 4 conditional mints.getConditionalTokenMintAddr(programId, vault, index)).amm v0.5): one constant-product pool per market — pPASS-META/pPASS-USDC and pFAIL-META/pFAIL-USDC. Half the spot liquidity is duplicated into each market when the proposal launches.u128) of seconds × last_observation. Prices use a lagging cap (twapMaxObservationChangePerUpdate) so flash-price manipulation cannot move the TWAP. Anyone can permissionlessly call crank_that_twap to update the observation. state ProposalState ::= Draft { amountStaked } | Pending | Passed | Failed | Removed
dao Pubkey // parent DAO
question Pubkey // conditional-vault question (proposal hash)
baseVault Pubkey // META-side vault
quoteVault Pubkey // USDC-side vault
passBaseMint Pubkey // pPASS-META
passQuoteMint Pubkey // pPASS-USDC
failBaseMint Pubkey // pFAIL-META
failQuoteMint Pubkey // pFAIL-USDC
squadsProposal Pubkey // links to a Squads v4 tx that executes on Pass
durationInSeconds u32 // trading window length (typ. 3 days = 259200)
timestampEnqueued i64 // when proposal entered Pending
isTeamSponsored bool // -> -3% threshold instead of +3%
number u32 // human-readable proposal number per DAOimport { FutarchyClient } from "@metadaoproject/programs/futarchy/v0.6";
import { AmmClient } from "@metadaoproject/programs/amm/v0.5";
import { AnchorProvider } from "@coral-xyz/anchor";
const provider = AnchorProvider.env();
const futarchy = FutarchyClient.createClient({ provider });
const amm = AmmClient.createClient({ provider });
const proposalKey = new PublicKey("..."); // proposal account
const proposal = await futarchy.getProposal(proposalKey);
const dao = await futarchy.getDao(proposal.dao);
// PASS AMM PDA = derived in AMM v0.5 from (passBaseMint, passQuoteMint)
const passAmmAccount = await amm.fetchAmm(passAmmPda);
const failAmmAccount = await amm.fetchAmm(failAmmPda);
// price = (reserves_quote / reserves_base) and TWAP is in oracle.aggregator
// Convert to UI price: ui = price * 10^(base_decimals - quote_decimals) / 1e12See scripts/read-proposal.ts for the full version that resolves all 7 PDAs, prints spot vs TWAP for both markets, and computes the pass/fail margin.
The motion is always two transactions at the protocol level (one to mint conditional tokens from underlying, one to swap on the conditional AMM) but the SDK wraps both into a single ix builder:
import { FutarchyClient } from "@metadaoproject/programs/futarchy/v0.6";
import BN from "bn.js";
await futarchy
.conditionalSwapIx({
dao,
baseMint: META, // METAwkXcqyXKy1AtsSgJ8JiUHwGCafnZL38n3vYmeta
proposal: proposalKey,
market: "pass", // "pass" | "fail"
swapType: "buy", // "buy" = quote -> base, "sell" = base -> quote
inputAmount: new BN(10_000_000), // 10 USDC (6 decimals)
minOutputAmount: new BN(0), // SET REAL SLIPPAGE in prod
})
.rpc();What this actually does on-chain:
inputAmount USDC from your ATA into the proposal's quote vault.inputAmount pPASS-USDC + inputAmount pFAIL-USDC to your ATAs.To exit before resolution: swap pPASS-META → pPASS-USDC on the pass AMM, then redeem both pPASS-USDC and pFAIL-USDC back to USDC via vaultClient.mergeConditionalTokens (only works if you have equal balances of pPASS and pFAIL — otherwise wait for resolution).
To redeem after resolution: once proposal.state is Passed or Failed, the winning side's conditional tokens redeem 1:1 against the underlying via the conditional vault. The losing side's tokens are worthless.
See scripts/trade-conditional.ts for the full mint + swap + redeem flow.
Creating a proposal involves:
futarchy.initializeProposalIx with a Squads v4 transaction (the action to execute on Pass), a description URI (IPFS/Arweave), and a duration. State = Draft { amountStaked: 0 }.stakeToProposalIx until total stake clears the DAO's passThresholdBps minimum (typically 200k–1.5M META depending on DAO). Staking is anti-spam only — no slashing, no lockup.launchProposalIx. This snapshots half the spot liquidity into pass + fail AMMs, mints conditional tokens, sets state to Pending, and starts the durationInSeconds clock. The TWAP oracle then has a 24-hour delay before recording begins (gives traders time to price).timestampEnqueued + durationInSeconds, anyone calls finalizeProposalIx. The program reads both AMMs' TWAPs, applies the 3% threshold (or -3% if isTeamSponsored), and sets state to Passed or Failed. If Passed, the linked Squads transaction becomes executable.In practice you rarely write the create-proposal flow from scratch — most users propose through the web UI at metadao.fi. The full programmatic example lives in the repo at metaDAOproject/programs/scripts/v0.5/initializeProposal.ts.
The launchpad (program v0.8 = moonDJUoHteKkGATejA5bdJVwJ6V6Dg74gyqyJTx73n) is futarchy's "skin in the game" ICO model:
bid_wall program (WALL8...) provides a programmatic post-launch floor — uses raised USDC to buy back the token below a price.mint_governor and performance_package_v2 programs vest team allocations behind on-chain milestones rather than time-only cliffs.This is the "unruggable" claim: a founder cannot withdraw raised funds without the market voting yes on each spend. To use it, run scripts/v0.7/startLaunch.ts from the programs repo, or use the metadao.fi UI which calls into the same programs.
getDownAndUpMintAddrs (down=fail, up=pass) and getFailAndPassMintAddrs. Mixing them up means you end up long the side you wanted to short. Always derive via the named helper and never assume an order.conditionalSwapIx helper hides this, but if you call the AMM swap instruction directly with USDC, it will fail because the AMM only accepts the conditional mint, not USDC.twapStartDelaySeconds (typ. 86400 = 24 hours) is the gap between when a proposal goes Pending and when the TWAP oracle begins observing. For the first day after a proposal launches, the spot AMM price is moving but the TWAP isn't recording yet. Don't write resolution logic that assumes the TWAP started at timestampEnqueued — it starts at timestampEnqueued + dao.twapStartDelaySeconds.proposal.state only flips to Passed/Failed when someone sends finalizeProposalIx. The web UI sometimes shows "resolved" based on its own off-chain TWAP calculation minutes before the on-chain state changes. If you're indexing or auto-redeeming, read the on-chain state field; do not trust the UI badge. Anyone can permissionlessly send the finalize ix — if it's been more than durationInSeconds and the state is still Pending, just send it yourself.ammClient.crankThatTwap(amm) (permissionless, ~2k CU) to force an observation update. The protocol uses lagging caps (twapMaxObservationChangePerUpdate) so even a stale TWAP can't be manipulated, but reading it without cranking gives you yesterday's number for new proposals.passAmm.totalLiquidity and failAmm.totalLiquidity before sizing — if either is below ~$50k equivalent, treat the market as unreliable for governance signal.SQDS4ep65T869zMMBKyuUq6aD6EgTu8psMjkvj52pCf). A proposal that passes executes a Squads transaction. If you're creating proposals programmatically you must derive the Squads transaction PDA before calling initializeProposalIx and pass it in — getting the transactionIndex wrong silently produces a proposal that, if it passes, will fail to execute. The script at metaDAOproject/programs/scripts/v0.5/initializeProposal.ts shows the correct derivation.https://market-api.metadao.fi)references/futarchy-explainer.mdscripts/read-proposal.ts — connect, fetch a known proposal + DAO, derive all PDAs, print state / pPASS price / pFAIL price / TWAPs / time remaining / current pass margin.scripts/trade-conditional.ts — mint conditional tokens from underlying, swap on pass/fail AMM, and the redeem/merge path.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.