Celo Mondo is a DApp for participating in staking and governance on Celo.
Earn rewards by locking & staking your CELO tokens. Help decide Celo's destiny by casting your vote in on-chain governance proposals.
For information about how Celo's Proof-of-Stake protocol works, or other aspects of the Celo blockchain, see the official Celo Documentation
For support, you can file an issue on this repository or join the Celo Discord
- Clone the repository
- Install dependencies:
yarn - Setup environment:
yarn setup:env- This will log you into Vercel, link the project, and pull environment variables
- The environment includes connection to the staging database (no local DB setup needed)
- Run locally:
yarn dev - Test locally:
yarn test
If you're not part of the cLabs Vercel team or want to modify the database locally:
- Clone the repository
- Install dependencies:
yarn - Start a local PostgreSQL database:
docker run -d \ --name celo-mondo-postgres \ -e POSTGRES_PASSWORD=postgres \ -e POSTGRES_DB=postgres \ -p 5432:5432 \ postgres:16
- Restore the database from the dump file:
cat ./db_dump.sql | docker exec -i celo-mondo-postgres psql -U postgres
- Update your
.envfile with your local database connection:POSTGRES_URL="postgresql://postgres:postgres@localhost:5432/postgres" NEXT_PUBLIC_RPC_URL="https://forno.celo.org"
- Get a WalletConnect Project ID (required for app to run):
If you cant use the
setup:envscript you will need to create your own.- Visit https://cloud.walletconnect.com
- Sign up or log in (free)
- Create a new project
- Copy your Project ID
- Add it to your
.envfile:NEXT_PUBLIC_WALLET_CONNECT_ID="your_project_id_here"
- Backfill the database with historical governance events:
yarn backfill-db
- Update proposal stages to current state:
yarn update-proposal-stages
- Run locally:
yarn dev - Test locally:
yarn test
To run Celo Mondo against a different network, set the NEXT_PUBLIC_RPC_URL env variable to your desired RPC endpoint (e.g., http://<your-rpc-url>).
For more information about the architecture and internals of this app, see DEVELOPER.md.
This section is a short explanation for the governance fetching and displaying. For some context, celo-mondo didn't have a backend part for a long time and fully relied on three data sources: celo blockchain, blockscout events API, and the github repository celo-org/governance. This meant that all merging and data fetching had to happen at runtime in the front-end, per client. Now, since the introduction of the backend we set-up a flow to make the front-end a bit simpler.
Events are indexed in the events table (for redundancy, data is fetched from both webhooks and a github action cronjob just in case).
When a new events is received, we can decode it and update the proposals table according the event to have an always up to date table that the each front-end client can fetch without further data manipulation. See src/app/api/webhooks/multibaas/route.ts to see the webhook and the function calls.
Proposal Stages: The proposals table stores the current stage for each proposal. Stages are kept current through two mechanisms:
- Event-based updates (backfill/webhooks): Process events like
ProposalQueued,ProposalDequeued,ProposalExecuted,ProposalExpired - Time-based updates (cron): A GitHub Action runs every 5 minutes to query
getProposalStage()from the blockchain for proposals in Referendum or Execution stages, which can transition without emitting events
The frontend reads stages directly from the database with no client-side computation, ensuring consistency and correctness.
There's a small schema explaining each table in more details here:
Scripts are located in the src/scripts folder and can be ran through tsx or via the package.json's scripts.
This script reads the @celo/abis and other hand-added known celo abis (eg: some mento stuff), and generates the function 4-byte hash and saves it in src/app/config/selectors.json
This script goes through ALL blocks (starting from last saved block in the DB, or 0 if filling a new DB) and gathers all governance-related events to the DB as well as compute proposal and vote states at the end
This script computes proposal state from the store events. It will OVERWRITE proposals' table data from the events.
It can take an optional argument proposalIds eg: 123,457,789. To replay events from only the given specific proposals.
This script computes all proposals votes from the store events. It will OVERWRITE votes' table data from the events. It can take an optional argument proposalIds eg: 123,457,789. To replay events from only the given specific proposals.
This script finds proposals in database inproposals in Referendum or Execution stage and use the blockchain's getProposalStage() function to updates the database with the current on-chain stage. It also computes off-chain stages like Rejected (when expired with No votes >= Yes votes) and respects Withdrawn status from metadata. This script is automatically run every 5 minutes via GitHub Actions to catch time-based stage transitions that don't emit events.