Request from a script
Send the address first. If the faucet answers 428, it has included a challenge in the body: find an answer whose sha256 of challenge:answer starts with difficulty zero bits (about a second of CPU), then send the same request again with challenge and answer. Anything else is paid or refused with a code and, for rate limits, a retry_at.
curl
curl -sS https://bryanlabs.net/api/networks/v1/faucet/provider/request \
-H 'content-type: application/json' \
-d '{"address":"cosmos1..."}'
# 200 {"txhash":"...","explorer_url":"...","amount_display":"10 ATOM",...}
# 428 {"code":"pow_required","challenge":"...","difficulty":18,"expires_at":...}Python, with the challenge handled
import hashlib, json, sys, urllib.request
API = "https://bryanlabs.net/api/networks/v1/faucet/provider"
def post(body):
req = urllib.request.Request(f"{API}/request", data=json.dumps(body).encode(),
headers={"content-type": "application/json"})
try:
with urllib.request.urlopen(req) as r:
return r.status, json.load(r)
except urllib.error.HTTPError as e:
return e.code, json.load(e)
def solve(challenge, difficulty):
prefix = (challenge + ":").encode()
n = 0
while True:
digest = hashlib.sha256(prefix + str(n).encode()).digest()
bits = int.from_bytes(digest[:4], "big")
if bits >> (32 - difficulty) == 0:
return str(n)
n += 1
address = sys.argv[1]
status, data = post({"address": address})
if status == 428 and data.get("code") == "pow_required":
answer = solve(data["challenge"], data["difficulty"])
status, data = post({"address": address, "challenge": data["challenge"], "answer": answer})
print(status, json.dumps(data, indent=2))Each address is paid once per window; check GET /status for the amount, the window, and whether the faucet is dispensing before a batch. Difficulty above 24 bits never happens, and a first request from a network the faucet has not seen lately is paid with no challenge at all.