Search projects, hackathons, sponsors and tech

    ← All projects

    Retainer

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

    Demo

    About

    An agent can pay for something. An agent cannot subscribe to something. Every payment rail built for agents charges per request: 402, sign, retry, pay, repeat. That works for one call. For anything an agent needs continuously, a human keeps re-authorising it — by clicking, or by operating a cron job somebody has to keep alive. There is always a person behind the subscription. Retainer removes that person. It is a live x402-gated service on Hedera testnet, settled through the Blocky402 facilitator. An agent pays once. The server forwards that settled payment on-chain into a contract, which opens a subscription and arms a scheduled renewal through the Hedera Schedule Service (HIP-1215, the system contract at 0x16b). When the access window closes, the network itself calls renew() on the contract. No user. No server job. No cron. The network has renewed access 55+ times across 3 deployments with nobody awake, and is still doing it hourly. What it cost to learn, said out loud rather than hidden: - The network charges the CONTRACT for each scheduled call, so the contract must hold gas to pay for its own future execution. Retainer books three separate pots: refundable to the subscriber, earned by the seller, and gas reserved for the next renewal. - A renewal that re-arms the next one costs ~1.55 HBAR; one that does not costs ~0.05. Re-arming is ~97% of the cost, so at 1 HBAR per period this loses money on every renewal. That is the real economic constraint of on-chain self-renewal. - One scheduled renewal reverted with our own Insolvent() guard when the three pots came within ~2.4 HBAR of the account balance. The contract correctly refused to spend money it had already promised elsewhere. It is disclosed as a limitation on /judge. Live: https://retainer.edycu.dev · For judges, 30 seconds: https://retainer.edycu.dev/judge Contract 0.0.10415845 / 0x433050c9bd203FBdd49FAB6b5E20eD3E1FB2a931

    How it's made

    Solidity contract (RetainerAccess) on Hedera testnet, a Next.js 15 App Router front end, and a TypeScript agent script, from the Scaffold-HBAR template as boilerplate. The engine is the Hedera Schedule Service. The contract books its own next execution through HIP-1215, the system contract at 0x16b, using three of its methods: scheduleCall arms the next renew() at the exact second the window closes, deleteSchedule releases the booking on cancel so reserved gas returns rather than being stranded, and hasScheduleCapacity asks the network whether the slot can be booked before committing — without that pre-check a full network turns a clean lapse into a revert. Tested locally against @hashgraph/system-contracts-forking, which is what made a system contract testable in CI at all. Payments are x402 over HBAR via @x402/core and @x402/hedera, settled through the Blocky402 facilitator. Blocky402 advertised hedera:testnet with scheme exact and x402Version 2 on the standard /supported contract, so it dropped into the template's HTTPFacilitatorClient with no adapter — the swap was one environment variable — and it supplies its own fee payer, which removed a whole account from our setup. Wallet connection is native Hedera through @hashgraph/hedera-wallet-connect and Reown AppKit on the hedera namespace, not an EVM-address shim, so the account a user sees is a real 0.0.x id. The hacky parts worth naming: 1. The agent signs exactly once. Rather than have it sign again to subscribe, the resource server takes the payment it just received and forwards it on-chain itself, so one signature becomes a self-sustaining subscription. Two transactions come back: the payment, and the subscription it became. 2. Two different units for the same money. HBAR value on the wire is weibar (1e18) while the EVM sees tinybar (1e8), and getting that boundary wrong silently mis-prices everything. It is pinned by property tests that check every tinybar amount from 0 to 100,000 exhaustively, plus 100,000 randomised amounts across the whole uint64 range. 3. A contract that pays for its own future needs an accounting model, not a balance. Three pots — refundable, earned, gas reserve — because "the contract has money" and "the contract can afford its next scheduled call" are different questions. We learned that from a live revert. 4. The payment and the access it buys are two unrelated rows on the ledger. An x402 settlement is a CRYPTOTRANSFER and the subscribeFor it pays for is a CONTRACTCALL; nothing on Hedera ties them together. Both are now written to a Hedera Consensus Service topic (0.0.10440194, immutable, no admin key) sharing a settlement id, so the join is public. Writing it surfaced the hacky bit: the two records for one request can reach consensus in either order, so the verifier joins on settlement id rather than sequence number. It is off unless configured and can never reject a payment — an HCS outage must not cost a paying agent its access. 5. The mirror node cannot see the thing being verified. Schedules a contract creates via scheduleCall do not appear under /api/v1/schedules, and /api/v1/contracts/{id}/results omits scheduled executions entirely — the first version of our verifier queried that endpoint, reported no renewals found, and looked entirely correct while doing it. Read the account's transactions, not the contract's results. 64 contract tests, 258 app unit tests including the property suite, and 58 end-to-end tests. The punctuality is measured rather than claimed: yarn bench needs no keys and reports that across all 30 renewals this deployment had armed as of the dated run on 2026-09-09, the network executed the scheduled call a median 64 ms — p95 151 ms — after the second it was asked for.