面向开发者 / 应用 API
水龙头
唯一一个会写到链上的第一方服务。它持有运营者密钥并替你提交那次滴水,这正是它不需要钱包的原因,也是为什么配额是调用者和那把密钥之间唯一的东西。
它做什么
你 POST 一个地址;服务检查它自己的配额,用运营者密钥签一次对水龙头合约的调用,提交它,并在 作答之前等到回执。页面上没有钱包,也没有来自你的签名,因为那笔交易不是你的。
不需要认证,而它花的是一把真密钥
没有令牌,没有验证码,没有签名。顶替认证的是三份在任何东西被签名之前就已预留的 配额,外加一个由合约自己强制的冷却期,所以一个绕过了其中一个的调用者仍然会撞上另一个。这里 没有任何东西能证明关于你是谁的任何事。
它的两条路由也在项目主站来源上被重新暴露了一次,滴水和状态,这样那里的页面不必做跨源调用就能 用它。
基础 URL 与 CORS
| 接入点 | Value |
|---|---|
| 公开 | https://faucet.picklechain.xyz这个服务从同一个来源提供它自己的静态页面 |
| 重新暴露的 | POST /drip 和 GET /faucet-status在项目主站来源上,代理到同一个服务 |
| 你自己运行的一套栈 | http://127.0.0.1:3000 |
| CORS | 一份允许名单OPTIONS 回答 204 并允许 POST、GET 和 OPTIONS;不在名单上的 Origin 被以 403 拒绝 |
凡不在 API 路由上、也不在那份明确的静态允许名单上的东西,都是 404,绝不是 403,因为一个区分 这两者的拒绝就等于确认了一个文件存在。
路由
/status
GET- Params
- address (optional)
- 返回
- {faucet, pickle, ethAmount, bxAmount, ethAmountEth, bxAmountBx, treasuryEth, treasuryBx, treasuryEthFmt, treasuryBxFmt, cooldown, evmBlock, miniBlock}
The faucet and token addresses, the drip amounts in both base units and display units, what is left in the treasury and the cooldown in seconds. Pass `?address=` and it also answers `canDrip`, `retryIn` and a formatted `retryIn`.
另见路径。 GET /faucet-status
值得注意。 The `bx`-prefixed keys are the PKL amounts. The names are historic and the SERVICE still emits them; the formatted string beside them says PKL. 502 when the node is unreachable, 500 for anything else.
/drip
POST- Params
- body {"address": "0x..."}
- 返回
- {hash, address}
Reserves quota, signs `dripTo` with the operator key, submits it and polls for the receipt before answering. No authentication of any kind.
值得注意。 It waits for the receipt: about three seconds of polling before it gives up with `no receipt yet`. A quota reservation is ROLLED BACK when the send fails, so a failed attempt does not cost you a daily slot.
/addresses
GET- Params
- none
- 返回
- the deployment manifest, as JSON
Streams the manifest file straight through. This is where an application discovers what is deployed.
另见路径。 GET /op-deployment/l2-addresses.json
值得注意。 404 with a JSON body when the file cannot be read, which is also what you get before a deployment has written it.
any
OPTIONS- Params
- none
- 返回
- 204
Allowed methods are POST, GET and OPTIONS; the allowed header is content-type.
值得注意。 403 when an Origin is present and not on the allowlist.
# What is left, and whether this address may claim right now.
curl -s "$FAUCET/status?address=$ADDR" | jq '{canDrip, retryIn, retryInFmt, treasuryEthFmt}'
# The claim. A body is required: a zero-length one answers 413, not 400.
curl -s -X POST "$FAUCET/drip" \
-H 'content-type: application/json' \
-d "{\"address\":\"$ADDR\"}"
# 200 -> {"hash": "0x…", "address": "0x…"}; the receipt has already been seen.配额
Quota is RESERVED before the transaction is signed and committed only once a hash comes back, so two simultaneous requests cannot both pass the check. The journal that backs it is an append-only file outside the served directory, rotated by size and by age, with a checkpoint at the head of each new file so the all-time total survives both rotation and a restart.
| 预算 | Value |
|---|---|
| 按客户端地址 | 每天 5 次以转发来的客户端地址为键 |
| 按被注资的地址 | 每天 2 次以请求体里的那个地址为键 |
| 全局 | 每天 1000 次还有一份独立的总预算 |
| 链上冷却期 | 每个地址一天由合约强制并从链上读取,不是记在服务里的 |
两种不同的拒绝意味着两件不同的事
一个 429 是这个服务自己的每日配额,在换日时重置。一个 409 是 合约的冷却期,是从最近一次滴水算起而不是从午夜算起,并在它的消息里带着要等多久。只有第二种 可以提前看出来:去问 /status?address=,并在 POST 之前读 canDrip 和 retryIn。
The per-address budget is keyed on the FUNDED address and the per-client one on the address the request came from, read from the right-hand end of the forwarded chain. Put a cache in front without telling the service how many proxies it now sits behind and every visitor collapses into one bucket.
错误
| 状态码 | 含义 |
|---|---|
| 400 | invalid json, invalid address, invalid content lengthand a chunked request, which the handler refuses outright |
| 409 | cooldownthe message carries the interval to retry in. The cooldown is enforced by the contract, one day per address, and is read from the chain rather than remembered here |
| 413 | payload too largethe cap is 4096 bytes - and a ZERO-LENGTH body answers 413 as well, which reads as the opposite of what happened. Send a body |
| 429 | quota exceeded5 a day per address seen, 2 a day per funded address, 1000 a day globally; the message says which one you hit |
| 502 | upstream RPC unavailablethe node did not answer. Nothing was signed |
| 503 | faucet empty, or the drip failedthe message names the remaining balance when it is a funding problem, and is the opaque `drip failed` otherwise |
发送之后的一个 503 不是一次安全的重试
一个 502 意味着节点根本没应答,什么都没被签名,那一个可以放心重试。一个 503 可能意味着交易发出去之后失败了,也可能意味着它发出去了但在轮询窗口之内 没有回执到达。两种情况下配额预留都会被回滚,所以重试是允许的;那笔交易仍可能落地。请去链上 轮询那个地址的余额,而不是去假定。