REFERENCE / GUIDE
Service rules
Escrowed requests, earned fee shares, retries and refunds on Arc and Robinhood Chain.
Read the repository referenceMeasured completion
In the Arc Testnet load test on 2026-09-18 (https://d20dao.org/benchmarks), isolated requests completed in a median of 2 seconds (4 blocks) and at most 14 seconds; all 500 requests of a burst opened in 5 blocks completed within 27 seconds, and requests arriving at 5 per second completed within 9 seconds. These are testnet measurements of a primary and a backup keeper at one point in time, not a guarantee or rolling average. Epoch readiness, load and network conditions affect actual timing. The script and raw results are at https://github.com/d20dao/benchmarks, and request and fulfillment blocks can be checked in the Explorer. The onchain acceptance and refund threshold remains 60 seconds. On Robinhood Chain a typical delivery takes 5–8 seconds.
60-second acceptance deadline
A valid proof must be accepted onchain at or before request timestamp plus 60 seconds. This is a timestamp rule, on both networks, not a guaranteed number of blocks or delivery SLA. On Arc, epoch publication and target-block waiting consume that same window. Crossing an epoch boundary does not shorten an existing request's deadline. A request can be accepted before its epoch packet is published and remain unfulfilled if publication or proof acceptance does not complete. While no fresh drand round can be obtained no epoch is published, because the drand catalog has no fallback source; affected requests expire and their escrowed fee is refundable on the usual terms.
Fee settlement and callback delivery
Accepted proof earns the configured keeper and treasury shares, including when the callback fails. Submitting a proof stays permissionless: any wallet can submit one, and the registry's authorization decides who receives the keeper share, not who is allowed to submit. On Arc the keeper share goes to the submitting wallet when the registry authorizes it as the committer or a backup committer, and to the committer for any other submitter; on Robinhood Chain, to the submitter when it is an allowed backup keeper, and otherwise to keeper(). Failed transfers become backed credits. Shares are computed from each request's escrowed fee. Keeper shares: Arc Mainnet 60% (keeperFeeBps 6000), Arc Testnet 50% (keeperFeeBps 5000), Robinhood Chain 80% (keeperFeeBps 8000), Robinhood Chain Testnet 80% (keeperFeeBps 8000). The owner can change any of them, so none is a permanent pricing promise. Administered recipients and split can change. Delivery retry uses the same stored word and does not earn another service fee. Failed callbacks do not qualify for the unfulfilled-request refund.
Refund transactions
After expiry without an accepted proof, the escrowed fee times the refund ratio snapshotted at request time is refundable to the fixed recipient. The ratio is 100% by default; the owner can lower it to no less than 50% for future requests only, and the remainder stays with the service. A transaction is required; gas and application fees are excluded. Publication is not permission to spend unfulfilled-request escrow, and fees cannot be earned merely by submitting a pending proof. A rejecting refund recipient can receive a backed credit. Inspect request, refund and credit state before retrying a claim.
Optional refund notification
The current consumer source supports authenticated onRefund(requestId), after the fixed recipient has been paid or credited. Override _onRefund for a bounded application update within the initial 100,000-gas budget. Failed notification does not undo the refund; retryRefundCallback retries only notification, without another payment. Reentry into coordinator request, refund and retry paths is blocked. Verify the deployed implementation supports this hook before relying on it; a new SDK does not upgrade an existing proxy.
Work with your agents
Copy a task-specific prompt with the protocol references and integration rules.
View prompt
Review and implement my application's D20DAO request lifecycle: pending publication, proof acceptance, callback delivery, same-word retries, expiry, refund credits and optional refund notification. Keep RNG fees separate from application payments. Read these public references first; do not guess signatures, addresses or limits: - This guide: https://d20dao.org/docs/service-rules (full text of every guide: https://d20dao.org/llms-full.txt, agent guide: https://d20dao.org/agents.md) - SDK README and AGENTS.md: https://github.com/d20dao/d20-sdk (also inside the installed package). It lists the randomness options, callback gas bounds, how to wait for results, compiler setup and gas needs for refunds and retries. - Protocol source (contracts and replay library): https://github.com/d20dao/d20-sdk/tree/main/protocol, pinned to commit 98e537fb249dd0d3365b8d78e6040a9323a65a88 by PROTOCOL-PROVENANCE.json - Deployment manifests: https://d20dao.org/deployments/arc-mainnet.json, https://d20dao.org/deployments/arc-testnet.json, https://d20dao.org/deployments/robinhood-mainnet.json, https://d20dao.org/deployments/robinhood-testnet.json - Integration skills and templates: https://github.com/d20dao/skills (d20-consumer: methods.md, RandomnessConsumer.sol, mappings.mjs) - Explorer for checking requests: https://d20dao.org/explorer (arc.d20dao.org for Arc Mainnet, arc-testnet.d20dao.org for Arc Testnet; Robinhood requests are read from the chain) - Agent API, for agents and services without a contract: https://d20dao.org/docs/agents (0.05 USDC per call over x402) If a link is unavailable, use the installed package's README, AGENTS.md, ABIs and protocol sources. Networks: Arc Mainnet chain 5042 (live, USDC; RPC https://rpc.mainnet.arc.io; explorer https://explorer.arc.io); Arc Testnet chain 5042002 (build and test here first, USDC; RPC https://rpc.testnet.arc.io; explorer https://testnet.arcscan.app); Robinhood Chain chain 4663 (live, ETH; RPC https://rpc.mainnet.chain.robinhood.com; explorer https://robinhoodchain.blockscout.com); Robinhood Chain Testnet chain 46630 (build and test here first, ETH; RPC https://rpc.testnet.chain.robinhood.com; explorer https://explorer.testnet.chain.robinhood.com). Native USDC on Arc and ETH on Robinhood Chain have 18 decimals. The consumer interface is the same on both; Arc serves requests through epochs, Robinhood Chain binds each request to a future drand round. Compile with Solidity 0.8.28 and EVM version cancun, importing contracts from the installed @d20dao/vrf-sdk package. Take the coordinator proxy address from the manifest of the network you target and check that its implementation matches the manifest. Any consumer contract can request; there is no allowlist, and EOAs cannot request. Requests and fees: use the D20VRFRequests helpers from the SDK for every randomness option (raw word, dice, custom dice, coin flip, ranges, choose one or many, shuffle). Never hardcode the fee. In a contract, quote with quoteFee(callbackGasLimit) inside the requesting transaction. Off chain, quote with quoteFeeAt(callbackGasLimit, latest block baseFeePerGas) plus a buffer, or the SDK's quoteRequestFee with an ethers v6 provider, because eth_call reports a base fee of 0. Choose one payment pattern deliberately: collect a buffered quote from the user, pay the exact fee from the contract and return the change; or forward msg.value and accept that the excess becomes refund credit of the refund address. Results: store the delivered word or mapped result in your consumer when the authenticated callback arrives, keyed by request ID, and have the application read that state. Off chain, wait for the coordinator's fulfillment events or poll getRequest (getRoundRequest on Robinhood Chain); the SDK documents the fields and mapped-result readers. A browser app must bundle the ESM package. Delivery usually takes a few seconds; measured Arc Testnet completion times, including under burst load, are at https://d20dao.org/benchmarks (observations of the testnet keepers, not an SLA). On Robinhood Chain a typical delivery takes 5–8 seconds. An unserved request can be refunded strictly after its 60-second deadline at the refund ratio fixed when it was requested. Give refund and callback-retry transactions explicit gas limits as documented. Keep callbacks small and authenticated through D20VRFConsumer, and never request randomness from inside a callback. An accepted proof with a failed callback is paid service: retry the same stored result, never reroll. Optional _onRefund(requestId) means the refund recipient was paid or credited, not that the consumer received funds, and notification retries must not pay twice. Keep application assets and settlement separate from RNG fees. For verification, keep the original epoch packet, request and target context and accepted proof evidence. Mathematical replay alone does not prove chain inclusion; check receipts and the implementation history too. Implement only the requested changes. Do not ask for keeper, VRF, deployer or bot secrets, and do not send funded or mainnet transactions without my explicit authorization. Compile, run lifecycle tests on a local chain or a testnet, then report changed files, results, anything unverified, and any documentation that was unclear or missing.