Generated Computers
Locals: an Apple Silicon engine that runs local LLMs up to 3x faster. A product of Generated Computers.
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Celo Testnets Faucet
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗This Repo contains the code for the celo testnets faucet. This is contained in 2 apps.
The firebase app contains functions which do the actual fauceting.
The web app contains a UI for making requests.
The web app deploys automatically to vercel.
The deploy-chains gh actions deploys functions to staging and production environments from staging and master branches respectively
Note other branches are not deployed automatically but can be by manually triggering the flow
To set up the web app to run locally:
navigate to the apps/web folder
$ cd apps/web
link your local repository to the faucet project on Vercel
$ yarn dlx vercel@latest link
You'll be asked to authenticate with your Vercel account. Once you've done that, you'll be
guided through a series of prompts to link your local project to the faucet Vercel project.
? Set up “~/Documents/celo-org/faucet/apps/web”? [Y/n] y
? Which scope should contain your project? Celo Ecosystem Project Hosting
? Link to existing project? [y/N] y
? What’s the name of your existing project? faucet
✅ Linked to c-labs/faucet (created .vercel)
fetch environment variables from Vercel
$ yarn dlx vercel@latest env pull
If you get an error like Error! No project found, you may need to run vercel link again.
If everything worked, you should see a message like this:
> Downloading `development` Environment Variables for Project faucet
✅ Created .env.local file [249ms]
run the app locally
$ yarn dev
You should see a message like this:
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
info - Loaded env from /Users/arthur/Documents/celo-org/faucet/apps/web/.env.local
You can now view the app in your browser at http://localhost:3000.
To set up the firebase app to run locally:
apps/firebase folder
$ cd apps/firebase
$ yarn dlx firebase-tools@latest login
You'll be asked to authenticate with your Firebase account.$ yarn run preserve
engines.node in
firebase/package.json. Currently this is Node 24 at the time of writing.
$ nvm use <the-required-node-version>
$ yarn run serve
The browser flow is gated on reCAPTCHA v3, which scores headless callers badly and cannot be solved without driving a real browser. Scripts and AI agents use an API key instead.
This section used to be the only place the API was documented, which meant an agent had to fetch and parse a README on GitHub to learn how to behave. The same contract is now published on the faucet's own domain, in formats meant to be read by a machine:
| File | For |
|---|---|
/openapi.json | The schema. Endpoints, request and response shapes, every error code. |
/llms-full.txt | The full reference as prose, for assistants that read rather than call. |
/llms.txt | The short index. |
Keep this section and those files in agreement. apps/web/tests/geo-assets.test.ts
asserts the published limits and payout amounts still match the constants the
code enforces, but the prose is on you.
Sign in with GitHub at /keys and create one.
The key is shown once and only a hash of it is stored, so it cannot be
recovered — create a new one if you lose it. You may hold up to 2 keys and they
expire after 90 days.
A key minted the way above is a human's credential handed to an agent. The faucet cannot tell one agent from another, or an agent from the person running it, because its only notion of identity was a GitHub account — and an agent cannot hold one.
An agent registered under ERC-8004 has an identity of its own, so it can mint its own key. Two calls, no browser, no OAuth, no human:
# 1. Ask for a challenge.
curl -X POST https://faucet.celo.org/api/keys/challenge \
-H 'Content-Type: application/json' \
-d '{"agentId":"2"}'
# → {"message":"…","nonce":"…","expiresAt":…,"agentWallet":"0x…"}
# 2. Sign that message with the agent wallet, then exchange it.
curl -X POST https://faucet.celo.org/api/keys/agent \
-H 'Content-Type: application/json' \
-d '{"agentId":"2","nonce":"…","signature":"0x…"}'
# → 201 {"key":"cfk_prd_…","record":{…}}
The key is bound to the agent id rather than to a person, so it draws on the agent's own daily allowance. That allowance grows with the age of the registration: an agent registered less than 7 days ago gets 2 requests a day, and an established one gets 10, the same as a signed-in person. Registering an agent costs a fraction of a cent, so without this one wallet could mint twenty identities and fill the shared programmatic ceiling on its own. The tier is decided at request time from the registration timestamp recorded on the key, so an agent grows into the larger allowance without minting a new key.
To revoke, ask for a challenge with "action":"revoke" and send the proof to
DELETE /api/keys/agent with the keyId. Omit keyId to revoke every key the
agent holds, which is the recovery path after a signing-key compromise: the
attacker's keys were never shown to the rightful agent, so it cannot name them.
A challenge names its action in the signed text, so a mint signature cannot be
turned into a revoke or the other way round.
Design notes, since each of these is load-bearing:
0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 on
chain 42220. Registering on Celo Sepolia costs Sepolia gas, which is what this
faucet hands out — a testnet registry would let an attacker faucet its way to
as many identities as it wanted.ownerOf. An agent whose getAgentWallet is unset is
refused with agent_wallet_unset. ownerOf is whoever holds the NFT, often a
human or a multisig, so accepting it would authenticate the operator while
reporting that an agent had signed. Agent 1 on mainnet is in exactly this
state today, so this is the common case, not an edge one.Sybil resistance is unchanged and deliberately modest: mainnet registration costs only gas. What bounds exposure is the programmatic ceiling that already existed — 20 requests per 10 minutes and 200 per day across every key. See discussion #286 for the x402 and reputation phases that turn "capped" into "costly".
Verify the whole path against a deployment with no cookie jar at all. You need
the signing key of a registered agent's wallet. If you do not hold one, register
a throwaway agent first: every register() overload in the registry sets the
agent wallet to the calling address, so one transaction from any wallet you
control (a fraction of a cent of mainnet CELO) gives you an agent id whose key
you already have.
export AGENT_SIGNING_KEY=0x... # any wallet with a little mainnet CELO
yarn --cwd apps/web register:smoke-agent # prints the new agent id
yarn --cwd apps/web smoke:agent-key \
--url https://faucet.celo.org --agent-id <id> --beneficiary 0xYourAddress
Neither script prints the key, and neither falls back to any other wallet
variable: to sign with a key held under a different name, set
AGENT_SIGNING_KEY_ENV to that name. The smoke run revokes the key it minted at
the end, so it leaves the agent's two slots as it found them and exercises the
revoke path live.
Send the key as a bearer token and omit captchaToken:
curl -X POST https://faucet.celo.org/api/faucet \
-H "Authorization: Bearer cfk_prd_…" \
-H 'Content-Type: application/json' \
-d '{"beneficiary":"0xYourAddress","network":"celo-sepolia"}'
A successful call returns HTTP 200 with {"status":"Pending","key":"…"}. The
queueing is carried by the status field, not by the status code: the payout is
accepted but not yet settled. Poll for the outcome with that key:
curl "https://faucet.celo.org/api/status?key=<key>&network=celo-sepolia"
# {"status":"Done","beneficiary":"0x…","txHash":"0x…"}
Other responses carry a machine-readable error code so you can branch without
parsing prose:
| Status | error | Meaning |
|---|---|---|
400 | — | Invalid network or beneficiary address |
401 | invalid_api_key | Missing, malformed, unknown or expired key |
401 | api_key_disabled | Programmatic access is switched off |
429 | faucet_limit_exceeded | Rate limited; honour Retry-After |
503 | faucet_unavailable | A dependency is down; honour Retry-After |
405 | — | Wrong HTTP method |
The browser flow keeps its existing 403 for rate limits; 429 is used only on
the key path, matching the Coinbase CDP faucet.
Never commit a key. Keys found in public repositories are revoked without notice. If you are integrating a tool that others will install, read the key from the user's environment — do not ship a default.
Environment variables on the web app:
| Variable | Required | Purpose |
|---|---|---|
FAUCET_API_KEY_PEPPER | yes | Secret mixed into the HMAC of every stored key. Without it, key minting and verification both fail closed. Rotating it invalidates every existing key. |
FAUCET_API_KEY_NETWORKS | no | Comma-separated networks that accept key auth. Defaults to celo-sepolia. |
PROGRAMMATIC_GLOBAL_DAILY_LIMIT | no | Daily ceiling across all keys. Defaults to 200. |
PROGRAMMATIC_BURST_LIMIT | no | Keyed requests allowed per 10 minutes across all keys. Bounds arrival rate so the payout pool cannot be locked. Defaults to 20. |
To stop all programmatic traffic immediately without a deploy, set the
api-keys:disabled key in Upstash to any truthy value. The browser flow is
unaffected. Delete it to re-enable.
apps/web/scripts/smoke-api-key.mjs exercises the whole key path over HTTP —
rejection of unissued keys, address and method validation, a real payout, the
status poll, and the returned tx hash. It needs no repo credentials:
export FAUCET_API_KEY=cfk_... # minted at <deployment>/keys
yarn --cwd apps/web smoke:api-key \
--url https://<deployment> --beneficiary 0xYourAddress
It exits non-zero if any check fails and never prints the key.
Every other test mocks the sender, so nothing otherwise proves the hash written
to goldTxHash is a real transaction. apps/firebase/src/celo-adapter.onchain.test.ts
sends a real transfer on Celo Sepolia. It is skipped unless explicitly opted in,
because it spends gas:
RUN_ONCHAIN_TESTS=1 PRIVATE_KEY=<funded key> \
yarn --cwd apps/firebase test:ci onchain
The transfer is a self-send, so only the gas fee (~0.0011 CELO at the 50 gwei floor) is consumed, and the test asserts the balance falls by exactly that fee.
Keys are self-serve on purpose. Allowlisted keys need a human to triage each request and hand the secret over out of band, which does not scale and tends to leave secrets in chat logs. Tying keys to a GitHub account instead reuses an identity the faucet already understands, which is also what the Coinbase CDP, Circle, and Chainstack faucets do.
If you are testing contracts in CI you probably do not want the faucet at all.
anvil --fork-url https://forno.celo-sepolia.celo-testnet.org gives you
pre-funded accounts against forked state, with no rate limits and no network
flakiness. Reach for a key only when you need funds on the real testnet.
Add the chain config and token info to config/chains.ts.
Add chain name to the networks array, and ChainId and FaucetAddress to enums in types/index.ts.
Dispatch the deploy-chains workflow. ensure chain name is kebab case and matches a network in config/chains.ts.