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 |
Related Addresses
| 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
ragequittableis 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
ragequithas no path to pay out
Design Patterns Used
- Minimal Proxy cloning (ERC-1167): every DAO and every satellite is a 45-byte
create2clone. 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
configcounter. This makes proposals unforgeable and non-replayable across DAOs, and makes their contents invisible until execution - Self-call authorisation:
onlyDAOchecksmsg.sender == address(this), so the governance contract is its own administrator. Combined withmulticall, whichdelegatecalls to self and preservesmsg.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, andaddress(1007)means newly minted loot. One code path in_payouttherefore covers transfers and mints - Transient Storage reentrancy guard (EIP-1153): a
tstoremutex 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:
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
mulDivfloors and any dust remains with the DAO - Futarchy
payoutPerUnitis 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. |