Skip to main content

Server Handler

Since version 0.3, daocafe-sdk reads governance data directly from the CreateDAO contracts over RPC. There is no hosted indexer: the hooks and query functions call /api/daocafe on your own origin, and a handler from daocafe-sdk/server answers from an in-memory cache that it keeps in sync with the chain.
Upgrading from 0.2.x? The hooks, query functions, types and IDs are unchanged. Mount the handler below and you’re done. https://dao.cafe/graphql is retired.

Setup

The handler needs viem:
Keep RPC URLs server-side (no NEXT_PUBLIC_ prefix): the browser only talks to your handler.

Options

Querying Without HTTP

In server components, route handlers or scripts, skip the HTTP hop:
Operations: daos, dao, proposals, proposal, votes, vote, delegates, delegate, tokenHolders, tokenHolder. They take the same parameters as the matching query functions. Servers with the same config share one cache per process.

Fresh Data After Transactions

Responses can be up to minSyncIntervalMs old. After a user’s transaction is mined, call refreshDaoCafe so their vote or proposal shows up immediately:
It refetches every SDK query, and for the next 20 seconds the server re-syncs before answering, at most once every minFreshIntervalMs per chain. If you invalidate queries yourself, call markFresh() first.

How It Works

1

Discover DAOs

DAOCreated events from the factory (0xc852E5Cb44C50614a82050163aB7170cB88EB5F9, same address on every chain).
2

Sync events

One eth_getLogs call covers the factory and every governor and token it created. The first sync starts at the factory deployment block; later syncs only fetch new blocks. If a provider rejects a block range, the range is split, using the limit the provider states when it gives one.
3

Re-read the head

The last ~minute of blocks is fetched again on every sync and replaces what was there. Providers sometimes report a block before its logs can be queried, and a single empty answer must not drop a proposal or vote.
4

Derive entities

DAOs, proposals (with tallies), votes, delegations and token holders (balances and voting power) are rebuilt from the events, with the same IDs and fields the indexer used.
5

Read live state

Governance settings (voting delay/period, threshold, quorum, manager, timelock delay) are read via multicall when a DAO appears and after events that change them. Proposal state comes from events and the block time. Once voting ends, state() is read once to decide SUCCEEDED vs DEFEATED, and the answer is cached.

What It Costs

While someone is browsing, each chain costs at most one eth_getBlockByNumber plus one eth_getLogs per minSyncIntervalMs (15 s by default). Any number of concurrent requests share that sync. With no traffic there are no calls at all. A cold start is about one eth_getLogs per chain with a provider that accepts wide block ranges, such as dRPC. With public RPCs only, the first Arbitrum sync takes a few hundred requests (~30 s); cacheDir keeps that from repeating on restart.

Decoded Actions

Each proposal includes decodedActions, a human-readable decoding of every target/value/calldata triple:
  • Common governance calls are decoded from built-in ABIs, with real argument names: ERC20 transfer/approve/transferFrom/delegate, governor setVotingDelay, setVotingPeriod, setProposalThreshold, updateQuorumNumerator, setManager, updateTimelock, relay, timelock updateDelay/grantRole/revokeRole, and ERC721/1155 safeTransferFrom.
  • Other selectors are looked up on 4byte.directory (cached per process); arguments are then named arg0, arg1, …
  • Empty calldata is reported as ETH Transfer.
When decoding fails, decoded is { status: "error", error, selector, hint }. See Types for the full definitions.