ClearPath: network-agnostic multi-network DAOs¶
ClearPath (spec 030) is the platform's DAO governance module — a registry, dashboard, and
action-router embedded as a My Account tab. Spec 042 opened it to chains beyond the app's
wager networks — starting with Ethereum mainnet (ENS, Uniswap), with Base/Arbitrum/Optimism
as config-only follow-ons. A network-agnostic-listing follow-up (mirroring the cross-chain
Portfolio pattern, usePortfolio.js) then made the panel itself network-agnostic: it lists
known/tracked DAOs from every clearpath-capable network at once, over each network's own
read provider, independent of the wallet's currently connected chain. A member only needs to
switch networks when they take a write action (register, track-on-a-registry-network, vote,
queue, execute, propose) — the same "Switch to X" pattern TransferForm.jsx uses for portfolio
assets on another chain.
This is a frontend-only capability: there is no new or changed on-chain contract. The
existing ExternalDAORegistry remains deployed only where it already is (Mordor); everywhere
else ClearPath works registry-less.
The three pillars¶
1. Open network model — a clearpath capability¶
Networks are declared in frontend/src/config/networks.js. Each network's capabilities
getter now carries a clearpath flag. A ClearPath-only network (e.g. Ethereum mainnet,
chainId 1) declares clearpath: true while dex/passkeyAccounts/polymarketSidebets/
friendMarkets are false and it has no wager deployment — so wagers/swaps/passkey each
self-disclose as unavailable (networkCapabilities.js exposes a clearpath feature tag).
Adding a network is pure config — declare the entry (RPC, USDC, explorer) and set
clearpath: true.
2. Registry-optional tracking, aggregated across every network¶
ClearPath availability is capability-driven, not registry-gated:
useClearPath().isSupported = capabilities.clearpath && !!reader (this reflects the connected
chain — it gates write actions, not what's listed). The on-chain ExternalDAORegistry is an
optional shared-discovery overlay used where deployed. On a registry-less network a member
tracks a DAO by address into a device-local store (trackedDaoStore.js, localStorage keyed
by chainId + wallet — no backend, no cross-device sync in this cut).
useClearPath().listExternalDAOs() scans every clearpath-capable chain in parallel
(getClearPathChainIds() in config/networks.js, mirroring getPortfolioChainIds()) via
Promise.allSettled — an unreachable RPC on one chain degrades that chain honestly without
blanking the others. For each chain it merges, de-duplicated and still strictly scoped to that one
chain:
on-chain registry entries (iff a registry is deployed on THAT chain)
+ device-local tracked DAOs (per chainId + wallet, on THAT chain)
+ curated known DAOs (config/clearpath/knownDaos.js, on THAT chain)
Every returned row carries its own chainId/networkName, badged in ClearPathPanel.jsx.
Tracking (device-local) works on any chain regardless of the connected one — no tx, no switch.
Registering on a registry network, and every Governor action (vote/queue/execute/propose in
ExternalDaoView.jsx), can only be signed on that DAO's own chain: those surfaces compare
chainId (the DAO's) against the connected chain and show a "Switch to X" button
(wagmi's useSwitchChain().switchChainAsync) in place of the action when they differ.
3. Pluggable per-framework connectors¶
components/clearpath/connectors/ holds one adapter per governance framework behind a common
interface (see specs/042-clearpath-multi-network/contracts/connector-interface.md):
ozGovernor.js(framework 0) — OpenZeppelinIGovernor(ENS, Olympia, …)governorBravo.js(framework 1) — Compound/Bravo (Uniswap):proposals()tallies, tokengetPriorVotesvoting power, id-basedqueue/execute,proposewith the extrasignaturesarray, block clock.
connectors/index.js exports detectFramework(reader, address) (probes OZ via COUNTING_MODE,
then Bravo via proposalCount+quorumVotes, else 'unknown') and getConnector(framework).
Adding a framework (Morpho, Aragon, …) is a new module plus one entry in ORDERED — no
change to the ClearPath UI, the data-source router, or the notification source.
Data sourcing & read routing¶
daoDataSource.js resolves a tracked DAO's proposals subgraph-first: a The Graph governance
subgraph when one is configured for (chainId, dao) in config/clearpath/daoSubgraphs.js and a
gateway key (VITE_CLEARPATH_GRAPH_KEY) is present, otherwise the connector's bounded, chunked
on-chain live indexer, otherwise a truthful empty/partial/error state — never fabricated.
Reads default to the network's public RPC (VITE_RPC_URL_MAINNET etc.); a member can opt
into wallet-managed routing (ReadRouteToggle). Routing affects reads only — every write
is always signed by the connected wallet.
Honesty, scoping & sanctions (unchanged invariants)¶
- Network-scoped data, network-agnostic view: every store and read is still keyed by
chainId(tracked list also by wallet) — a DAO tracked on one chain never leaks into another's scope. The panel aggregates those per-chain scopes into one list for browsing; it never merges DAOs or balances across chains the way a token portfolio would. - Non-custodial: ClearPath constructs actions the member signs against the DAO's own contract; it holds no keys, roles, or funds.
- Sanctions (FR-013): the action path screens the connected signer; a confirmed
restrictedresult (only where aSanctionsGuardis deployed) blocks fail-closed, whileuncertain(no source on the network, e.g. mainnet) proceeds under the DAO's own rules — ClearPath never fabricates a screening result it cannot produce.
Adding a network or a DAO¶
- New network: add a
NETWORKSentry innetworks.jswithcapabilities.clearpath: trueand a usablerpcUrl(+ USDC for treasury reads). Optionally seed known DAOs and subgraphs. - New known DAO: add
{ address, framework, label }toconfig/clearpath/knownDaos.js— verify the address on-chain first (probeCOUNTING_MODEfor OZ, orproposalCount+quorumVotesfor Bravo); never guess. Optionally add its governance subgraph id todaoSubgraphs.js— but only a verified, currently-synced entry on The Graph's decentralized-network gateway (thegraph.com/explorer); the ENS/Uniswap entries are deliberately left empty today because no such live id could be confirmed (see the comment in that file) — a wrong id is worse than none, since the router just falls back to the on-chain live scan either way. - New framework: add
connectors/<framework>.jsimplementing the interface and register it inconnectors/index.js#ORDERED.
See specs/042-clearpath-multi-network/ for the full spec, plan, and task breakdown.