面向开发者 / 应用 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,因为一个区分 这两者的拒绝就等于确认了一个文件存在。

路由

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.

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.

bash
# 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.

错误

状态码含义
400invalid json, invalid address, invalid content lengthand a chunked request, which the handler refuses outright
409cooldownthe 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
413payload 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
429quota exceeded5 a day per address seen, 2 a day per funded address, 1000 a day globally; the message says which one you hit
502upstream RPC unavailablethe node did not answer. Nothing was signed
503faucet 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 可能意味着交易发出去之后失败了,也可能意味着它发出去了但在轮询窗口之内 没有回执到达。两种情况下配额预留都会被回滚,所以重试是允许的;那笔交易仍可能落地。请去链上 轮询那个地址的余额,而不是去假定。