Skip to content

Contract Analysis

DISCLAIMER // NFA // DYOR

This analysis is based on observations of the contract behavior. We are not smart contract security experts. This document aims to explain what the contract appears to do based on the code. It should not be considered a comprehensive security audit or financial advice. Always verify critical information independently and consult with blockchain security professionals for important decisions.

⊙ generated by robots | curated by humans

Analysis Date: 2026-08-18


Metadata

Primary Contract

PROPERTY VALUE
Contract Address 0x643A45B5...0673C1 (etherscan)
Network Ethereum Mainnet
Contract Type Implementation — cloned per DAO as an ERC-1167 Minimal Proxy
Deployment Date 2025-11-17 07:54:23 UTC
Deployment Block 23817534
Contract Creator 0x1C0Aa8cC...855A20 (etherscan)
Creation TX 0xe46cba9e...384e12 (tx)
Compiler Version Solidity v0.8.30+commit.73712a01, optimizer enabled, 245 runs
Total Functions 136 across five contracts (81 on Moloch)
External Contract Dependencies 1 — the shared renderer
Upgrade Mechanism ☒ None — the implementation address is baked into each clone's bytecode and cannot be changed
Verification Status ☑ Verified on Etherscan, and byte-identical to repository HEAD
Audit Status ◇ 33 reports published in the project repository, a mix of security firms and language-model passes; not reviewed or endorsed here
TYPE ADDRESS NOTES
Factory 0x00000000...eE9138 (etherscan) Summoner — the SUMMONER immutable and the only address that can initialise a clone. 56 DAOs summoned at analysis, 59 by 2026-09-26
Shares implementation 0x71E9b38d...Acf600 (etherscan) Cloned once per DAO
Loot implementation 0x6f1f2aF7...7bc6A5 (etherscan) Cloned once per DAO
Badges implementation 0x47C175Ce...eD96d5 (etherscan) Cloned once per DAO
Renderer 0x00000000...D6E654 (etherscan) Shared metadata renderer; replaceable per DAO by vote
Sampled instance — zOrg 0x5E58BA0e...74053E (etherscan) daos(0). Cited for storage reads and proposal-lifecycle behaviour
Sampled instance — FWC 0xE7Aa6cA3...F49853 (etherscan) daos(26). Cited for permit and allowance behaviour

The subject of this analysis is the implementation contract, not any DAO running on it. The two DAOs above are two of those clones, cited throughout as evidence that a behaviour read out of the source occurs in production; their settings, balances and proposal histories belong to them and are not framework defaults. The per-instance reads are collected in artifacts.md.


Executive Summary

Majeur is a DAO framework. The address above is not a DAO — it is the logic that every one of them shares — 56 at analysis, 59 by 2026-09-26. Each DAO is a 45-byte clone pointing at this implementation, and each summons three satellite contracts of its own at birth: Shares (a voting ERC20 with checkpoints and delegation), Loot (an economic ERC20 with no vote), and Badges (a soulbound seat board for the largest holders). None of the four can be upgraded, re-pointed, or administered by any privileged address, because there is no privileged address in the system at all.

That last point is the framework's defining property. There is no owner, no admin role, no pause, and no proxy upgrade path. Every privileged function is guarded by onlyDAO, which on the governance contract means msg.sender == address(this) — the DAO calling itself. The only ways to reach that state are a proposal that passed a vote, a permit a previous proposal granted, or a setup call made in the summon transaction before any electorate existed. Governance is not a layer on top of an admin key.

A proposal in Majeur is a hash. proposalId(op, to, value, data, nonce) returns the keccak of an intent bound to the DAO address and a version counter, and every subsequent step — opening, voting, queueing — takes only that number. The target address, the ether amount and the calldata are never written to storage and never emitted at proposal time. They first appear on-chain in the call to executeByVotes, once the proposal has passed. This is what makes the system's central question a social one rather than a technical one: voters must obtain the intent from somewhere off-chain and trust that it hashes to the number in front of them. The hash is independently verifiable by anyone who recomputes it.

The design descends from Moloch, and its load-bearing primitive is Ragequit: any holder may burn shares and loot and walk away with a proportional slice of the treasury rather than be bound by a decision. Both live DAOs have this enabled. The framework layers on machinery that classical Moloch lacks — split delegation across up to four delegates, prediction markets attached to proposals, badge-gated on-chain chat, and standing permits that let a single vote authorise an action many times over.

Three trust assumptions carry most of the weight. A passing proposal can delegatecall, which runs arbitrary code against the DAO's own storage and can rewrite anything, including the ragequit flag. A proposal that has been queued never expires, so approved actions accumulate as a permanent backlog that any address may fire at a time of its choosing. And the meaning of a proposal exists only where its author published it. The contract records none of it. Nothing in the framework requires that it be published anywhere, so what a voter can know is a property of the DAO's operating conventions rather than of the code — a DAO that publishes its parameters leaves them checkable against the stored hash, and one that does not leaves voters with only a number.

Against those, four properties are verifiable from the source. Vote weight is read exclusively from historical checkpoints with no current-balance fallback, so shares bought after a snapshot buy no influence over it. Reentrancy protection uses Transient Storage and covers every outflow path, though fundFutarchy pulls ERC-20 funds in without the guard. The satellite binding is written once and has no setter. And the deployed bytecode is byte-identical to the published repository.


Architecture

graph TB
    EOA["Summoner caller<br/>(permissionless)"]
    SUM["Summoner<br/>0x00000000...eE9138<br/>59 DAOs summoned (2026-09-26)"]

    subgraph Impls["Implementations — immutable, cloned per DAO"]
        MI["Moloch<br/>0x643A45B5...0673C1"]
        SI["Shares<br/>0x71E9b38d...Acf600"]
        LI["Loot<br/>0x6f1f2aF7...7bc6A5"]
        BI["Badges<br/>0x47C175Ce...eD96d5"]
    end

    subgraph DAO["One DAO instance (clone)"]
        M["Moloch clone<br/>0x5E58BA0e...74053E<br/>governance + treasury"]
        S["Shares clone<br/>votes, checkpoints, delegation"]
        L["Loot clone<br/>economic rights only"]
        B["Badges clone<br/>256 soulbound seats"]
    end

    R["Renderer<br/>0x00000000...D6E654<br/>replaceable by vote"]

    EOA -->|"summon()"| SUM
    SUM -->|"create2 clone"| M
    SUM -.->|"delegatecall target"| MI
    M -->|"create2 in init()"| S
    M -->|"create2 in init()"| L
    M -->|"create2 in init()"| B
    S -.->|"delegatecall target"| SI
    L -.->|"delegatecall target"| LI
    B -.->|"delegatecall target"| BI

    S -->|"onSharesChanged"| M
    M -->|"onSharesChanged"| B
    M -->|"tokenURI / contractURI"| R
    B -->|"badgeTokenURI"| R

    M -->|"executeByVotes: call or delegatecall"| EXT["Any address<br/>chosen per proposal"]

    style MI fill:#e1f0ff
    style M fill:#fff4e1
    style EXT fill:#ffe1e1

System Overview

A DAO is created by calling summon on the factory. That deploys a Moloch clone with create2, and the clone's init immediately deploys its own Shares, Loot and Badges clones, mints the founding share allocation, and executes an arbitrary list of setup calls supplied by the summoner. From that point the DAO is autonomous — the factory retains no authority over it.

Members hold shares. Shares carry both economic and voting rights, and voting rights are routed by delegation that defaults to self. A proposal is opened against a precomputed intent hash, which fixes a snapshot at the previous block; votes are weighted by delegated balance at that snapshot and nothing later changes them. If the proposal clears its quorum and has more FOR than AGAINST, it becomes executable — through a timelock queue where one is configured.

  • Holds and disburses a treasury in ETH and arbitrary ERC-20 tokens, with proportional exit available to every holder at any time while ragequittable is set
  • Executes arbitrary calls, and arbitrary delegatecalls, against any address on the basis of a passing vote
  • Tracks voting power through historical checkpoints, so influence cannot be bought after a proposal opens
  • Does not record what any proposal actually does. Only the hash is stored, so an observer reading the chain cannot describe a pending proposal's effect
  • Does not expire a proposal once queued, so approved actions remain executable indefinitely by any caller, subject to the live tally and current quorum settings until they run
  • Does not distribute NFTs on exit. Both live DAOs can receive ERC721 and ERC1155 assets that ragequit has no path to pay out

Design Patterns Used

  • Minimal Proxy cloning (ERC-1167): every DAO and every satellite is a 45-byte create2 clone. Deployment is cheap and addresses are deterministic, and because the implementation address is written into the clone's own bytecode there is no upgrade path and no proxy admin to compromise
  • Content-addressed intents: a proposal is identified by the hash of what it would do, salted with the DAO address and a config counter. This makes proposals unforgeable and non-replayable across DAOs, and makes their contents invisible until execution
  • Self-call authorisation: onlyDAO checks msg.sender == address(this), so the governance contract is its own administrator. Combined with multicall, which delegatecalls to self and preserves msg.sender, one proposal can perform many configuration changes
  • Checkpointed voting with split delegation: an ERC20Votes-style checkpoint array per delegate, extended so a holder can divide weight across up to four delegates in basis points. Reallocation computes old and new target allocations and moves only the difference, which keeps repeated changes free of rounding drift
  • Sentinel addresses as asset selectors: address(0) means ETH, address(this) means newly minted shares, and address(1007) means newly minted loot. One code path in _payout therefore covers transfers and mints
  • Transient Storage reentrancy guard (EIP-1153): a tstore mutex at a fixed slot, applied to all six functions that pay value out
  • Dual-token economics: shares vote and claim; loot only claims. Issuing loot dilutes treasury claims without diluting governance, so a contributor can be paid without gaining voting weight

Access Control

Roles & Permissions

ROLE ASSIGNED BY REVOKABLE CALL COUNT
The DAO itself Structural — msg.sender == address(this) No — it is the contract's own identity Unlimited, but only via a passing proposal, a permit, or a summon-time init call
Proposer openProposal, recorded in proposerOf No — fixed per proposal Once per proposal; may cancel only while untouched
Voter Holding delegated shares at the snapshot block Yes — cancelVote while the proposal is Active Once per proposal, unless cancelled and recast
Permit holder setPermit by the DAO Yes — a later setPermit with a lower count Up to the granted count, with no expiry
Allowance holder setAllowance by the DAO Yes — a later setAllowance Unlimited draws up to the granted amount, with no expiry
Badge holder Badges.onSharesChanged automatically Yes — evicted when balance hits zero or a larger holder displaces them Unlimited chat calls while seated
Summoner (factory) Immutable in implementation bytecode No init once per clone
Executor Anyone N/A Unlimited — executeByVotes has no caller restriction

Permission Matrix

FUNCTION DAO (VIA VOTE) PROPOSER SHARE HOLDER PERMIT HOLDER ANYONE
openProposal ☑ ☑ ☑ above threshold ☒ ☒ below threshold
castVote ☑ ☑ ☑ with snapshot weight ☒ ☒
cancelVote ☑ ☑ ☑ own vote only ☒ ☒
cancelProposal ☒ ☑ if untouched ☒ ☒ ☒
queue ☑ ☑ ☑ ☑ ☑
executeByVotes ☑ ☑ ☑ ☑ ☑
spendPermit ☑ ☒ ☒ ☑ ☒
spendAllowance ☑ ☒ ☒ ☒ ☑ if granted
ragequit ☑ ☑ ☑ ☑ ☒ without shares
buyShares ☑ ☑ ☑ ☑ ☑ while a sale is active
chat ☑ ☑ ☑ if badged ☑ if badged ☒
fundFutarchy ☑ ☑ ☑ ☑ ☑
All set* configuration ☑ ☒ ☒ ☒ ☒
bumpConfig ☑ ☒ ☒ ☒ ☒
mintFromMoloch / burnFromMoloch ☑ ☒ ☒ ☒ ☒

Time Locks & Delays

ACTION TIME LOCK CAN CANCEL PURPOSE
Execute a passed proposal Yes — timelockDelay seconds after queue; per-instance, zero disables Only by bumpConfig, which invalidates every pending proposal ☑ Delay between approval and effect
Proposal expiry Yes — proposalTTL from creation, but only while unqueued; per-instance, zero disables N/A △ Applies to unqueued proposals only; queueing removes it permanently
Spend a permit None Only by a later setPermit ☒ Immediate, no delay, no expiry
Draw an allowance None Only by a later setAllowance ☒ Immediate, no delay, no expiry
Configuration changes Inherited from the proposal that makes them N/A △ Takes effect immediately and applies retroactively to proposals already in flight
Ragequit None N/A ☑ Exit is always immediate while enabled

Governance Configuration

Every parameter below is per-DAO state, changed thereafter only by a passing proposal calling the DAO's own setter. The implementation ships no defaults. init takes quorumBps and ragequittable directly and leaves every other parameter at zero, so anything else a DAO wants configured at birth must be written by the arbitrary initCalls that run in the same summon transaction. Only quorumBps is range-checked; every other setter accepts any value its type can hold.

SETTING ZERO MEANS EFFECT WHEN NON-ZERO
quorumBps No turnout requirement Turnout required as a fraction of the snapshot share supply. Rejected above 10,000
quorumAbsolute Disabled Minimum total votes cast, in share units, regardless of supply
minYesVotesAbsolute Disabled Minimum FOR votes, in share units, below which the proposal is Defeated
proposalThreshold Anyone may open a proposal Current delegated votes (getVotes) the opener must hold at the time of opening; on an implicit open, the first voter
proposalTTL Unqueued proposals never expire Seconds from creation before an unqueued proposal reads Expired
timelockDelay Queued proposals are immediately executable Seconds a queued proposal must wait before it can run
ragequittable Exit is disabled Holders may burn shares and loot for a proportional slice of the treasury
config Never bumped A version counter mixed into every proposal hash; incrementing it invalidates all pending proposals and permits at once
autoFutarchyParam / autoFutarchyCap No automatic market Basis points of share supply earmarked as a futarchy reward pool per proposal, and a ceiling on that earmark

Two of these interact in a way that is not apparent from either alone. On a timelocked DAO, execution requires that a proposal be queued while it is still Succeeded and unexpired, and then that the full timelock elapse. The window to rescue a passing proposal is therefore proposalTTL measured from creation, and timelockDelay plays no part in it — a DAO can lengthen its timelock indefinitely without buying its members any more time to queue. Where a DAO sets the two equal, the earliest possible execution is one full TTL after the deadline to queue. On a DAO with a TTL and no timelock, queue returns without effect, and the proposal must be executed inside the TTL.

state() is computed live rather than snapshotted, so all of these apply retroactively to proposals already in flight. Changing quorum can pass a proposal that was failing, or strand one that was passing, without any vote being cast.

Both behaviours are observable on the sampled DAOs. Two zOrg proposals cleared a 10% quorum with zero AGAINST votes — one at roughly three times the required turnout, the other at roughly 2.2 times — and both read Expired, having never been queued; a third was queued with 3.6 hours of its 24-hour window remaining. A fourth reads Expired today only because proposalTTL was raised from zero after it was opened. In the opposite direction, two FWC proposals were queued on their creation day, cleared their timelock, and have been executable by any address for roughly 16 days without being executed.


Economic Model

The framework holds a treasury and issues two fungible tokens against it. Value enters through direct transfer, share sales, and futarchy funding; it leaves through proposal execution, allowance draws, permit spends, futarchy payouts, and ragequit.

Ragequit

The exit right is the economic centre of the design. A holder burns some quantity of shares and loot and receives that fraction of each token they enumerate:

due = pool × (sharesToBurn + lootToBurn) / (shares.totalSupply + loot.totalSupply)

The denominator is read before the burn, so the ratio reflects the caller's pre-burn ownership. Shares and loot are interchangeable for this calculation, which is the mechanism by which loot dilutes treasury claims without touching governance.

flowchart TD
    A["ragequit(tokens[], sharesToBurn, lootToBurn)"] --> B{"ragequittable?"}
    B -->|no| R["revert NotOk"]
    B -->|yes| C["total = shares.totalSupply + loot.totalSupply<br/>(read BEFORE burning)"]
    C --> D["burn caller's shares and loot"]
    D --> E["for each token in caller-supplied list"]
    E --> F{"token is shares, loot,<br/>this, or 1007?"}
    F -->|yes| R2["revert Unauthorized"]
    F -->|no| G{"strictly ascending?"}
    G -->|no| R3["revert NotOk"]
    G -->|yes| H["due = pool × amt / total"]
    H --> I["pay out ETH or ERC-20"]
    I --> E
    E --> J["tokens NOT in the list:<br/>claim destroyed, shares already burned"]

    style J fill:#ffe1e1
    style D fill:#fff4e1

The list is caller-supplied and never checked against what the treasury holds. Omitting an asset forfeits the claim on it, and because the burn happens first, the forfeit is permanent rather than deferred.

Fee Structure

There are no protocol fees. The framework takes nothing on deposits, sales, exits, or executions, and no address accrues revenue from its operation.

Funding Sources & Sinks

DIRECTION MECHANISM CONSTRAINT
In Direct transfer to the DAO receive() accepts ETH unconditionally
In buyShares Requires an active sale at a governance-set price; may mint new units or sell treasury-held ones
In fundFutarchy Anyone may fund a proposal's reward pool in the pinned asset
Out executeByVotes Arbitrary, up to the full treasury, per passing proposal
Out spendAllowance Up to the standing allowance, at the holder's discretion, with no expiry
Out spendPermit Whatever the permitted intent does, repeatable up to the granted count
Out cashOutFutarchy Winning-side receipts burned for a pro-rata slice of the pool
Out ragequit Proportional slice of every enumerated ERC-20 and ETH

Economic Properties Observed in the Source

  • Ragequit pays strictly less than or equal to the caller's proportional share, because mulDiv floors and any dust remains with the DAO
  • Futarchy payoutPerUnit is fixed once at resolution against the winning side's supply, so subsequent receipt transfers redistribute claims without changing the total paid out
  • Shares, loot, the DAO address and the loot sentinel are rejected as ragequit claim targets, which appears to stop an exit recursively consuming the governance tokens
  • Vote weight for a proposal is bounded by the share supply checkpointed at its snapshot block, and no post-snapshot mint can increase it
  • Sale caps decrement before funds are pulled, which on the source ordering should prevent a reentrant call exceeding the cap; this was not tested dynamically

Summary of Observations

The findings that carry the most weight are the ones about what a member can know and when they can act, rather than about the treasury.

What a proposal is turns out to be the whole story. A hash of mode, target, value, calldata and nonce is the only thing the chain records at proposal time. Voters approve a number; the number's meaning lives wherever its author published it. Anyone can recompute the hash to check the correspondence, and nothing in the contract requires them to. Whether a member can know what they are voting on is therefore a property of the DAO's conventions, not of the framework — and the same holds for an approved proposal that has not yet executed, whose parameters remain unrevealed on-chain until someone runs it.

The clock behaviour is the finding most likely to affect a real member, and it is the least visible. A proposal that passes still dies unless somebody queues it (on a timelocked DAO) or executes it (on one without) inside proposalTTL, and nobody is obliged to. It has happened on a sampled DAO to proposals carrying unanimous support at multiples of the required turnout. Compounding it, state() evaluates against current settings rather than those in force at the snapshot, so configuration changes apply retroactively to proposals already in flight — one proposal reads Expired today for no reason other than that its DAO raised proposalTTL from zero after it was opened.

Queueing inverts the same mechanism. Once queuedAt is set the expiry branch becomes unreachable, so an approved proposal remains executable indefinitely and any address may fire it — though until it runs, the live tally and current quorum settings still decide whether it reads Succeeded. Both behaviours follow from a state machine that treats queueing and expiry as alternatives rather than as a sequence.

On money the picture is mixed rather than alarming. Ragequit is a proportional exit that no vote can block while the flag is set, and it rounds in the treasury's favour. Vote weight comes only from historical checkpoints, so influence cannot be bought after a proposal opens. Against that, a passing proposal can delegatecall arbitrary code into the DAO's own storage, and the two standing-authorisation mechanisms — permits and allowances — outlive the vote that created them with no expiry and no revocation short of another vote. Neither sampled DAO has executed anything via op != 0, but one carries a live single-use delegatecall permit, which puts that path a permit-holder's transaction away rather than a vote away. Allowances are the quieter of the two: setAllowance emits no event at all, so a standing right to mint shares or draw treasury tokens is recoverable only by reading storage or decoding executed calldata. On one sampled DAO the share-minting allowances outstanding came to roughly 4.5 times its share supply on 2026-09-26 (artifacts).

Three properties are worth recording because they were checked rather than assumed. The deployed bytecode is byte-identical to the published repository, confirmed by diff. The satellite contracts are bound to their governor by a write-once field with no setter. Split Delegation reallocates by computing old and new target allocations and moving only the difference, so repeated changes do not leak voting power to rounding.

This analysis was performed for educational purposes. It is not a security audit and it is not financial advice. Nothing here should be read as a statement that the framework is safe, and nothing here should be read as a statement that it is unsafe. Verify independently, and consult qualified professionals before making decisions that depend on any of it.


References

RESOURCE NOTES
Etherscan — Moloch implementation Verified source, compiler settings, and creation transaction
z0r0z/majeur Project repository; deployed source diffed against HEAD 7d7a36b5 and found identical
Foundry Cast reference Command syntax for all on-chain reads in the verification guide
Etherscan API v2 Source retrieval, creation metadata, and event log queries
zFi DAO interface Front end through which both sampled DAOs are operated
ZorgConviction Contract Analysis A contract governed by the zOrg instance, and the target of an executed proposal
zRouter Contract Analysis Target of an executed proposal calling trust(address,bool)
TokenList Contract Analysis The zFi registry that ZorgConviction ranks
z0r0z Entity profile of the framework's author
Proxy Contracts & Upgradeability Background on the clone pattern used for every contract here
Multisigs & Timelocks Background on the timelock semantics discussed above

Change Log

DATE AUTHOR NOTES
2026-08-18 Artificial. Generated by robots. Gas: 1.7 mtok
? ? Reviewed, edited, and curated by humans.