Skip to Content
Quorum contracts are live on Base Sepolia. Mainnet ships after external audit. Do not send real funds.
ContractsChamberRegistry

ChamberRegistry

ChamberRegistry.sol is the on-chain notary for chambers and the source of truth for graduated idea tokens. 183 LOC, Solidity 0.8.26, OpenZeppelin v5.

Responsibilities

  1. Notarize chambers — store the Merkle root of every committed chamber so the off-chain transcript is auditable.
  2. Register idea tokens — when IdeaFactory.deployIdea succeeds, the factory calls back to ChamberRegistry.registerIdea(chamberId, slot, tokenAddress).
  3. Track graduationmarkGraduated(token) flips an idea to graduated state. markGraduated is strictly gated: only the registered idea token itself OR IdeaFactory may call it (NotIdeaTokenOrFactory revert otherwise). An open-auth path here would let any EOA mark arbitrary ideas as graduated and skew fee routing.

Surface

function commitChamber(uint64 chamberId, bytes32 root, uint256 createdAt) external onlyDealer; function registerIdea(uint64 chamberId, uint32 slot, address tokenAddress, bytes32 ticker, address creator) external onlyFactory; function markGraduated(address tokenAddress) external; function getChamber(uint64 chamberId) external view returns (Chamber memory); function getIdea(address tokenAddress) external view returns (Idea memory); function getIdeasByChamber(uint64 chamberId) external view returns (address[] memory); function getGraduatedIdeas() external view returns (address[] memory); // Owner-gated function setFactory(address factory) external onlyOwner; function setDealer(address dealer) external onlyOwner;

Storage layout

struct Chamber { uint64 chamberId; uint256 createdAt; bytes32 merkleRoot; } struct Idea { uint64 chamberId; uint32 slot; bytes32 ticker; address creator; bool exists; bool graduated; } mapping(uint64 => Chamber) private _chambers; mapping(address => Idea) private _ideas; mapping(uint64 => address[]) private _chamberIdeas; address[] private _ideaTokens; uint64[] private _chamberIds; address public factory; // IdeaFactory address public dealer; // relayer EOA

Why markGraduated is access-controlled

A registry of this shape with open markGraduated lets any EOA flag arbitrary tokens as graduated, which would skew fee routing and trigger downstream LP migration paths. ChamberRegistry closes that surface by restricting the caller:

function markGraduated(address tokenAddress) external { Idea storage idea = _ideas[tokenAddress]; if (!idea.exists) revert IdeaNotRegistered(); if (idea.graduated) revert AlreadyGraduated(); // GATE: only the registered idea token itself OR the IdeaFactory can call this. if (msg.sender != tokenAddress && msg.sender != factory) { revert NotIdeaTokenOrFactory(); } idea.graduated = true; emit IdeaGraduated(tokenAddress); }

Test test_MarkGraduated_RandomCallerReverts asserts the access control. The CLAUDE.md project rule: every PR that touches ChamberRegistry re-asserts this test.

Audit notes

  • L-01getGraduatedIdeas() is O(n) over _ideaTokens. At >10k ideas the call blows the block gas limit. Pre-mainnet fix: maintain a separate _graduatedIdeas array on markGraduated instead.
  • L-02 — The msg.sender == tokenAddress branch in markGraduated is structurally dead (Clanker v4 tokens are pure ERC-20s with no callback). Kept for forward-compatibility but documented.

Events

event ChamberCommitted(uint64 indexed chamberId, bytes32 root); event IdeaRegistered(uint64 indexed chamberId, uint32 indexed slot, address indexed tokenAddress, bytes32 ticker); event IdeaGraduated(address indexed tokenAddress); event FactoryUpdated(address indexed previous, address indexed next); event DealerUpdated(address indexed previous, address indexed next);

Access control summary

FunctionCaller
commitChamberdealer (the relayer EOA)
registerIdeafactory (IdeaFactory)
markGraduatedthe registered idea token OR factory
setFactory, setDealerowner
All viewsanyone

The dealer is the trust anchor for off-chain → on-chain commitments. On mainnet this will be a Safe multisig with a clear policy: commit only chamber roots produced by the canonical forum-API instance. The dealer cannot censor on-chain — it can only choose what to commit.

Last updated on