Součást série o stavbě cz-agents → pod kapotou

Kde jsme skončili minule

Před pár týdny jsem tady psal, že na moje veřejné MCP servery z celé x402 ekonomiky dorazily jen sondy — indexovací služby, které si mapují, kdo umí přijmout strojovou platbu. Žádný agent s peněženkou, žádná poptávka, žádná mince. A upřímně jsem přiznal proč: moje servery x402 tehdy vůbec nepřijímaly. Nula plateb na serveru bez platební brány není datový bod o protokolu, je to datový bod o mém stanovení priorit.

Ta věta mě ale nenechala na pokoji. Protože jedna věc je říct „nemám platební bránu" a druhá věc je vědět, jestli by ta brána, kdybych ji postavil, vůbec unesla reálnou minci. Chtěl jsem tu mezeru zavřít — ne kvůli zákazníkům, kteří zatím nejsou, ale kvůli sobě: abych věděl, jestli mluvím o něčem, co reálně funguje, nebo o snímku z konference.

Milník: mince se pohnula

Tak jsem x402 rozjel do konce. A na konci se stalo přesně to, na co jsem se ptal: na Base mainnetu se usadilo reálné USDC v on-chain transakci. Ne testovací žetony na testnetu, ne simulace — skutečný stablecoin, který se pohnul z jedné strany na druhou, potvrzený řetězcem, end-to-end. Roura unese minci. To je odpověď na otázku, kterou jsem si minule položil.

A teď to, co musím říct hned, aby si to čtenář nedomýšlel sám a měl pravdu: byla to řízená demonstrace, kanárek, ne platící zákazník. Řídil jsem obě strany té transakce. Byl to test naostro — reálné peníze, reálný řetězec — ale ne komerční validace a ne organický zákazník, který přišel sám a chtěl si něco koupit. Je to rozdíl mezi „umím přijmout platbu" a „někdo mi platí", a ten rozdíl je celý zbytek téhle branže.

Milník je tedy reálný, ale skromný. Inženýrsky se něco změnilo: existuje ověřená cesta, po které projde skutečná mince. Obchodně se nezměnilo nic: zákazníci pořád nechodí. Obojí je pravda naráz a poctivost velí říct obě půlky nahlas, ne jen tu, co se lépe cituje.

Čtyři háčky, které našel až ostrý běh

Cennější než ta mince je ale to, co se cestou rozbilo. Protože se ukázalo něco, co znám z jiných oblastí, ale u peněz to bolí víc: část chyb se neprojeví v testech ani na testnetu, jen u reálného protějšku v ostrém běhu. Všechny čtyři háčky níže by prošly unit testy. Píšu je jako přenositelné pasti ekosystému x402 a EVM, ne jako popis svého systému — protože o přesně tyhle věci zakopne každý, kdo staví na stejném základu.

1. Podpisová doména EIP-712 se liší mezi testnetem a mainnetem

Platba v tomhle světě je podepsaná zpráva, a podpis je vázaný na takzvanou podpisovou doménu — sadu hodnot, které jednoznačně říkají, co a kde se podepisuje. Jedna z těch hodnot je jméno tokenu. A tady je past: na testnetu se USDC v té doméně jmenuje USDC, kdežto na mainnetu USD Coin. Kdo si tu hodnotu zadrátuje podle toho, co viděl na testnetu, na mainnetu vyrobí neplatný podpis u každé jednotlivé platby — a ověření ho odmítne. Zákeřné je, že testnet tuhle chybu neodhalí nikdy: tam ta hodnota sedí. Projde tudy tisíc zelených testů a první ostrá transakce na mainnetu spadne.

2. Jedno pole payloadu je objekt, ne řetězec

V datech, která klient posílá, je pole, které vypadá jako jednoduchá hodnota, ale ve skutečnosti je to strukturovaný objekt. Klient ho vrací beze změny, přesně jak má. Problém vznikne na straně, která to kontroluje: když porovnává objekt tak, jako by to byl řetězec, nikdy nesedí — a když nesedí, nic se nevydá. Kontrola tiše selže a odpověď se nikdy nepošle. Žádná chyba, žádná výjimka, jen prázdno tam, kde měla být data.

3. Podpisovou doménu je nutné klientovi předat explicitně

Souvisí s prvním bodem, ale je to samostatná past. Klient nemá podpisovou doménu odkud vzít, pokud mu ji server výslovně nepředá. Když se na to zapomene, klient nemá čím podepsat — a co nepodepíše, to protistrana neověří. V testu, kde si člověk obě strany drží sám, tahle hodnota často „nějak je", protože si ji tam ručně dodá. V ostrém běhu s cizím klientem chybí a celý tok se zastaví na začátku.

4. Kontrola expirace může být nesplnitelná

Poslední je nejzáludnější, protože vypadá jako přísnost, a přitom je to logická past. Kontrola platnosti platby může vyžadovat, aby v okamžiku ověření zbýval z časového okna celý limit. Jenže klient nastaví to okno přesně na tu hodnotu. Výsledek: podmínka je splnitelná jen v nulovém čase — jen kdyby ověření proběhlo v tomtéž okamžiku, kdy klient podepsal, což reálně nikdy nenastane. Každá skutečná platba dorazí o zlomek sekundy později a je odmítnuta jako prošlá. Testy to nechytí, když si člověk kolem té podmínky sám obejde časování.

Zastřešující myšlenka všech čtyř bodů: každý z nich projde unit testy a projeví se až u reálného protějšku v ostrém běhu. Testnet navíc některé věci schovává úplně — třeba testnet facilitátor bývá bez autentizace, kdežto mainnet vyžaduje ověřený účet. To znamená, že i „funguje mi to na testnetu od začátku do konce" je nálepka s hvězdičkou. Prošel jste zjednodušenou verzí reality.

Proč tyhle chyby žijí zrovna tady

Není náhoda, že se ani jedna z těch čtyř věcí neukázala dřív. Všechny žijí v mezeře mezi „prošlo to testy a funguje na testnetu" a „funguje s reálnými penězi na mainnetu". Ta mezera je úzká, snadno se přehlédne — a je to přesně místo, kde se láme rozdíl mezi tím, co si o svém systému myslíte, a tím, co dělá.

Unit test ověřuje, že se kód chová podle vaší představy. Jenže tři z těch čtyř háčků jsou případy, kdy je špatně sama ta představa: zadrátovaná hodnota z testnetu, porovnání objektu jako řetězce, nesplnitelná časová podmínka. Test postavený na téže mylné představě ji potvrdí, ne vyvrátí — zezelená a lže o všem. Chybu odhalí až protějšek, který vaši představu nesdílí, protože běží podle protokolu, ne podle vašeho očekávání.

U peněz je cena toho omylu konkrétní a nepříjemná. Není to prasklý test v CI, který se opraví do dalšího commitu. Je to spálený gas za transakci, která nikam nedošla, a na druhém konci protějšek, který zaplatil a nic nedostal — nebo naopak dostal a nezaplatil. Právě proto se tahle vrstva neověřuje tím, že „to prošlo", ale tím, že skutečná mince skutečně prošla. Nic menšího tu mezeru nezavře.

Co si z toho beru

Odpověď na otázku, kterou jsem si minule položil — unese ta roura reálnou minci? — zní ano, ověřeně. Na Base mainnetu se usadilo reálné USDC, end-to-end. To je hotová věc, ne snímek.

Ale zarámuju to tak, jak to je, ne jak by se lépe sdílelo. Ekosystém x402 je pořád velmi rané: napříč protokolem červenec skoro žádné organické platby nepřinesl, drtivá většina settlementů byly testy, a to zvlášť tady v Evropě. Moje mince do téhle statistiky patří — byla to demonstrace, ne zákazník. Milník, který jsem uzavřel, je inženýrský: roura unese minci. Milník, který uzavřený není, je obchodní: aby po té rouře poslal minci někdo, kdo přišel sám. Ten druhý pořád čeká a je v pořádku to říct nahlas.

Co si odnáším nejvíc, ale nakonec nejsou peníze, jsou ty čtyři háčky. Připomněly mi věc, kterou je snadné zapomenout, když má člověk zelené testy a funkční testnet: „prošlo to" a „funguje to s reálnými penězi" jsou dvě různá tvrzení, a mezi nimi je přesně tolik místa, kolik ho potřebují chyby, které nikdo nečekal. Milník je skromný. Poučení není.

Řešíte, jestli podobná integrace ve vaší firmě opravdu unese reálný provoz, ne jen testy? → AI konzultace