https://github.com/blockful/delegation-incentives-system
https://github.com/blockful/delegation-incentives-system
Last synced: 23 days ago
JSON representation
- Host: GitHub
- URL: https://github.com/blockful/delegation-incentives-system
- Owner: blockful
- License: mit
- Created: 2026-03-07T06:48:44.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-06-10T20:38:15.000Z (about 1 month ago)
- Last Synced: 2026-06-10T22:15:54.873Z (about 1 month ago)
- Language: TypeScript
- Homepage: https://delegation-incentives-system-fronte.vercel.app
- Size: 2.11 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# ENS Delegation Incentives System
Monorepo for computing and distributing monthly ENS delegation incentive rewards. Active voters and their token holders earn pro-rata shares of a tier-based reward pool determined by month-over-month growth in the total voting power held by active voters.
## Architecture
Single-service: Ponder indexes on-chain events and serves REST API endpoints from the same process.
```
packages/
└── domain/ — Pure incentives logic (no framework deps, fully tested)
apps/
├── backend/ — Ponder indexer + Hono REST API
└── frontend/ — Web dashboard (placeholder)
```
## Quick Start
```bash
# 1. Copy env and fill in values
cp .env.example .env
# 2. Install dependencies
pnpm install
# 3. Run tests
pnpm --filter @ens-dis/domain test
pnpm --filter @ens-dis/backend test
# 4. Start the backend (requires RPC_URL and DATABASE_URL)
pnpm --filter @ens-dis/backend dev
```
## Environment Variables
| Variable | Description |
|---|---|
| `RPC_URL` | Ethereum mainnet RPC (required) |
| `DATABASE_URL` | PostgreSQL connection string (required) |
| `BACKEND_PORT` | API port (default: 42069) |
| `ROUND_MONTHS` | Comma-separated configured round months, e.g. `2026-03,2026-04,2026-05` |
| `BLOCKFUL_API_TOKEN` | Bearer token forwarded by the backend to the Gateful relayer (required when relayer is enabled) |
| `GATEFUL_UPSTREAM_URL` | Upstream Gateful relayer base URL (required when relayer is enabled) |
| `ALLOWED_ORIGINS` | Comma-separated frontend origins permitted to call this backend cross-origin (required in production when the SPA hits the backend on a different origin) |
## API Endpoints
Routes are served at the root (no `/api` prefix on the backend). Frontends configure a base via `VITE_API_BASE_URL` if they want one.
Scalar API reference at `GET /docs`. OpenAPI 3.0 spec at `GET /openapi.json`.
| Method | Path | Description |
|--------|------|-------------|
| `GET` | `/health` | Ponder's built-in liveness check (use this for Railway/uptime probes) |
| `GET` | `/voters/active` | Addresses that voted on ≥ 7 of the last 10 proposals |
| `GET` | `/eligibility/{address}` | Is this address an active voter or a token holder of one? |
| `GET` | `/tiers/progression` | Current tier, VP needed for next tier, all tier thresholds |
| `GET` | `/apy/{address}` | Estimated monthly reward and annualized APY |
| `GET` | `/distributions/{month}` | Fetch a stored distribution (JSON) |
| `GET` | `/distributions/{month}/csv` | Download distribution as CSV |
The backend also starts an automatic distribution scheduler in normal runs. It waits for Ponder readiness, then scans every minute and computes any configured `ROUND_MONTHS` that ended at least one minute ago and are not already cached.
## Documentation
| Document | Contents |
|---|---|
| [docs/algorithm.md](./docs/algorithm.md) | Full pipeline spec: each step, all formulas, pool tiers, TWB, cap redistribution, lottery |
| [docs/integrations.md](./docs/integrations.md) | Protocol integrations: contracts indexed, events handled, how data feeds the pipeline |
| [OPERATOR.md](./OPERATOR.md) | Operator guide: running a distribution round, CSV export, monitoring |
## Tech Stack
- **Indexer & API**: Ponder 0.16, Hono, Zod OpenAPI, Drizzle ORM
- **Domain logic**: Pure TypeScript, zero framework dependencies
- **Arithmetic**: BigInt throughout — no floating point
- **Testing**: Vitest, fast-check (property-based)
- **Package manager**: pnpm workspaces
## Gasless Delegation (Relayer)
The frontend delegates voting power via a gasless relayer (when eligible) or falls back to a direct on-chain `delegate(address)` call. Backend routes at `/api/gateful/:dao/relay/*` proxy the upstream Gateful relayer with the bearer token injected server-side.
Eligibility is the only gate: if the relayer's `/balance` reports `hasEnoughBalance: false`, the upstream is unreachable, or the user is over their rate limit / under `minVotingPower`, the modal switches to direct-tx automatically. To take gasless offline cluster-wide without a redeploy, make `/balance` return `hasEnoughBalance: false`.
## Resources
- [ENS Forum — Delegation Incentives Temp Check](https://discuss.ens.domains/t/temp-check-delegation-incentives-program/21824) — original spec
- [ERC20MultiDelegate contract](https://etherscan.io/address/0x3CA5CCC96648d016D41c5aF40eED82202BD019cc)
- [Hedgey TokenVestingPlans contract](https://etherscan.io/address/0x2CDE9919e81b20B4B33DD562a48a84b54C48F00C)