Skip to content
x402 · exactHedera testnetHIP-1215 · 0x16b

Your agent’s access renews itself on-chain at 3am, with nobody awake.

An x402-gated feed on Hedera. One payment, signed once; the Hedera Schedule Service renews the window.

For judges · 30 s
REPLAY · 2026-09-07 · 0.0.10406083 · 10× time
Countdown 01:00.
19renewals the network executed by itself — three deployments, every one scheduled=true · SUCCESSmirror node · 3 + 7 + 9 · 2026-09-08
~30×1.54896 ℏ to renew and re-arm, 0.0507 ℏ to renew without — re-arming is ~97% of the costdocs/proof.md · first run; current deployment repeats it at 1.5404 / 0.0522 ℏ
scheduled=truethe ledger's mark for a call nobody submittedmirror node · CONTRACTCALL · SUCCESS
64 + 258contract tests + resource-server tests passingyarn hardhat:test · yarn next:test

How it works

402 → pay → 200 → still 200.

The ordinary x402 pattern charges on every request: 402, sign, retry, pay, repeat forever. That works for one-off calls and breaks for anything an agent needs continuously — somebody has to keep paying, so somebody has to stay awake. Here the gate is an on-chain subscription that the network renews.

  1. 01GET /api/retainer/access → 402

    A cold agent is charged

    The route reads hasAccess(agent) on-chain, gets false, and answers with an x402 challenge: scheme: exact, network: hedera:testnet, native HBAR.

  2. 02PAYMENT-SIGNATURE → settled by Blocky402

    It signs one payment

    Verified and settled through the hosted Blocky402 facilitator. This is the only thing the agent ever signs.

  3. 03subscribeFor(agent) · scheduleCall(0x16b)

    The payment becomes on-chain state

    The server forwards what it received into RetainerAccess, which charges period one and arms the first renewal with the Hedera Schedule Service.

  4. 04GET … → 200 · paidThisRequest:false

    Still 200 after the window expired

    Between the two requests the network executed renew() itself — CONTRACTCALL, scheduled=true. Nothing was paid, nobody was awake, no cron ran.

The window, live

Every number here is a chain read.

/api/retainer/status asks the contract and nothing else, so this can be polled without ever touching the payment path. Paste an address in the instrument above, or watch the demo agent.

No agent selected. The meter, the balance, the pending schedule and the event log appear here as chain state.

Proof

Check it on Hedera yourself, not on our word.

scheduled=true on a SUCCESS CONTRACTCALL is the ledger saying the transaction had no submitter. The run below is the one the instrument replays: the contract paid for its own executions, re-armed itself twice, and stopped loudly when the money ran out.

The recorded run on 0.0.10406083 — read back from the public mirror node, 2026-09-07. Timestamps open HashScan.
ConsensusUTCTypescheduledChargedWhat the contract said
1788780167.77145365711:22:47ETHEREUMTRANSACTIONfalse1,582,554 gasSubscriptionStarted · period 60s · 4 ℏ funded · RenewalScheduled 0.0.10406098
1788780226.01636620811:23:46CONTRACTCALLtrue1.54896 ℏRenewed · paid 1 ℏ · balance left 2 ℏ · RenewalScheduled 0.0.10406108
1788780286.01973520811:24:46CONTRACTCALLtrue1.54896 ℏRenewed · paid 1 ℏ · balance left 1 ℏ · RenewalScheduled 0.0.10406116
1788780346.34541884211:25:46CONTRACTCALLtrue0.0507 ℏRenewed · paid 1 ℏ · balance left 0 · Lapsed("balance will not cover the next period") · no schedule
The current deployment, 0.0.10415845 — the same loop on the deployed source, 90s periods, read back 2026-09-08. One scheduled execution reverted; the run that followed is eight renewals by the network, the last one lapsing.
ConsensusUTCTypescheduledChargedWhat the contract said
1788840325.13528220804:05:25CONTRACTCALLtrue1.54327368 ℏRenewed · after a 3 ℏ x402 payment opened the window · re-armed 0.0.10416101
1788840415.07812180204:06:55CONTRACTCALLtrue0.0654 ℏCONTRACT_REVERT_EXECUTED Insolvent() — the contract’s own solvency guard rejected the network’s call. Limitation 03.
1788844245.40639373205:10:45ETHEREUMTRANSACTIONfalse1,481,020 gasrenew() sent by the seller after creditFor(+8 ℏ) — the restart · RenewalScheduled 0.0.10416711
1788844334.06956582305:12:14CONTRACTCALLtrue1.54036168 ℏRenewed · re-armed 0.0.10416728
1788844424.14749969305:13:44CONTRACTCALLtrue1.54036168 ℏRenewed · re-armed 0.0.10416743
1788844514.03117120805:15:14CONTRACTCALLtrue1.54036168 ℏRenewed · re-armed 0.0.10416751
1788844604.06210318905:16:44CONTRACTCALLtrue1.54036168 ℏRenewed · re-armed 0.0.10416761
1788844694.15296220805:18:14CONTRACTCALLtrue1.54036168 ℏRenewed · re-armed 0.0.10416782
1788844784.02199177305:19:44CONTRACTCALLtrue1.54036168 ℏRenewed · re-armed 0.0.10416798
1788844874.08784567205:21:14CONTRACTCALLtrue1.53536968 ℏRenewed · re-armed 0.0.10416816
1788844964.08562720805:22:44CONTRACTCALLtrue0.0522288 ℏRenewed · balance 0 · Lapsed("balance will not cover the next period") · no schedule

The recorded run, whole chain, one request

curl -s "https://testnet.mirrornode.hedera.com/api/v1/transactions/0.0.7314364-1788780163-271854529" \
  | jq -r '.transactions[] | [.consensus_timestamp, .name, "scheduled=\(.scheduled)", .result, "fee=\(.charged_tx_fee)"] | @tsv'

The current deployment's eight renewals, one request

curl -s "https://testnet.mirrornode.hedera.com/api/v1/transactions/0.0.7314364-1788844238-651641588" \
  | jq -r '.transactions[] | [.consensus_timestamp, .name, "scheduled=\(.scheduled)", .result, "fee=\(.charged_tx_fee)"] | @tsv'

The scheduled calls inherit the transaction id of the EVM call that armed the first schedule, so one response holds that call, every renewal it led to and every SCHEDULECREATE between them.

Three deployments exist — the recorded run’s 0.0.10406083, an intermediate 0.0.10414167, and the current one — and they are not the same code. docs/proof.md keeps them apart and says exactly where they differ.

Contract on HashScan: 0.0.10415845

Consumable by an agent

The same gate, as MCP tools.

The API publishes an OpenAPI 3.1 document at /openapi.json. Registering it with Bazantic produces an HTTP gateway and, from the same document, an MCP server — the tool descriptions an agent reads are that document’s own description strings, verbatim. The spec is the interface; nothing is written twice.

A second gateway wraps one endpoint of Hedera’s Mirror Node as the tool findScheduledExecutions. It is deliberately unpublished: that API is Hedera’s, not ours.

Four tools, from the spec

getAccess · getStatus · info · externalDocs, priced per method: the paid call at 1000 millicents, the chain read at 0. The same asymmetry the contract has.

The gateway is published to Bazantic’s marketplace at retainer-x402.bazgateway.com, currently pending verification.

A recipe that checks the claim

It reads the seller’s own getStatus, then asks Hedera whether the renewal that claim rests on was executed. The vendor asserts; the network confirms.

verification_result verified · access_status true · scheduled_renewals_found 8 in a ten-transaction window · 1788941916.005290514

The endpoint that cannot see a self-renewal

Building it surfaced a finding worth carrying: /api/v1/contracts/{id}/results does not return scheduled executions — it lists calls that arrived as an EthereumTransaction, and a renewal the Schedule Service executes never was one. The scheduled renewal at 1788940215.030907876 was absent from that endpoint’s twenty newest results when measured on 2026-09-09, and is plainly present under /api/v1/transactions?account.id=0.0.10415845 as CONTRACTCALL with scheduled: true. The first version of the recipe queried it, reported none found, and looked entirely correct while doing it. Read the account’s transactions, not the contract’s results.

Questions a judge asks

Answered from the docs, not from the pitch.

Is anything on this page simulated?
No. Live mode is /api/retainer/status, a chain read. The recorded run is four transactions from the public mirror node; each row and each chip links to HashScan. There is no offline, mock or demo mode for the product.
What does the agent sign?
One x402 payment — a Hedera TransferTransaction under the exact scheme, settled by the Blocky402 facilitator. Renewals are CONTRACTCALLs the network executes from a schedule; scheduled=true is the ledger saying there was no submitter.
Who pays for a renewal?
The contract, from its own gasReserve. One re-arming renewal cost 1.54896 ℏ on testnet; at 1 ℏ per period the seller loses money on every renewal. That is stated in the README and on /judge, not hidden.
What happens when the money runs out?
The renewal charges the last period, emits Lapsed("balance will not cover the next period") and does not re-arm. The last row of each ledger above is that event — 0.0507 ℏ on the recorded run, 0.0522 ℏ on the current deployment — with no SCHEDULECREATE after it. Loud, not silent. It does not restart itself either: from there renew() reverts NotSubscribed(), and opening a subscription again is the way back.
Which Hedera Schedule Service calls are load-bearing?
Three: scheduleCall arms the renewal, hasScheduleCapacity is asked before arming so a full second becomes a clean Lapsed rather than a silent stop, and deleteSchedule returns the held gas on cancel(). Remove any one and the product breaks rather than degrades.

What this does not claim

Four real limitations. None is fixed here.

  1. 01

    It loses money at the default price.

    A renewal burns ~1.55 ℏ of the seller’s gas reserve to collect 1 ℏ. Pricing a period above the renewal cost is a product decision this build did not make.

  2. 02

    The metering write is fire-and-forget.

    The allowance is enforced by simulating meter(), but the recording transaction is not awaited. A burst can overshoot by roughly the number in flight.

  3. 03

    One scheduled renewal reverted on the deployed source.

    At 04:06:55 the network fired renew() and the contract’s own Insolvent() guard rejected it; the run had to be restarted by hand. The numbers point at the gas Hedera reserves on the payer during a scheduled call. Not fixed here.

  4. 04

    A lapse cannot restart itself.

    Once active is false the contract will not re-arm: renew() reverts NotSubscribed() and fund() only adds money. Opening a subscription again is the way back, so the unattended part runs exactly as far as the funding does.

For whoever is judging this

The 30-second read: the claim, four commands, the measured costs, and the limitations.

No account, no key, no clone. Everything runs against the live deployment and the real Hedera testnet.

contract 0.0.10415845 · retainer.edycu.dev · v1.5.3