Cloudflare Worker that proxies and filters DeFiLlama's protocol data to work within Dune Analytics' 4MB response limit. Supports any DeFi protocol available on DeFiLlama.
- Supports any DeFiLlama protocol (aave, uniswap, curve, etc.)
- Filters TVL data by chain and time period
- Minimal dependencies (only Hono framework)
- CORS enabled for Dune Analytics
- Returns
invalid_protocol_requestedfor non-existent protocols - Configurable days lookback and result limits
- Request IDs and security headers on every response
- Configurable rate limiting and CORS allowlist
- Cloudflare Durable Object distributed rate limiting
- Upstream circuit breaker for repeated API failures
- Install dependencies:
bun install
# or npm install- Login to Cloudflare:
bunx wrangler login
# or npx wrangler login- Deploy the worker:
bun run deploy
# or npm run deployYour worker will be deployed to: https://defi-tvl-proxy.{your-subdomain}.workers.dev
GET /protocol/{protocol}/tvl/{chain}?days={days}&limit={limit}
Parameters:
protocol(required): Protocol name (e.g., aave, uniswap, curve)chain(optional): Chain name (default: "Ethereum")days(optional): Number of days to look back (default: 30, use 0 for all data)limit(optional): Maximum entries to return (default: 0 for no limit)
GET /protocol/{protocol}/chains
GET /health
Set environment variables in .dev.vars for local development or Worker vars in Cloudflare:
CACHE_TTL(default600)API_TIMEOUT(default5000)CORS_ORIGINS(comma-separated allowlist; default*when unset)RATE_LIMIT_MAX(default120)RATE_LIMIT_WINDOW_MS(default60000)
The distributed rate limiter is bound through wrangler.jsonc as Durable Object RATE_LIMITER.
WITH tvl_data AS (
SELECT json_parse(
http_get('https://your-worker.workers.dev/protocol/aave/tvl/Ethereum?days=30&limit=10')
) as response
)
SELECT
json_extract_scalar(tvl_item, '$.date') as date,
json_extract_scalar(tvl_item, '$.totalLiquidityUSD') as totalLiquidityUSD
FROM tvl_data
CROSS JOIN UNNEST(
cast(json_extract(response, '$.tvl') as array(json))
) as t(tvl_item);WITH tvl_data AS (
SELECT json_parse(
http_get('https://your-worker.workers.dev/protocol/uniswap/tvl/Arbitrum?days=7')
) as response
)
SELECT
json_extract_scalar(tvl_item, '$.date') as date,
json_extract_scalar(tvl_item, '$.totalLiquidityUSD') as totalLiquidityUSD
FROM tvl_data
CROSS JOIN UNNEST(
cast(json_extract(response, '$.tvl') as array(json))
) as t(tvl_item);SELECT json_parse(
http_get('https://your-worker.workers.dev/protocol/curve/chains')
) as available_chains;The proxy returns invalid_protocol_requested when:
- The protocol doesn't exist on DeFiLlama
- The API returns invalid data
- The protocol name is misspelled
Example error response:
{ "error": "Protocol 'invalid-protocol' not found", "requestId": "<request-id>" }Some commonly used protocols:
aave- Lending protocoluniswap- DEXcurve- Stablecoin DEXcompound- Lending protocolmaker- CDP protocolsushi- DEXbalancer- DEXyearn- Yield aggregatorconvex-finance- Yield optimizerlido- Liquid staking
Run locally:
bun run dev
# or npm run dev
bunx wrangler dev src/upgrade.ts
bunx wrangler devThe worker will be available at http://localhost:8787
Test locally:
# Test Aave
curl 'http://localhost:8787/protocol/aave/tvl/Ethereum?days=7&limit=5'
# Test invalid protocol
curl http://localhost:8787/protocol/invalid-protocol/tvl/Ethereum
# List chains for Uniswap
curl http://localhost:8787/protocol/uniswap/chainscurl 'http://localhost:8787/protocol/aave/tvl/Ethereum?days=7'
or
curl http://localhost:8787/protocol/aave/tvl/Ethereum\?days=7
or (zsh-specific)
noglob curl http://localhost:8787/protocol/aave/tvl/Ethereum?days=7Repomix
repomix --style markdown -o _v01-llm.md --verbose --parsable-style --no-file-summary --include src,package.json,dprint.json,tsconfig.json,wrangler.jsonc
repomix --style markdown -o _v01-llm.md --verbose --parsable-style --no-file-summary --ignore "/_dev,/node_modules,/.wrangler,./test,.dev.vars,bun.lock"defi-tvl-proxy/
├── src/
│ └── index.ts # Main worker code
├── package.json # Dependencies
├── wrangler.toml # Cloudflare config
├── tsconfig.json # TypeScript config
└── README.md # This file
- Each request fetches fresh data from DeFiLlama
- Protocol responses are cached and filtered at query time
- Request spikes are controlled with Durable Object distributed rate limiting
- The 4MB limit typically handles several years of daily TVL data
- Default 30-day window results in ~1-2KB responses per chain
If you get invalid_protocol_requested:
- Check the protocol name spelling
- Verify the protocol exists on DeFiLlama
- Use the exact protocol slug from DeFiLlama URLs