Opinionated DAO governance — members can always exit with their share of the treasury. Built-in futarchy, weighted delegation, and soulbound badges.
- Ragequit — exit with your share of the treasury
- Futarchy — prediction markets on proposals
- Split delegation — divide votes across multiple delegates
- On-chain SVG metadata — no IPFS, no servers
- DUNA legal wrapper support
All contracts are deployed at the same CREATE2 addresses across supported networks.
| Contract | Address | Description |
|---|---|---|
| Summoner | 0x0000000000330B8df9E3bc5E553074DA58eE9138 |
Factory for deploying new DAOs |
| Renderer | 0x000000000011C799980827F52d3137b4abD6E654 |
On-chain SVG metadata renderer |
| MolochViewHelper | 0x00000000006631040967E58e3430e4B77921a2db |
Batch read helper for dApps |
| Tribute | 0x000000000066524fcf78Dc1E41E9D525d9ea73D0 |
OTC escrow for tribute proposals |
| ShareBurner | 0x000000000040084694F7B6fb2846D067B4c3Aa9f |
Burn unsold shares after sale deadline |
| ZAMM | 0x000000000000040470635EB91b7CE4D132D616eD |
AMM for LP seed swaps |
| SafeSummoner | 0x00000000004473e1f31c8266612e7fd5504e6f2a |
Safe deployment wrapper with validated config |
Minimal proxy clones are deployed from these implementation contracts. Each DAO gets its own clone of Moloch, Shares, Loot, and Badges via CREATE2.
| Contract | Address | Description |
|---|---|---|
| Moloch | 0x643A45B599D81be3f3A68F37EB3De55fF10673C1 |
DAO governance logic |
| Shares | 0x71E9b38d301b5A58cb998C1295045FE276Acf600 |
ERC-20 voting token |
| Loot | 0x6f1f2aF76a3aDD953277e9F369242697C87bc6A5 |
ERC-20 non-voting token |
| Badges | 0x47C175Ce83B6B931ccBedD5ce95e701984eD96d5 |
ERC-721 soulbound NFT |
| Token | Standard | Purpose |
|---|---|---|
| Shares | ERC-20 | Voting power + economic rights (delegatable) |
| Loot | ERC-20 | Economic rights only — no voting |
| Receipts | ERC-6909 | Vote receipts for futarchy payouts |
| Badges | ERC-721 | Soulbound NFTs for top 256 shareholders |
Shares, Loot, and Badges deploy as minimal proxy clones. Receipts live inside the Moloch contract. The DAO controls minting, burning, and transfer locks.
Burn shares/loot → receive your pro-rata cut of the treasury. Own 10%? Claim 10% of every token. Only external tokens (ETH, USDC, etc.) — not the DAO's own shares, loot, or badges.
Prediction markets on proposals. Anyone funds a reward pool → voters receive receipt tokens → winning side splits the pool.
Divide voting power across multiple delegates (e.g. 60% Alice, 40% Bob).
Soulbound NFTs for the top 256 shareholders. Auto-update as balances change. Gate on-chain chat.
Majeur supports Wyoming's Decentralized Unincorporated Nonprofit Association (DUNA) (Wyoming Statute 17-32-101). On-chain covenant in metadata, badge-based member registry, permanent governance records, ragequit as a legal exit right.
Unopened → Active → Succeeded → Queued (if timelock) → Executed
↘ Defeated
↘ Expired (TTL)
Pass conditions (all must hold): quorum reached, FOR > AGAINST, minimum YES threshold met (if set), not expired.
Summoner summoner = new Summoner();
Moloch dao = summoner.summon(
"MyDAO", // name
"MYDAO", // symbol
"", // URI
5000, // 50% quorum (bps)
true, // ragequittable
address(0), // renderer (0 = default on-chain SVG)
bytes32(0), // salt
[alice, bob, charlie],
[100e18, 50e18, 50e18],
new Call[](0)
);uint256 proposalId = dao.proposalId(0, to, value, data, nonce);
dao.castVote(proposalId, 1); // 0=AGAINST, 1=FOR, 2=ABSTAIN
dao.executeByVotes(0, to, value, data, nonce);dao.shares().setSplitDelegation([alice, bob], [6000, 4000]); // must sum to 10000
dao.shares().clearSplitDelegation();dao.fundFutarchy(proposalId, address(0), 1 ether); // 0 = ETH
dao.cashOutFutarchy(proposalId, myReceiptBalance);// DAO configures sale (governance action)
dao.setSale(address(0), 0.01 ether, 1000e18, true, true, false);
// token price cap mint active isLoot
// Users buy
dao.buyShares{value: 1 ether}(address(0), 100e18, 1 ether);
// token shares maxPaydao.ragequit([weth, usdc, dai], myShares, myLoot); // tokens must be sortedPermits let specific addresses execute actions without voting:
dao.setPermit(op, to, value, data, nonce, alice, 1); // DAO issues
dao.spendPermit(op, to, value, data, nonce); // Alice spendsdao.setTimelockDelay(2 days);
dao.setProposalTTL(7 days);dao.chat("Hello DAO members!"); // top 256 only// Wrong - will revert if not sorted
address[] memory tokens = [dai, weth, usdc];
// Correct - tokens sorted by address
address[] memory tokens = [dai, usdc, weth]; // sorted ascending// Wrong - doesn't sum to 10000
uint32[] memory bps = [6000, 3000]; // 90% total
// Correct - must sum to exactly 10000
uint32[] memory bps = [6000, 4000]; // 100% totalSummoner (Factory)
└── Deploys via CREATE2 + minimal proxy clones
│
├── Moloch (Main DAO Contract)
│ ├── Governance logic (proposals, voting, execution)
│ ├── ERC-6909 receipts (multi-token vote receipts)
│ ├── Futarchy markets
│ ├── Ragequit mechanism
│ └── Token sales
│
├── Shares (Separate ERC-20 + ERC-20Votes Clone)
│ ├── Voting power tokens
│ ├── Transferable/Lockable (DAO-controlled)
│ ├── Single delegation or split delegation
│ └── Checkpoint-based vote tracking
│
├── Loot (Separate ERC-20 Clone)
│ ├── Non-voting economic tokens
│ └── Transferable/Lockable (DAO-controlled)
│
└── Badges (Separate ERC-721 Clone)
├── Soulbound (non-transferable) NFTs
├── Automatically minted for top 256 shareholders
└── Auto-updated as balances change
Renderer (Singleton)
├── On-chain SVG generation
├── DUNA covenant display
├── DAO contract metadata
├── Proposal cards
├── Vote receipt cards
├── Permit cards
└── Badge cards
Trade external assets for DAO membership:
// 1. Proposer locks tribute (e.g., 10 ETH for 1000 shares)
tribute.proposeTribute{value: 10 ether}(
dao, // target DAO
address(0), // tribTkn (ETH)
0, // tribAmt (use msg.value for ETH)
sharesToken, // forTkn (what proposer wants)
1000e18 // forAmt (how much)
);
// 2. DAO votes to accept, then claims (executes the swap)
// DAO receives tribute, proposer receives shares
dao.executeByVotes(...); // calls tribute.claimTribute(proposer, tribTkn, tribAmt, forTkn, forAmt)Key functions:
proposeTribute()- Lock assets and create offercancelTribute()- Proposer withdraws (before DAO claims)claimTribute()- DAO accepts and executes swapgetActiveDaoTributes()- View all pending tributes for a DAO
Batch reads for dApp frontends:
// Fetch full state for multiple DAOs in one call
DAOLens[] memory daos = helper.getDAOsFullState(
0, // daoStart
10, // daoCount
0, // proposalStart
5, // proposalCount
0, // messageStart
10, // messageCount
tokens // treasury tokens to check
);
// User portfolio: find all DAOs where user is a member
UserMemberView[] memory myDaos = helper.getUserDAOs(
user, 0, 100, tokens
);Returns DAOLens (full state), MemberView (balances, delegation), ProposalView (tallies, state, futarchy).
Sell shares or loot via the allowance system. Uses Moloch's _payout sentinels (address(dao) mints shares, address(1007) mints loot) with 1e18-scaled pricing.
// Setup (in SafeSummoner extraCalls or initCalls):
// 1. dao.setAllowance(shareSale, address(dao), cap) // or address(1007) for loot
// 2. shareSale.configure(address(dao), payToken, price, deadline)
// Users buy shares
shareSale.buy{value: cost}(dao, 10e18); // 10 shares
// Pricing: cost = amount * price / 1e18
// e.g. price = 0.01e18 means 0.01 ETH per shareKey functions:
configure()- Set sale token, payment token, price, and deadline (called by DAO)buy()- Purchase shares/loot (permissionless, refunds overpayment)saleInitCalls()- Generate initCalls for setup
Linear vesting from a DAO treasury via the allowance system.
// Setup (in SafeSummoner extraCalls or initCalls):
// 1. dao.setAllowance(tap, token, totalBudget)
// 2. tap.configure(token, beneficiary, ratePerSec)
// Anyone can trigger claim — funds always go to beneficiary
tap.claim(dao);
// View functions
tap.claimable(dao); // min(owed, allowance, daoBalance)
tap.pending(dao); // total owed (ignoring caps)Vesting formula: owed = ratePerSec * elapsed, capped by min(owed, allowance, daoBalance).
DAO governance:
setBeneficiary()- Change recipient (DAO-only)setRate()- Change rate, non-retroactive: unclaimed accrual is forfeited (DAO-only). Set to 0 to freeze.
Seeds ZAMM liquidity from DAO treasury. Gates addLiquidity pre-seed, returns swap fees post-seed.
// Configured automatically via SafeSummoner SeedModule, or manually:
// 1. dao.setAllowance(lpHook, tokenA, amountA)
// 2. dao.setAllowance(lpHook, tokenB, amountB)
// 3. lpHook.configure(...)
// Anyone can trigger once conditions are met
lpHook.seed(dao);
lpHook.seedable(dao); // check if readyBurns unsold shares after a sale deadline. DAOs issue a one-shot permit during setup.
// Setup via SafeSummoner (automatic when saleBurnDeadline > 0):
// 1. dao.setPermit(op=1, target=burner, ..., spender=burner, count=1)
// After deadline, anyone can trigger the burn
shareBurner.closeSale(dao, sharesAddr, deadline, nonce);Wraps the Summoner with audit-derived configuration guardrails. Validates SafeConfig structs and builds initCalls automatically.
// Preset deployments (one-call with sane defaults)
safe.summonStandard(name, symbol, uri, salt, holders, shares, lockShares); // 7d/2d/10%
safe.summonFast(name, symbol, uri, salt, holders, shares, lockShares); // 3d/1d/5%
safe.summonFounder(name, symbol, uri, salt); // 1d/none/10%/solo
// Full control
safe.safeSummon(name, symbol, uri, quorum, ragequittable, renderer, salt,
holders, shares, loot, config, extraCalls);
// With modular sale/tap/LP (replaces legacy DAICO)
safe.safeSummonDAICO(name, symbol, uri, quorum, ragequittable, renderer, salt,
holders, shares, loot, config, sale, tap, seed, extraCalls);
safe.summonStandardDAICO(name, symbol, uri, salt, holders, shares, lockShares, sale, tap, seed);
safe.summonFastDAICO(name, symbol, uri, salt, holders, shares, lockShares, sale, tap, seed);
// Utilities
safe.predictDAO(salt, holders, shares);
safe.predictShares(dao);
safe.predictLoot(dao);
safe.previewCalls(config);Modules: ShareSale, TapVest, LPSeedSwapHook — configured via SaleModule, TapModule, SeedModule structs. Set singleton = address(0) to skip.
const shares = await dao.shares();
const totalSupply = await shares.totalSupply();
const myBalance = await shares.balanceOf(account);
const myVotes = await shares.getVotes(account);
// Check proposal state
const state = await dao.state(proposalId);
// States: 0=Unopened, 1=Active, 2=Queued, 3=Succeeded, 4=Defeated, 5=Expired, 6=Executed
// Get vote tally
const tally = await dao.tallies(proposalId);
console.log(`FOR: ${tally.forVotes}, AGAINST: ${tally.againstVotes}`);Key events: Opened, Voted, Executed, SaleUpdated.
# Install Foundry
curl -L https://foundry.paradigm.xyz | bash
foundryup
# Build
forge build
# Run all tests
forge test
# Run with verbosity
forge test -vvv
# Run specific test file
forge test --match-path test/Moloch.t.sol
# Run specific test
forge test --match-test test_Ragequit
# Gas snapshot
forge snapshot| File | Coverage |
|---|---|
Moloch.t.sol |
Core governance: voting, delegation, execution, ragequit, futarchy, badges |
Tribute.t.sol |
OTC escrow: propose, cancel, claim tributes |
MolochViewHelper.t.sol |
Batch read functions for dApps |
SafeSummoner.t.sol |
Preset deployments, config validation, ShareBurner integration, address prediction |
ShareSale.t.sol |
Share/loot purchases, refunds, allowance caps, pricing |
TapVest.t.sol |
Linear vesting claims, rate changes, beneficiary updates, cap enforcement |
LPSeedSwapHook.t.sol |
LP seed swap hook for automatic ZAMM LP initialization |
RollbackGuardian.t.sol |
Rollback guardian for emergency DAO recovery |
ContractURI.t.sol |
On-chain metadata and DUNA covenant |
URIVisualization.t.sol |
SVG rendering for cards |
Bytecodesize.t.sol |
Contract size limits |
Key test scenarios:
- Proposal lifecycle (open → vote → queue → execute)
- Split delegation with multiple delegates
- Futarchy funding and payout
- Ragequit with multiple tokens
- Badge auto-updates on balance changes
- Tribute propose/cancel/claim flows
- SafeSummoner preset guardrails and ShareBurner permits
- ShareSale buy/refund/cap flows with ETH
- TapVest claim/rate/beneficiary governance
- LP seed swap hook initialization
- Rollback guardian emergency recovery
| Technique | Savings | Details |
|---|---|---|
| Clone pattern | ~80% deployment | Minimal proxy clones for Shares, Loot, Badges |
| Transient storage | ~5k/call | EIP-1153 for reentrancy guards |
| Badge bitmap | ~20k/update | 256 holders in single storage slot |
| Packed structs | ~20k/write | Tallies use 3 × uint96 for compact storage |
forge script script/Deploy.s.sol --rpc-url $RPC_URL --broadcast| Protection | Mechanism |
|---|---|
| Flash loan attacks | Snapshot at block N-1 |
| Reentrancy | Transient storage guards (EIP-1153) |
| Majority tyranny | Ragequit — minorities can exit with their share |
| Malicious proposals | Timelocks give time to ragequit; bumpConfig() invalidates all pending |
| Token reentrancy | Ragequit requires sorted token arrays |
Moloch.sol has been scanned by twenty-nine independent audit tools. Reports with per-finding review notes are in /audit. Formal verification specs and harnesses are in /certora.
| Auditor | Type | Findings | Report |
|---|---|---|---|
| Zellic V12 | Vulnerability scan | 24 (all false positive, design tradeoff, or low-confidence) | No production blockers |
| Plainshift AI | Vulnerability scan | 3 (2 High, 1 Medium — all design tradeoffs) | No production blockers |
| Octane | Vulnerability scan | 26 vulns + 23 warnings | 4 valid observations, no production blockers |
| Pashov Skills | Vulnerability scan (deep) | 13 (deduplicated from 5 agents) | 2 novel findings, 1 false positive, no production blockers |
| Trail of Bits Skills | Sharp edges + maturity | 20 footguns + 9-category scorecard (2.67/4.0) | Validates config guidance, no production blockers |
| Cyfrin Solskill | Development standards | 32 standards evaluated (21 compliant, 5 partial, 3 non-compliant by design, 3 N/A) | Strong adherence, 2 trivial actionable items |
| SCV Scan | Vulnerability scan (36 classes) | 3 confirmed (2 Low, 1 Informational) from 36 classes | All duplicates of prior findings, no production blockers |
| QuillShield | Multi-layer audit (8 plugins) | 8 findings (3 Medium, 3 Low, 2 Info) | All duplicates or design tradeoffs, no production blockers |
| Archethect SC-Auditor | Map-Hunt-Attack + MCP tools (Slither, Aderyn, Solodit, Cyfrin checklist) | 0 novel (8 spots falsified, 397 Slither + 21 Aderyn findings triaged, 1 KF#8 duplicate via Solodit) | V2 re-run with full MCP integration validates V1 manual results, no production blockers |
| HackenProof Triage | Bug bounty triage (severity re-classification) | 14 triaged: 0 Critical, 0 High, 2 Medium, 5 Low, 5 OOS | No Critical/High under bounty standards |
| Forefy | Multi-expert audit (10 fv-sol categories + governance context) | 8 Low (1 valid, 2 questionable, 5 dismissed) | All duplicates, no novel findings, no production blockers |
| Claudit (Solodit) | Prior art cross-reference (20k+ real findings) | 12 patterns searched, 0 novel | Validates defenses against Nouns/Olympus/PartyDAO exploits |
| Auditmos | Multi-skill checklist (6 of 14 skills applied) | 2 Low, 1 Informational | All duplicates, no production blockers |
| EVM MCP Tools | Regex heuristic scan (5 checks) | 0 confirmed (1 informational) | Tool too basic for governance contracts, no production blockers |
| Claude (Opus 4.6) | 3-round AI audit (systematic → economic → triager) | 1 Medium, 1 Low, 1 Informational | 1 novel observation (post-queue voting — by design), no production blockers |
| Gemini (Gemini 3) | 3-round AI audit (2 passes) | Pass 1: 1 Low (false positive), 1 Info; Pass 2: 5 items (all known/design) | No novel findings across either pass, no production blockers |
| ChatGPT (GPT 5.4) | 3-round AI audit (systematic → economic → triager) | 1 Medium (novel), 1 Low (duplicate) | 1 novel finding (public futarchy freeze), no production blockers |
| DeepSeek (V3.2 Speciale) | 3-round AI audit (systematic → economic → triager) | 1 Low (duplicate) | Front-run cancel is KF#11, no production blockers |
| ZeroSkills Slot Sleuth | EVM storage-safety scan (5-phase) | 0 | No storage-safety vulnerabilities; no manual slot arithmetic, no upgradeable proxies, no lost writes |
| Qwen | 3-round AI audit (Qwen3.5-Plus) | 1 Medium, 1 Low, 1 Info (all duplicates) | No novel findings, competent methodology compliance |
| ChatGPT Pro (GPT 5.4 Pro) | 3-round AI audit (systematic → economic → triager) | 1 Medium (novel), 1 Low, 1 Info (2 duplicates) | 1 novel finding (dead futarchy pools on executed IDs), no production blockers |
| Certora FV | Formal verification (142 properties, 7 contracts) | 1 Low, 2 Informational (all acknowledged, by design) | 126 invariants verified; L-01 tap forfeiture is intentional Moloch exit-rights design |
| Grimoire | Agentic audit (4 sigils + 3 familiars) | 10 confirmed (1 High, 4 Medium, 5 Low, 2 Info — all duplicates) | 0 novel; adversarial triage dismissed 3 false positives, reentrancy surface fully clean |
| Cantina Apex | Quick scan (smart contracts + frontend) | 4 High, 20 Medium (5 novel SC findings + ~18 novel frontend findings) | First to cover frontend and peripherals; most novel findings of any single audit; no production blockers. Frontend findings patched in demo dapp (XSS class, chain mismatch, ABI fix, token classification, decimal validation, deep-link provenance) |
| Solarizer | AI multi-phase security engine (static + semantic + cross-contract) | 1 High, 3 Medium, 15 Low, 5 Info, 5 Gas (0 novel) | All duplicates, false positives, or design observations; "D" security grade is misleading (HIGH-1 is intentional post-queue voting); 3 false positives (multicall access control, checkpoint asymmetry, proposerOf hijack); no production blockers |
| Almanax | Vulnerability scan | 1 High, 2 Medium, 2 Low (0 novel) | All duplicates of known findings (KF#3, KF#8, KF#11, KF#18); no production blockers |
| Archethect SC-Auditor V2 | Map-Hunt-Attack V2 + PoC suite (sc-auditor v0.4.0) | 16 claimed (4H, 5M, 5L, 2 design) — 2 novel, 13 duplicates, 1 config-mitigated | 2 novel findings (ragequit front-run, sale transfer lock bypass); significant severity inflation (all 4 HIGHs are known/config-dependent); 14 PoC tests provide useful regression coverage; no production blockers |
| Ackee Wake Arena | Vulnerability scan | 6 (1H, 3M, 1L — all duplicates) | 0 novel findings; all 6 are duplicates of known findings (KF#1, KF#3, KF#6, KF#15) or previously identified patterns; no production blockers |
| Auron | Vulnerability report | 1 Low (1 novel — downgraded from reported High) | 1 novel finding: self-transfer under split delegation produces non-canceling vote deltas. Invariant violation is real but not practically exploitable with 18-decimal tokens — rounding asymmetry is sub-wei dust. Fix recommended for correctness; no production blockers |
No production blockers were identified across any audit. Thirteen novel smart contract findings were surfaced across twenty-nine scans (5 from prior audits + 5 from Cantina covering peripheral contracts and namespace issues + 2 from Archethect V2 + 1 from Auron). Cantina additionally identified ~18 novel frontend findings (XSS and logic bugs) — the first audit to cover the dapp. Configuration-dependent concerns are enforced by SafeSummoner; code-level issues are candidates for v2 hardening.
Novel smart contract findings (13):
- Vote receipt transferability breaks
cancelVote(Pashov — Low, design tradeoff) - Zero-winner futarchy pool lockup (Pashov — Low, funds remain in DAO treasury)
- Post-queue voting can flip timelocked proposals (Claude Opus 4.6/SECURITY.md — by design, timelock is a last-objection window)
- Public
fundFutarchy+ zero-quorumstate()enables permanent proposal freeze via premature NO-resolution (ChatGPT (GPT 5.4) — Medium, configuration-dependent, enforced by SafeSummoner) fundFutarchyaccepts executed/cancelled proposal IDs, creating permanently stuck futarchy pools (ChatGPT Pro (GPT 5.4 Pro) — Medium, missingexecuted[id]check)bumpConfigemergency brake bypass — lifecycle functions accept raw IDs without config validation (Cantina — Medium, extends KF#10)- Tribute bait-and-switch — escrow settlement terms not bound to claim key (Cantina — Medium, Tribute.sol)
- Permit IDs enter proposal/futarchy lifecycle — missing
isPermitReceiptguards enable futarchy pool drain (Cantina — Medium, extends KF#10) - DAICO LP drift cap uses wrong variable (
tribForLPvstotalTrib) — shifts tokens from LP to buyer when pool spot > OTC. Buyer pays full price; drift is self-correcting via arb; UIs hide pool until sale completion. Impact is reduced LP depth, not theft (Cantina — Low, DAICO.sol, V2 hardening candidate) - Counterfactual Tribute theft via summon frontrun —
initCallsexcluded from salt + Tribute accepts undeployed DAOs (Cantina — Low-Medium, extends KF#9) - Ragequit front-run of treasury inflows —
ragequitreads livebalanceOf(address(this))with no snapshot, allowing front-running of large inflows for disproportionate extraction (Archethect V2 — Low, attacker must hold shares, marginal profit) - Non-minting sale bypasses
transfersLocked— DAO address exemption in_checkUnlockedallowsbuySharesnon-minting path to distribute shares despite transfer lock (Archethect V2 — Low, governance configures both sale and lock) - Self-transfer under split delegation produces non-canceling vote deltas —
_moveTokens()applies two deltas onfrom == tothat don't cancel under split delegation due to_targetAllocrounding. Invariant violation is real but not practically exploitable with 18-decimal tokens — rounding asymmetry is sub-wei dust (Auron — Low, correctness fix recommended)
Tool ranking by signal quality:
-
Cantina Apex produced the most novel smart contract findings (5) of any single audit, plus ~18 novel frontend findings — the first tool to systematically cover the dapp and peripheral contracts (Tribute, DAICO). The bumpConfig bypass (MAJEUR-15), Tribute bait-and-switch (MAJEUR-10), permit futarchy drain (MAJEUR-21), and DAICO LP math bug (MAJEUR-7) are all code-verified. The frontend XSS findings share a single root cause (
innerHTMLwithout escaping) but are individually valid. Signal-to-noise: 5 novel SC findings from 24 total (21%). -
ChatGPT (GPT 5.4) produced the single highest-impact finding (KF#17, Medium) with the best signal-to-noise ratio (1 novel from 2 total findings, 50%). Its architecture assessment — identifying the boundary between live governance state and prediction-market settlement — is the clearest articulation of the futarchy design tension.
-
ChatGPT Pro (GPT 5.4 Pro) surfaced the 5th novel finding (KF#18, Medium) —
fundFutarchymissingexecuted[id]check creates permanently stuck pools on dead proposals. Signal-to-noise: 1 novel from 3 findings (33%). The reentrancy inventory in Category 1 is the most thorough across all 26 audits. LOW-2 (tombstoning) is KF#11 and INFORMATIONAL-3 (auto-futarchy overcommit) was found by 6 prior audits. -
Pashov Skills surfaced 2 novel findings via 5 parallel agents with adversarial reasoning. Higher noise (12 findings, 17% novel rate) but broader coverage.
-
Claude (Opus 4.6) identified a subtle design observation (post-queue voting) that no other tool found, plus the
spendPermitmissingexecuted[id]check (a sharper angle on KF#10, later catalogued as KF#16). -
Trail of Bits and Cyfrin provided unique non-vulnerability value: maturity scoring (2.67/4.0) and standards compliance (21/32 compliant), respectively.
-
Claudit validated defenses against real-world exploits (Nouns, Olympus, PartyDAO) — unique cross-reference approach.
-
Octane produced the most raw findings (49) with 4 valid observations. While none were first-ever novel, Octane provided the most detailed early articulation of the auto-futarchy minted-reward farming vector (vuln #4) — later confirmed by Pashov, Forefy, QuillShield, ChatGPT, ChatGPT Pro, and Qwen. High volume with broad surface coverage — useful for exhaustive first-pass scanning.
-
Gemini (Gemini 3) and DeepSeek (V3.2 Speciale) used the same SECURITY.md prompt as ChatGPT (GPT 5.4) and ChatGPT Pro (GPT 5.4 Pro) but produced zero novel findings, demonstrating that prompt quality alone is insufficient — model capability is the dominant factor.
-
Archethect V1 ran the full Map-Hunt-Attack methodology with MCP tool integration (Slither v0.11.5, Aderyn v0.1.9, Solodit search, Cyfrin checklist). Triaged 397 Slither + 21 Aderyn findings (0 true positives), ran 11 Solodit cross-reference queries, and evaluated 8 suspicious spots. All falsified. The Solodit cross-reference confirmed KF#8 (fee-on-transfer) as the only surviving finding — a duplicate. Zero novel findings, zero false positives escaped the devil's advocate protocol. Archethect V2 (sc-auditor v0.4.0) is dramatically more productive: 16 findings with 14 PoC tests. However, severity inflation is significant — all 4 HIGHs are known findings or config-dependent issues reclassified upward. 2 genuinely novel findings: ragequit front-run of treasury inflows (MH-015) and non-minting sale bypassing
transfersLocked(MH-026), both Low. The 14-test PoC suite is the most comprehensive regression coverage from any single audit. Signal-to-noise: 2 novel from 16 total (13%). -
ZeroSkills Slot Sleuth ran a 5-phase EVM storage-safety analysis (lost writes, attacker-influenced slots, upgrade collisions, storage semantics). Clean pass — Moloch.sol avoids the vulnerability patterns this detector targets (no assembly
SSTORE, no manual slot arithmetic, no upgradeable proxies). Useful for confirming architectural hygiene. -
Forefy, QuillShield, SCV Scan, and Auditmos each independently confirmed subsets of the known findings, adding cross-validation confidence without novel discoveries. EVM MCP Tools was too basic for governance contracts (regex heuristics only).
-
Solarizer produced the highest volume of findings (29) but zero novel discoveries. Notable for 3 clear false positives: LOW-4 (claims
multicallbypassesonlyDAO— incorrect,delegatecalltoaddress(this)preserves caller'smsg.sender), LOW-9 (claims burn/mint checkpoint asymmetry — code is actually symmetric), and MED-1 (claimsproposerOfhijack enables cancel DOS — blocked by auto-futarchy and re-submittable with different nonce). The "D" security grade and "HIGH" risk rating are driven by HIGH-1, which is the documented intentional post-queue voting design (KF#15). Signal-to-noise: 0 novel from 29 total (0%). -
Almanax produced 5 findings (1 High, 2 Medium, 2 Low) — all duplicates of known findings (KF#3, KF#8, KF#11, KF#18). Clean report with no false positives, but zero novel discoveries. The HIGH-1 (auto-futarchy farming) has been found by 9+ prior audits. Signal-to-noise: 0 novel from 5 total (0%).
-
Qwen (Qwen3.5-Plus) used the same SECURITY.md prompt as ChatGPT, Gemini 3, and DeepSeek V3.2 Speciale. All 3 findings are duplicates (KF#5, auto-futarchy overcommit, KF#1), with an inflated self-assessment claiming 2 novel. Competent category sweep and methodology compliance, but zero novel findings — similar depth to DeepSeek V3.2 Speciale and Gemini 3.
-
Grimoire uses a two-pass agentic workflow — 4 parallel Sigil agents (hypothesis-driven hunters) followed by 3 parallel Familiar agents (adversarial verifiers that try to disprove each finding). Similar to Pashov Skills' multi-agent approach but with an explicit adversarial triage pass. Covered 10 of 18 known findings (56%) with zero false positives after triage. The reentrancy surface was thoroughly cleared. The Familiar pass correctly dismissed 3 false positives and adjusted severity on 2 findings. No novel findings, but the highest false-positive rejection rate of any tool.
-
Ackee Wake Arena submitted 6 findings (1 High, 3 Medium, 1 Low) — all duplicates of known findings (KF#1, KF#3, KF#6, KF#15) or previously identified patterns. Finding #1 matches an explicit False Positive Pattern (ragequit drains futarchy pools). The composite High finding (#5) chains known components without novel discovery. Clean code snippets and exploit scenarios, but zero novel findings. Signal-to-noise: 0 novel from 6 total (0%).
-
Certora FV is the only formal verification engagement. 142 properties across 7 contracts provide mathematical proofs for critical invariants (sum-of-balances, state machine monotonicity, write-once fields, access control, split delegation constraints, ragequit payout bounds). The L-01 tap forfeiture finding is confirmed via intentional violation (D-L1a) and reachability witness (D-L1b) — a novel angle on ragequit interaction with DAICO, but acknowledged as intentional Moloch exit-rights design. The two informational findings (unbounded Tribute arrays,
mulDivphantom overflow) are both known tradeoffs. -
Auron identified a novel invariant violation in split-delegation vote accounting: self-transfers produce non-canceling deltas. However, the PoC used 0-decimal balances (raw integer mints like
mintFromMoloch(attacker, 1)= 1 wei, not 1 share). Exhaustive testing across 11 configurations with realistic 18-decimal balances showed: (a) any transfer ≥ 1e14 wei produces exactly 0 steal, (b) 1-wei transfers consistently benefit the victim not the attacker (the "remainder to last" mechanism in_targetAllocpenalizes the attacker position), (c) the 4-way split loop (original PoC config) produced exactly 0 net change over 1000 iterations with 18-decimal balances, (d) even the "best" 2-way loop accumulated only 1000 wei (10^-15 of 1 share) over 1000 iterations. Downgraded from reported High to Low. Signal-to-noise: 1 novel from 1 total (100%), but significant severity inflation from unrealistic PoC parameters. Illustrative case study in why PoCs must use deployment-realistic token scales.
Cross-referencing across all twenty-nine scans — thirteen independent novel smart contract findings (plus ~18 novel frontend findings from Cantina), twenty-three catalogued known findings (KF#1–23), consistent duplicate confirmation across tools, and 142 formally verified invariants — increases confidence that the known findings represent the full smart contract attack surface. Cantina's coverage of the frontend and peripheral contracts (Tribute, DAICO) opened a new surface area not previously audited. Archethect V2's ragequit front-run and transfer lock bypass findings extend coverage to economic timing attacks and access control edge cases not previously explored.
SafeSummoner.sol is a wrapper around the deployed Summoner that enforces audit-derived configuration guardrails at deployment time. Instead of hand-encoding raw initCalls calldata, deployers fill in a typed SafeConfig struct and the contract validates + builds the calls automatically.
| Guard | Finding | What it prevents |
|---|---|---|
proposalThreshold > 0 required |
KF#11 | Front-run cancel, proposal spam, minted futarchy farming |
proposalTTL > 0 required |
Config | Proposals lingering indefinitely |
proposalTTL > timelockDelay |
Config | Proposals expiring while queued |
quorumBps ≤ 10000 |
KF#12 | init() skips this range check |
| Non-zero quorum if futarchy enabled | KF#17 | Premature NO-resolution proposal freeze |
autoFutarchyCap > 0 if futarchy enabled |
KF#3 | Unbounded per-proposal earmarks; default minted-loot reward path has no natural balance cap, enabling NO-coalition treasury farming |
| Block minting sale + dynamic-only quorum | KF#2 | Supply manipulation via buy → ragequit |
DAOs deployed through SafeSummoner.safeSummon() cannot hit the configuration footguns identified across the twenty-eight audits. The previewCalls() function lets frontends inspect exactly which initCalls will execute, and predictDAO() returns the deterministic address before deployment. An extraCalls escape hatch preserves full flexibility for advanced setups (custom allowances, etc.).
Several audit findings highlight configuration combinations that require care. DAOs deploying through SafeSummoner get these enforced automatically. For direct Summoner users:
- Set
proposalThreshold > 0— A non-zero threshold gates proposal creation behind real stake, preventing permissionless griefing (front-run cancel, mass proposal opening for minted futarchy rewards). - Be thoughtful with minted futarchy rewards — When
autoFutarchyParamis set with minted reward tokens (rewardToken = 0→ minted Loot), the per-proposalautoFutarchyCaplimits individual proposals but not aggregate exposure across many proposals. Prefer non-minted reward tokens (ETH, or shares/loot held by the DAO) which have natural balance caps. - Set a non-zero quorum if futarchy is enabled — When both
quorumAbsoluteandquorumBpsare zero,state()returnsDefeatedimmediately with zero votes. SincefundFutarchyis public, an attacker can attach a 1-wei futarchy pool and callresolveFutarchyNoto permanently freeze any proposal before voting begins. Any non-zero quorum prevents this becausestate()returnsActiveuntil quorum is met. - Avoid futarchy in concentrated DAOs — Futarchy is designed to energize broad participation. In DAOs where a small coalition can reach quorum quickly, early NO voters can resolve futarchy and freeze voting before a FOR comeback. Futarchy adds little value in these cases and should not be enabled. Additionally, a majority NO coalition can repeatedly defeat proposals and collect auto-funded futarchy pools — this is by design (NO voters are rewarded for correct governance predictions), but in concentrated DAOs it becomes extractive. The
autoFutarchyCapbounds per-proposal exposure, andproposalThreshold > 0limits who can trigger the earmark cycle. - Ragequit is the nuclear exit — Ragequit gives pro-rata of all DAO-held assets by design, including ETH earmarked for futarchy pools. Futarchy pools are incentive mechanisms subordinate to governance, not restrictive escrows. This is intentional — if excluded from ragequit, a hostile majority could shield treasury via futarchy funding.
- Sale cap is a soft guardrail — The
capinsetSalecorrectly blocks buys exceeding the remaining cap and decrements on each purchase, but uses0as the sentinel for both "unlimited" and "exhausted." After exact sell-out (shareAmount == cap), the cap resets to 0 and the sale becomes unlimited. This only matters for minting sales where the cap is the sole supply constraint — for non-minting sales, the DAO's held share balance is the real hard cap regardless. Buyers always paypricePerShareso there are no free tokens. The DAO can deactivate the sale at any time viasetSale(..., active: false), andSaleUpdatedevents enable off-chain monitoring. V2 hardening candidate: usetype(uint256).maxas the "unlimited" sentinel instead of0. - Dynamic quorum + minting sale + ragequit — When all three are enabled, an attacker can inflate supply via
buyShares, then ragequit after the snapshot, manipulating the quorum denominator. This is economically constrained but worth noting. Consider using absolute quorum (quorumAbsolute) instead of percentage-based (quorumBps) if minting sales are active. - Post-queue voting is intentional — When
timelockDelay > 0, voting remains open during the timelock period. This is by design: the timelock serves as a last-objection window where holders who didn't vote during the Active period can register late opposition. A late AGAINST vote with sufficient weight can flip a Succeeded proposal to Defeated after the delay elapses. This is asymmetric —cancelVoterequires Active state, so existing voters cannot undo votes post-queue. DAOs that prefer Compound-style frozen timelocks should note this behavior.
Identified through audit review for future contract versions:
- Short-circuit self-transfers in
_moveTokens()— addif (from == to) { emit Transfer(from, to, amount); return; }to prevent split-delegation vote delta invariant violation (Auron L-01, correctness fix) - Add
executed[id]check tofundFutarchy— prevents dead futarchy pools on cancelled/executed proposals (KF#18) - Global aggregate cap on auto-futarchy earmarks (or restrict minted rewards to require
proposalThreshold > 0) - Decouple futarchy resolution from voting freeze, or require
Expiredonly (notDefeated) inresolveFutarchyNo— prevents premature NO-resolution on live proposals with zero quorum - Snapshot total supply at proposal creation for quorum calculation (or add cooldown between share purchase and ragequit)
- Bind CREATE2 salt to
msg.senderin Summoner - Snapshot loot supply for futarchy earmark basis
- Namespace separation for permit and proposal IDs
- Optional
freezeOnQueueflag to disable post-queue voting for DAOs that prefer Compound-style frozen timelocks - Store originating
configon proposal open; reject lifecycle actions on stale-config proposals (Cantina MAJEUR-15) - Add
if (isPermitReceipt[id]) revertguards toopenProposal,castVote,fundFutarchy,resolveFutarchyNo(Cantina MAJEUR-21) - Bind
claimTributeto expected settlement terms via nonce/hash (Cantina MAJEUR-10) - Include
initCallsin Summonersummonsalt (Cantina MAJEUR-17) SystematicPatched in demo dappinnerHTML→textContent/DOM API pass in dapp for all untrusted data sinks (Cantina XSS class)Hard-block transactional flows on signer chain ≠ app network (Cantina MAJEUR-24, MAJEUR-16)Patched in demo dappFixPatched in demo dappfetchAndOpenDAOABI toshares()/loot()(Cantina MAJEUR-12)Three-way token classification: shares / loot / unverified ERC20 (Cantina MAJEUR-11)Patched in demo dappResolve token decimals from contract, not chat tags (Cantina MAJEUR-14, MAJEUR-9)Patched in demo dappValidate 18-decimal requirement for custom token wrapping at submit time (Cantina MAJEUR-20)Patched in demo dappRequire Summoner provenance for deep-link DAOs (Cantina MAJEUR-8)Patched in demo dapp (warning label + code check)Route dapp summon throughSafeSummoner deployedSafeSummoner.safeSummon()(Cantina MAJEUR-18)
A: Yes — cancelVote(proposalId) while the proposal is Active. Once it transitions past Active, votes are locked.
A: Yes. Specify how many shares/loot to burn.
A: keccak256(abi.encode(dao, op, to, value, keccak256(data), nonce, config)). Deterministic — anyone can compute it.
A: A version number in every proposal ID. bumpConfig() invalidates all pending proposals and permits — an emergency brake.
A: setSale() is simpler — direct minting at a fixed price. The modular approach composes ShareSale + TapVest + LPSeedSwapHook for controlled fund release, vesting, and automatic LP seeding — configured via SafeSummoner.
A: It limits how fast ops can withdraw raised funds. The DAO can vote to lower the rate or freeze it. Ragequit auto-adjusts the tap to the reduced treasury.
Reviewed by twenty-nine auditing tools (see Audits) — no formal manual audit. Use at your own risk.
MIT