-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
409 lines (395 loc) · 25.1 KB
/
Copy pathindex.html
File metadata and controls
409 lines (395 loc) · 25.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ZeroClaw on Solana: an agent bounded by the chain</title>
<meta name="description" content="A DePIN node that sells its own signed readings, and a shop that takes money without holding keys. Every claim checkable with one command.">
<!-- Without these, this URL pasted into Discord or X renders as a bare link. The showcase post is
the submission itself, so the card is the first thing a judge sees of the project. -->
<meta property="og:type" content="website">
<meta property="og:site_name" content="zeroclaw-solana">
<meta property="og:title" content="ZeroClaw on Solana: an agent bounded by the chain">
<meta property="og:description" content="A DePIN node that sells its own signed readings, and a shop that takes money without holding keys. Every claim checkable with one command.">
<meta property="og:url" content="https://belumume.github.io/zeroclaw-solana/">
<meta property="og:image" content="https://belumume.github.io/zeroclaw-solana/docs/assets/social-preview.png">
<meta property="og:image:width" content="2560">
<meta property="og:image:height" content="1280">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="ZeroClaw on Solana: an agent bounded by the chain">
<meta name="twitter:description" content="A DePIN node that sells its own signed readings, and a shop that takes money without holding keys. Every claim checkable with one command.">
<meta name="twitter:image" content="https://belumume.github.io/zeroclaw-solana/docs/assets/social-preview.png">
<style>
:root{
--bg:#fbfaf8; --fg:#1a1815; --muted:#615c54; --rule:#e2ddd4;
--card:#ffffff; --accent:#b34a1a; --ok:#1f6f43; --code-bg:#f4f1ec;
}
@media (prefers-color-scheme:dark){
:root{
--bg:#14130f; --fg:#eae5db; --muted:#9b948a; --rule:#2c2a25;
--card:#1c1a16; --accent:#e0824f; --ok:#5fb98a; --code-bg:#211f1a;
}
}
*{box-sizing:border-box}
body{
margin:0; background:var(--bg); color:var(--fg);
font:16px/1.65 ui-sans-serif,-apple-system,"Segoe UI",Inter,Roboto,Helvetica,Arial,sans-serif;
-webkit-font-smoothing:antialiased;
}
.wrap{max-width:760px; margin:0 auto; padding:0 20px}
header{padding:72px 0 12px}
h1{font-size:clamp(28px,5vw,40px); line-height:1.15; margin:0 0 16px; letter-spacing:-.02em}
h2{font-size:clamp(19px,3vw,23px); margin:56px 0 14px; letter-spacing:-.01em}
h2 .n{color:var(--muted); font-variant-numeric:tabular-nums; font-weight:400; margin-right:.5em}
.lede{font-size:clamp(17px,2.4vw,19px); color:var(--muted); margin:0 0 28px}
p{margin:0 0 16px}
a{color:var(--accent); text-underline-offset:3px}
code,pre{font-family:ui-monospace,"Cascadia Code",Consolas,"SF Mono",Menlo,monospace}
/* inline code carries base58 addresses, which have no break opportunity and would push the
page sideways on a phone. pre keeps its own horizontal scroll, so it is excluded below. */
code{
background:var(--code-bg); padding:.12em .38em; border-radius:4px; font-size:.9em;
overflow-wrap:anywhere;
}
pre{
background:var(--code-bg); border:1px solid var(--rule); border-radius:8px;
padding:14px 16px; overflow-x:auto; font-size:14px; line-height:1.55; margin:0 0 16px;
}
pre code{background:none; padding:0; font-size:inherit}
.stats{
display:grid; grid-template-columns:repeat(auto-fit,minmax(132px,1fr)); gap:1px;
background:var(--rule); border:1px solid var(--rule); border-radius:10px; overflow:hidden;
margin:0 0 18px;
}
.stat{background:var(--card); padding:16px 18px}
.stat b{display:block; font-size:26px; letter-spacing:-.02em; font-variant-numeric:tabular-nums}
.stat span{display:block; font-size:12.5px; color:var(--muted); margin-top:3px}
.stat.good b{color:var(--ok)}
.note{
border-left:3px solid var(--accent); padding:2px 0 2px 16px; margin:0 0 18px;
color:var(--muted); font-size:15px;
}
.note strong{color:var(--fg)}
video{width:100%; border:1px solid var(--rule); border-radius:10px; display:block; background:#000}
.links{list-style:none; padding:0; margin:0}
.links li{padding:11px 0; border-top:1px solid var(--rule); display:flex; gap:14px; flex-wrap:wrap}
.links li:last-child{border-bottom:1px solid var(--rule)}
.links b{min-width:150px; font-weight:600}
.links span{color:var(--muted); font-size:14.5px}
footer{margin:64px 0 40px; padding-top:22px; border-top:1px solid var(--rule); color:var(--muted); font-size:14px}
.tag{
display:inline-block; font-size:12px; letter-spacing:.09em; text-transform:uppercase;
color:var(--muted); border:1px solid var(--rule); border-radius:20px; padding:4px 11px; margin-bottom:20px;
}
</style>
</head>
<body>
<div class="wrap">
<header>
<span class="tag">Superteam · ZeroClaw on Solana</span>
<h1>An agent bounded by the chain, and a node that pays its own gas</h1>
<p class="lede">
Two things run, both self-hosted, both auditable by a stranger in an evening. A DePIN node that
signs its own readings on-chain and <em>sells</em> them per request, and a merchant
terminal that takes an order in Portuguese and settles in USDC. The reading comes from a keyless
public weather API on that host rather than from a physical probe; a Raspberry Pi with a DHT11 is
the hardware path, and the on-chain half is identical either way, because what is signed is the
value and the device key rather than the enclosure.
</p>
<p>
Every claim on this page is checkable with one command or one link. Nothing here is a
screenshot of something that used to work. Start with the shortest one:
</p>
<pre><code>curl -i https://x402.perfpilot.dev/price</code></pre>
<p class="note">
A live node answering <code>HTTP/1.1 402 Payment Required</code> with a single-use nonce that
changes on every request. That is the whole machine-commerce claim, in one request, against a
node that is running right now. The node is an Ampere ARM instance on Oracle's free tier;
its signing key was generated there and has never left it.
</p>
<p class="lede" style="font-size:15px">
On Windows that can fail with <code>curl: (35) schannel: … CRYPT_E_REVOCATION_OFFLINE</code>.
The node is fine; Schannel could not reach a certificate-revocation responder and treats that
as fatal for every HTTPS host. Add <code>--ssl-revoke-best-effort</code>, which downgrades an
unreachable responder from fatal to non-fatal and still validates the certificate.
</p>
</header>
<!-- Served from this repo rather than embedded from a third party, so the page has no dependency
it does not control and the file is in the clone. Captions are the operator's own words. -->
<video controls preload="metadata" width="100%" style="border-radius:10px;display:block;margin:8px 0 6px"
poster="docs/assets/social-preview.png">
<source src="docs/assets/zeroclaw-demo-1080p.mp4" type="video/mp4">
<track src="docs/assets/zeroclaw-demo.vtt" kind="captions" srclang="en" label="English" default>
Your browser will not play this inline.
<a href="docs/assets/zeroclaw-demo-1080p.mp4">Download the demo</a> instead.
</video>
<p class="note">
Two minutes fifteen, one take, no slides. Also on
<a href="https://youtu.be/a0jT0feuMAg">YouTube</a> in 4K. Everything it shows is exercisable
below without a wallet.
</p>
<h2><span class="n">01</span>It has been running, not demoed</h2>
<div class="stats">
<div class="stat"><b>2,292+</b><span>publishes on chain</span></div>
<div class="stat good"><b>0</b><span>failed</span></div>
<div class="stat"><b>2</b><span>independent devices</span></div>
<div class="stat"><b>20.5<small>m</small></b><span>median gap</span></div>
</div>
<p>
Read at 2026-08-15T19:41Z, and carried as a floor because the ARM node publishes every twenty
minutes or so; the second device's count is final. Re-derive both rather than believing this page. It is an unauthenticated
call against a public devnet RPC, no key and no account:
</p>
<pre><code>python3 scripts/verify-proof.py # stdlib only, no install, no key</code></pre>
<p>
<strong>Two devices, not one, and that is the DePIN claim rather than a gadget claim.</strong>
The same on-chain oracle program serves both, each with its own device key, each on its own
machine. Neither can sign for the other.
</p>
<ul class="links">
<li><b><code>JEtuZk…Vveg</code></b>
<span>the ARM node. Publishing since 25 July, 1,514+ so far, 0 failed, median gap
20.5 min. Its key was
generated on that box and has never left it, so this workstation cannot forge a reading for
it.</span></li>
<li><b><code>3aMsPj…Vx8K</code></b>
<span>a second device, 778 publishes, 0 failed, over a <strong>completed</strong> 12.4-day
run ending 2026-08-06. Deterministic publisher, no model in its path. It was laptop-hosted
and it has stopped, which is why the continuity claim below rests on the node alone.</span></li>
</ul>
<p>
To count either history directly, the underlying call is <code>getSignaturesForAddress</code> on
the feed account.
</p>
<p class="note">
Zero failures is
exact and covers both devices: no transaction has ever errored. Continuity is where they differ.
The ARM node's largest gap is <strong>61.5
minutes</strong> across the run since 25 July, so "every twenty minutes" is true at the
median with one
hour-long interruption. The second device was laptop-hosted, so it slept, and its largest gap
inside its run was <strong>36 hours</strong>. It has since stopped for good, and the command
cannot tell you that: it measures gaps between consecutive publishes, so once a feed stops its
largest gap freezes at the last value it reached instead of growing to reflect the silence.
Re-run it in a month and it still reports 36 hours, with nothing in the number marking the
device as gone. Its job was to show the
same program accepting signed readings from a second independent device with a second key, and a
completed run of 778 publishes at zero failures did that. Continuity rests on the node alone.
The command above shows you both anyway, which is the only reason either is worth writing down:
a number you can check beats a rounder one you cannot.
</p>
<h2><span class="n">02</span>The custody argument does not depend on trusting us</h2>
<p>
An approval prompt is not a boundary. The sentence a human reads before approving was written by
the model, so influencing the model influences the description. An attacker needs no key, only an
operator who reads one plausible sentence and says yes.
</p>
<p>
Being key-free is what every careful entry in this space says, and it is a claim about what our
own code <em>declines</em> to do, which is only ever as good as our code.
<strong>The load-bearing difference is where the limit is enforced.</strong> Ours is not in the
plugin, not in the host, and not in the prompt: it is a deployed, audited on-chain program.
</p>
<p>
Demonstrated on <strong>mainnet</strong>, and the program that does the
refusing is <strong>not ours</strong>. Solana Foundation's audited
Allowances program (<code>De1egAFMk…</code>, on mainnet since June 2026, audited by Cantina) rejected an over-cap transfer with custom error <code>0x12c</code>, signed by a
freshly generated agent session key. The same key moved a within-cap transfer normally, settling
0.4 USDC. Three mainnet transactions in all, captured as raw bytes in the repo, verifying offline
with no network and no dependencies:
</p>
<pre><code>python3 scripts/verify_proof_offline.py</code></pre>
<p>
Prompt-inject every layer we wrote and the ceiling is still there, because it was never ours to
remove.
</p>
<p>
<strong>The selling side is capped too, which the brief makes mandatory in both directions.</strong>
The node sells its readings behind an x402 paywall, and a per-payer per-day ceiling is enforced in
the gate's own code rather than by the protocol: a payer who drains the cap in many small buys is
refused the same as one who tries it in a single large one. The ledger is durable, so restarting
the process does not re-open a spent allowance. An earlier version restarted the day on every
boot, which is a cap in name only. Check the fix:
</p>
<pre><code>curl -s https://x402.perfpilot.dev/health | jq '.ledger'</code></pre>
<p>
<strong>That paywall has taken real money, and the precise claim is a split one.</strong>
Reading the feed and settling the payment are separate concerns on separate RPC endpoints, so the
gate settled a genuine <strong>mainnet</strong> payment of 1.000000 USDC while serving a reading
from our <strong>devnet</strong> feed. The settlement is
<code>3gSg3mQE9vA5X9CmFBxGEY2EFSAMXGhaC1HrUDbH8uA3MQhuaVjCdHjb1kshyzTqWKRALa9EQPeKja2Hk2rWcF2f</code>,
finalized on mainnet-beta. The goods stay on devnet because a <code>DeviceFeed</code> account is
owned by our <code>zeroclaw_oracle</code> program, deployed on devnet only, so a mainnet feed is a
program deployment rather than a config flag. The hosted endpoint above runs the devnet default.
</p>
<p>
<strong>The exchange rate is off the model as well.</strong> A Brazilian order carries one
money-touching number a language model could simply state, with nothing checking it: the rate.
It is now fetched in code from Brazil's central bank (BCB PTAX) and refused unless the ECB's
published figure agrees within a stated band. Both sources are keyless, and there is no
last-known value to fall back on, so an unreachable source stops the quote instead of ageing
one. On 2026-08-14 the two sat 0.91% apart, which is the margin a single source would have
carried silently.
</p>
<pre><code>python3 scripts/rate_crosscheck.py # the corroborated rate, or a refusal
python3 scripts/check-pay-link-rate-agreement.py # the pay path's copy still matches</code></pre>
<p class="note">
What this does not close: the order <em>value</em> is still supplied by the caller. An
implausible one is refused in code, so "table 4, R$ 0.05" no longer produces a link, but a
plausible wrong amount still does. That band is wide on purpose, because this shop has no
catalog and a narrow one would refuse legitimate orders. One free parameter of two is gone and
the second is narrowed. The shop on the node has not picked either change up yet, so the
enforcement is in the repo and the deploy is what remains.
</p>
<h2><span class="n">03</span>The customer's own page refuses, in their language</h2>
<p>
Every layer above is still something the agent composes, and an agent talked into a different
recipient composes a perfectly well-formed link to it. So the checkout page pins the one address
it will ever pay and does not trust the link that opened it. Change a single character of the
recipient and the card is replaced by <strong>RECUSADO</strong>, the pay button is gone rather
than disabled, and both addresses print <em>in full</em>, because a truncated
<code>C331…iLHJ</code> is exactly what lets a swapped address survive a glance.
</p>
<pre><code>python demo/verify-merchant-invariant.py</code></pre>
<p>
That harness covers the swapped recipient. Six more cover the rest of the page, each written
after a failure we actually hit rather than one we imagined, and each drives the live page:
</p>
<pre><code>python demo/verify_wallet_picker.py # the customer can choose a wallet, at no layout cost
python demo/verify_qr_scannable.py # the QR decodes, under two independent decoders
python demo/verify_no_cdn_dependency.py # the pay path loads its code from this origin, never a CDN
python demo/verify_paid_link_refused.py # a reference that already settled is refused, both directions
python demo/verify_pay_path_rpc.py # the desktop path reaches its RPC from a browser
python demo/verify_settlement_poll.py # the page polls for settlement, not only on load</code></pre>
<p>
One more covers a different surface. Those checks decode the QR off the <em>page</em>; what a
viewer actually scans is a frame of the shipped video, and an h264 encode is precisely what
degrades a QR's sharp module boundaries through chroma subsampling and deblocking. A code that
decodes off the page can fail off the tape, and only the tape ships:
</p>
<pre><code>python demo/verify_qr_in_encoded_cut.py # the pay QR still decodes after the lossy encode</code></pre>
<p>
<strong>Or exercise it yourself, right now, with no wallet and no funds.</strong> These are the
live checkout page, opened with three different orders. Nothing is sent by loading any of them.
</p>
<ul>
<li>
<a href="https://zeroclaw-shop-pay.pages.dev/index.html?lang=pt&u=c29sYW5hOkMzMzFYNFlDSENkY0VTZXhSVEtTakU1ZXRqc1d5V0pMSzczWjE4WldpTEhLP2Ftb3VudD0wLjM5JnNwbC10b2tlbj1FUGpGV2RkNUF1ZnFTU3FlTTJxTjF4enliYXBDOEc0d0VHR2tad3lURHQxdiZyZWZlcmVuY2U9NVp6Z3V6NE5zU1JGeEdrSGZNNEttSlROVlBNSjJQM2pGYTJ5OGJUSFk0a1cmbGFiZWw9WmVyb0NsYXclMjBTaG9wJm1lc3NhZ2U9UGVkaWRv">One character changed in the recipient</a>
→ <strong>RECUSADO</strong>, no pay button, both addresses in full.
</li>
<li>
<a href="https://zeroclaw-shop-pay.pages.dev/index.html?lang=pt&u=c29sYW5hOkMzMzFYNFlDSENkY0VTZXhSVEtTakU1ZXRqc1d5V0pMSzczWjE4WldpTEhKP2Ftb3VudD0wLjM5JnNwbC10b2tlbj1FUGpGV2RkNUF1ZnFTU3FlTTJxTjF4enliYXBDOEc0d0VHR2tad3lURHQxdiZyZWZlcmVuY2U9NVp6Z3V6NE5zU1JGeEdrSGZNNEttSlROVlBNSjJQM2pGYTJ5OGJUSFk0a1cmbGFiZWw9WmVyb0NsYXclMjBTaG9wJm1lc3NhZ2U9UGVkaWRv">The correct recipient</a>
→ the payable card, with the pay button live. <em>This one is the control</em>: without it,
the refusal above would be consistent with a page that refuses everything.
</li>
<li>
<a href="https://zeroclaw-shop-pay.pages.dev/index.html?lang=pt&u=c29sYW5hOkMzMzFYNFlDSENkY0VTZXhSVEtTakU1ZXRqc1d5V0pMSzczWjE4WldpTEhKP2Ftb3VudD01LjAwJnNwbC10b2tlbj1FUGpGV2RkNUF1ZnFTU3FlTTJxTjF4enliYXBDOEc0d0VHR2tad3lURHQxdiZyZWZlcmVuY2U9OVROS29DdlZvdzFrdFJnTU1hcEo5ZDlHV2hnVFlDQTlpM3IzTVo3MUZVVDImbGFiZWw9WmVyb0NsYXclMjBTaG9wJm1lc3NhZ2U9UGVkaWRv">A reference that already settled</a>
→ <strong>Pago</strong>. Note the link asks for <code>5.00</code> and the card shows
<code>0.39</code>, because 0.39 is what the chain recorded. The page reads the chain, not the link.
</li>
</ul>
<p class="note">
The control is the point. A page that refused <em>everything</em> would produce an identical
screenshot, so the harness drives both directions: the pinned address must stay payable while a
one-character variant is refused. It reads the pinned address out of the shipped page rather than
restating it, so the two cannot drift, and neutering its tampering makes it exit non-zero instead
of quietly passing.
</p>
<p>
The page localises from <code>navigator.language</code> and renders <code>pt-BR</code> end to
end. The refusal a Brazilian customer actually reads:
<em>"Este link paga um endereço que não é desta loja. Nada foi enviado."</em>
</p>
<h2><span class="n">04</span>Reproduce it: clone, then three commands</h2>
<pre><code>git clone https://github.com/belumume/zeroclaw-solana && cd zeroclaw-solana
python3 scripts/verify-proof.py # 10 static + up to 5 live claims, stdlib only
python3 scripts/verify_proof_offline.py # the custody proofs, no network at all
python3 scripts/certify_publish_tx.py # seven injection shapes, all refused</code></pre>
<p>
No install step, no virtualenv, no credentials. The offline verifier refuses to report at all if
its own positive control stops passing, so a green result cannot come from a broken checker.
</p>
<h2><span class="n">05</span>Four things in the repo</h2>
<p>
These are not extras bolted on for a demo. Each one exists because a specific claim elsewhere on
this page would otherwise rest on our word, and each is exercisable by a stranger.
</p>
<p>
<strong>Where the cap's boundary sits today, on mainnet, with no key and no
funds.</strong> The captured refusal above proves the program said no once. This finds where it
says no <em>today</em>: it reads the remaining allowance off the delegation account and replays
the captured message at amounts either side of it. It requires at least one amount to be refused
<em>and</em> at least one to be accepted, so a program that had stopped working and a check that
had stopped checking both fail it rather than printing a clean result over nothing.
</p>
<pre><code>python3 scripts/replay_allowance_probe.py</code></pre>
<p>
<strong>A second program reads the feed on chain, which is the difference between an oracle and a
memo.</strong> Publishing signed bytes proves only that bytes were published. A separate deployed
program, <code>consumer_example</code>, CPI-reads the feed account, checks the owner and gates on
freshness, so the data is consumable by something other than a human squinting at an
explorer. It last read the live ARM feed in transaction
<code>4CRapo3AEFBFLh7Y7byJR9XDYZEa95MEioUQMzUhJVxTB9HaDTRtX2X47pVgxaSu8KNfYsPyugeQ6FjN8hBzi54L</code>.
</p>
<p>
<strong>The sanitizer, in your browser, compiled from the code that ships.</strong> Untrusted
on-chain text reaches a model through our plugins, so it is sanitized and labelled first. The page
below is not a JavaScript reimplementation demonstrating the idea. It compiles
<code>solana_core::sanitize</code> itself to wasm, so what you are typing at is the same function
the plugins call. Paste a right-to-left override or a zero-width joiner and watch what the model
would actually receive.
</p>
<p>
<a href="https://belumume.github.io/zeroclaw-solana/sanitizer-microworld/"><strong>Open the
sanitizer microworld</strong></a> — it runs in this browser, no clone and no build. Six
presets, and one of them strips zero invisible characters and still labels the input, which is
the case a canned demo would not think to include.
</p>
<pre><code>sanitizer-microworld/index.html # or open it from a clone, no build step</code></pre>
<p>
<strong>A fuzzer graded by someone else's decoder.</strong> Every other correctness gate here
tests a property we thought to write down. The differential fuzzer seeds from real serialized
transactions, mutates them with correlated perturbations rather than uniform byte flips, and
scores each result against <code>solana-sdk</code>'s own deserializer as an external oracle
so it can find disagreement we did not predict. It is deliberately isolated from the
plugin workspace, because that oracle cannot compile to wasm and must never be reachable from the
shipped crates.
</p>
<h2><span class="n">06</span>Everything else</h2>
<ul class="links">
<li><b><a href="https://github.com/belumume/zeroclaw-solana">Repository</a></b>
<!-- Re-derive before editing this number; it moves whenever a crate is added:
git ls-files '*Cargo.toml' | xargs grep -l '^\[package\]' | wc -l
docs/ARGUMENT.md carries the same command beside the same claim. This said sixteen
while that said seventeen, because a crate was added and only one surface was swept.
Deliberately NOT gated: a counter cannot tell this claim from TESTING.md's historical
account or ci.yml's intentional floor without judgement, and a gate that fires on
those two is worse than this comment. -->
<span>seventeen crates, clippy-clean at <code>-D warnings</code> on host and wasm</span></li>
<li><b><a href="https://github.com/belumume/zeroclaw-solana/blob/main/docs/WRITEUP.md">Write-up</a></b>
<span>what it is, who it is for, custody and threat model</span></li>
<li><b><a href="https://github.com/belumume/zeroclaw-solana/blob/main/docs/ONE-PAGER.md">One-pager</a></b>
<span>the submission in three minutes, every claim with its command</span></li>
<li><b><a href="https://github.com/belumume/zeroclaw-solana/blob/main/docs/ARGUMENT.md">The case in full</a></b>
<span>the same claims at length, with the reasoning and the controls</span></li>
<li><b><a href="https://github.com/belumume/zeroclaw-solana/blob/main/QUICKSTART.md">Quickstart</a></b>
<span>run it yourself</span></li>
<li><b><a href="https://github.com/belumume/zeroclaw-solana/blob/main/docs/MAINNET-PROOF.md">Mainnet custody proof</a></b>
<span>the <code>0x12c</code> refusal, byte-for-byte</span></li>
<li><b><a href="https://github.com/belumume/zeroclaw-solana/blob/main/docs/transcripts/injection-refund-redirect.md">Injection transcript</a></b>
<span>refused without reaching for a fund tool; it escalated to the operator, who denied it</span></li>
<li><b><a href="https://github.com/belumume/zeroclaw-solana/blob/main/docs/HOST-SECURITY-AUDIT.md">Upstream audit</a></b>
<span>ten host defects confirmed and reported, one escalated to a private advisory</span></li>
<li><b><a href="https://github.com/belumume/zeroclaw-solana/blob/main/docs/WHAT-WE-GOT-WRONG.md">What we got wrong</a></b>
<span>eight things we believed that were false, and the measurement that killed each. Six were
invisible to a passing check, and four of those passed because the check answered a different
question than we thought it did</span></li>
</ul>
<footer>
Built for the Superteam ZeroClaw bounty. Devnet for the feed by choice; the custody proof is on
mainnet. Figures on this page carry the command that re-derives them, because a number without
one is a claim with an expiry date.
</footer>
</div>
</body>
</html>