testnet-10 · 2026-09-24
A coordinator took a job, split it, hired a specialist for each part, and paid each one for its own piece. The rules were enforced by Kaspa rather than by anybody’s good behaviour. This is the whole run, from the first transaction to the last — including the payment that settled and delivered nothing, and how that was recovered without paying twice.
Every figure on this page is read from one-job.json, written by the script that ran it.
The cast · covenant v4 · superseded
The coordinator signs the genesis spend and both delegations and never signs a purchase. Each worker signs its own purchase and nothing else. A fourth key — the stopper — can end any of it at any moment and receives nothing, and no agent here holds it.
All three run the covenant version above — read from the manifests, not typed here. A grant’s script is committed in its address, so a version is not an upgrade: it is a second covenant, and grants issued under the first keep running it until they are reissued. covenant/versions.json maps every fingerprint to its version, and each one is re-derived from its archived template rather than asserted.
The narrowing
The coordinator’s allowlist has two members. Each child was delegated down to one of them — and the child does not merely promise that. It commits to a node of the parent’s allowlist tree and carries the path from that node up to the parent’s root, so the chain can check the narrowing without ever seeing the list. That is why the roots below differ: a different root is the narrowing, visible rather than asserted.
RESEARCH could not have paid the Auditor. VERIFY could not have paid the Researcher. Neither could have paid anyone else at any price, however their code was written.
The sequence
Hiring is serial because a grant is one UTXO: the second delegation’s input is the first one’s output and does not exist until it confirms. Settlement runs backwards because the reserve chain is popped from the end — VERIFY was hired second, so it came home first, and a child settled out of order is refused before anything is built.
| UTC | Step | Transaction |
|---|---|---|
| 11:49:35 | Generated three keys one coordinator, two workers; the stopper is a fourth nobody here holds | — |
| 11:49:36 | Created the coordinator grant 0.8 KAS, two payees, may delegate 2 deep | b5338f8f3fbaa910… |
| 11:49:51 | Opened the batch a local record of what is committed to whom | — |
| 11:49:52 | Delegated to RESEARCH narrowed to 1 of 2 payees, proven by witness | e889c208983f033d… |
| 11:50:09 | Delegated to VERIFY narrowed to the other one, same way | a7f3ea9f5d1c32d9… |
| 11:50:29 | RESEARCH bought its record from the Researcher, at its listed price | 186570c82688f263… |
| 11:57:36 | VERIFY bought the audit paid at 11:50, delivered at 11:57 — see below | e92bd705f3123830… |
| 11:57:38 | Settled VERIFY reserve released, the parent charged what it spent | 1c6b956e4e601101… |
| 11:57:54 | Settled RESEARCH last hired settles first; the chain pops from the end | 290e06f53a5d3936… |
| 11:58:10 | Closed the batch nothing outstanding | — |
| 12:02:45 | Wrote the trace this page is built from it | — |
What was bought
RESEARCH bought a checkable record about kaspanet/silverscript from Warda’s
Researcher. VERIFY bought an audit of covenant/warda_grant.sil from the Covenant
Auditor — so the thing being audited is the thing that enforced the payment. Both
services were already running and neither was told anything about this demonstration.
| UTC | What | Result | Payment | |
|---|---|---|---|---|
| 11:50:24 | research https://github.com/kaspanet/silverscript warda-growth.vercel.app | 200 bought | 186570c82688… | first try |
| 11:50:29 | audit warda_grant.sil warda-node.tailc0c0ec.ts.net:8443 | 502 paid-but-refused | e92bd705f312… | first try |
| 11:53:58 | audit warda_grant.sil warda-node.tailc0c0ec.ts.net:8443 | 409 paid-but-refused | e92bd705f312… | resumed |
| 11:55:13 | audit warda_grant.sil warda-node.tailc0c0ec.ts.net:8443 | 409 paid-but-refused | e92bd705f312… | resumed |
| 11:57:35 | audit warda_grant.sil warda-node.tailc0c0ec.ts.net:8443 | 200 bought | e92bd705f312… | resumed |
VERIFY’s 0.04 KAS reached the Auditor and the report did not come back. The fault was the seller’s: its delivery callback read the covenant off an argument that carries the payment’s metadata, not the request, so it compiled undefined. The free endpoint never had the bug, which is why it survived — the paid path was the only one that could break and the only one never run end to end.
The seller records a payment as spent before it delivers, on purpose: recorded after, a crash leaves a payment that can be replayed forever. So the second attempt was refused as a replay, correctly. Only the operator could undo that — and the buyer never paid twice, because it keeps the proof it was issued and re-presents it rather than buying again.
Fixed, then redeemed: e92bd705f312… paid at 11:50:29 and delivered at 11:57:35 UTC, against the same proof. Four records of one payment, one delivery.
What the network would carry
KIP-9 storage mass counts 1/value over a transaction’s outputs, and a
grant that pays out creates two: the payment, and the grant’s own successor. A covenant
output carries a 32-byte binding that pushes it into a second storage unit and squares its
weight, so the successor dominates. What costs is what the grant has left.
A nearly-empty grant is the expensive one.
This is consensus, not the covenant, and no grant term relaxes it. The per-payment caps below are the sellers’ listed prices to the sompi; the budgets are the smallest amounts the network will let a worker pay out of, with headroom. Every transaction is massed before anything is built.
| Transaction | Storage mass | Against a ceiling of 500,000 |
|---|---|---|
| delegate research | 185,329 | 37% of the ceiling |
| delegate verify | 243,476 | 48% of the ceiling |
| buy research | 262,222 | 52% of the ceiling |
| buy verify | 318,182 | 63% of the ceiling |
| settle verify | 0 | 0% of the ceiling |
| settle research | 0 | 0% of the ceiling |
What this does not show
Everyone joining one agreement in a single step is the shape people usually describe,
and it is what the covenant forbids: #[covenant.fanout(to = 2)] with
require(OpAuthOutputCount == 2) fixes the topology at parent plus
one child. Two workers is two delegations, in two transactions.
Since: it needed the covenant to change, and the covenant
changed. delegate2 hires two in one transaction — below.
A grant is one UTXO, so the second delegation’s input is the first one’s output. Hiring is serial by construction, not by scheduling.
Since: two children out of one input are each their own coin from the same moment, so they are parallel rather than merely quick.
A grant’s payee set is fixed at genesis and a child may only narrow it, so a coordinator can hire from the cast it was created with and nobody else. An agent discovered at run time cannot be paid, at any delegation depth. That is the honest distance between this and an open market, and no amount of tooling closes it — it needs the covenant to change.
Still true. Two of the three above were removed by a covenant change on the day this ran. This one was not, and it is the one that matters most.
The reserve came back. reabsorb requires
newState.reserved == reserved - child.budgetTotal, so settling a worker
restores the coordinator’s capacity to delegate again rather than consuming it for the
grant’s whole life. The cost is ordering: child.reserved == 0 means a
subtree settles from the leaves up, and a long-lived child at the bottom of the chain holds
everything above it.
What changed after this run · covenant v5
The run above is v4, and it stays that way: it is a record of what
happened, not a claim about what is possible today. Two of its three limits were removed
hours later by a new covenant entrypoint, delegate2, and this is that
transaction and the two that unwound it. A different covenant, so a different grant —
nothing above was re-run.
| Hired | Budget | Reserve chain | Agent key |
|---|---|---|---|
| child A | 0.25 KAS | pushed first, settles last | 3333bd46… |
| child B | 0.22 KAS | pushed second, settles first | fb3e774e… |
One input, three outputs, one signature. The coordinator keeps its change and reserves the rest: reserved coin has left the coordinator’s reach without leaving its budget, which is what makes the next part possible.
reabsorb gives it back.| Transaction | What it did | On chain |
|---|---|---|
| genesis | 0.8 KAS, nothing delegated | b488d1e3492e2a03… |
| delegate2 | two children, one transaction | 1387b839f03b5882… |
| settle B | B comes home first | 01973e8f784e5041… |
| settle A | reserve empty again | d54690e3db9b883c… |
Both children settled, in the only order the chain allows: the reserve is a hash chain and settlement pops it from the end, so the worker hired last comes home first. After the second one the coordinator holds 0.690192 KAS of its original 0.8, with nothing reserved and an empty chain — and because a grant’s address is a hash of its state, it is back at the address it was born at. The difference is 0.109808 KAS of fees. Nobody spent anything; the money was lent and returned.
This is the part a budget alone cannot do. Handing a worker a limit and waiting for it to expire returns the coin to the human. Settling returns it to the coordinator, mid-task, ready to hire again.
Kaspa’s storage mass counts 1/value over a transaction’s
outputs, so each extra child costs a whole term rather than a slice of one. An atomic 1:2
masses 420,435 against a ceiling of
500,000; 1:3 masses
770,994 and is refused by the network. The covenant
would allow it. The chain will not.
The second budget is the engine’s stack, and it is now measured rather than
assumed: delegate peaks at 161 of
244 and delegate2 at
189. It is not what bounds fanout today. It is
what would, if the mass ceiling ever moved.
The covenant this section describes is a draft with a passing probe suite and no audit. The run above is the audited-shape one.