LOPWLayer of Onchain Programmable Warranties

Demo Walkthrough with real transactions

Watch an agent get paid back.

An autonomous agent buys a EUR/USD quote for one cent from a bonded API, catches the seller quoting 10% away from the oracle, and is paid 5 USDC from the seller's stake in a single claim. Every step below happened on-chain, and every transaction is linked so you can verify it yourself.

$0.01 per quotepaid through standard x402
200 USDC stakedslashable, held by the Bond Registry
10% off the oracleagainst a promise of 0.5%
5 USDC paid backone claim, one transaction

01 The cast

A seller, a buyer, and three contracts.

The seller and the agent are ordinary x402 participants. The Bond Registry, the Claims contract and the validators are what LOPW adds. None of them needs a human to act.

SellerBonded API

FX quote API

Sells EUR/USD quotes for one cent each and warrants five predicates against its own stake.

Stake held
200 USDC Active
Price per quote
0.01 USDC
Max payout per receipt
5 USDC
Warranty
P1P2P3P4P6
P6 reference
SEP-40 oracle, EUR/USD
P6 tolerance
within 0.5%
AgentBuyer policy

Autonomous buyer

Runs the LOPW buyer SDK. It reads the bond before paying and refuses any service that falls short of its policy.

Pays only services that are
Active
Minimum stake
100 USDC
Must cover
P6
Minimum payout per receipt
1 USDC
Verifies every receipt
yes
Files claims
automatically
Contract

Bond Registry

Holds the seller's stake, its registered terms and signing key. Slashes only on instruction from the Claims contract.

Contract

Claims

Checks signatures, the claim window and double claims, asks the right validator, then pays the buyer or rejects.

Contracts

Validators P1–P6

One per predicate. P6 reads the SEP-40 oracle on-chain, so the seller cannot influence the verdict.

02 Walkthrough

Twelve steps from discovery to payout.

Play it, or step through it at your own pace. The console shows the demo agent's real output; the grey lines underneath explain what happened on the wire and on-chain at each step.

    demo-agent · consoleFAULT=BAD_PRICE
    
                  
    demo-agent outputwhat happens underneath
    Seller stake200.00 USDC
    0agent minimum 100200
    1. Discover the service

      The agent asks the seller what it warrants. The listing names the service and the bond behind it.

      GET https://fx.lopw.com/v1/warranty
      
      {
        "service_id": "a1f1c5c89c63…",
        "state": "Active",
        "stake": "2000000000"   // 200 USDC, 7 decimals
      }
      discover service a1f1c5c89c63… Active, stake 200.00 USDC
    2. Read the bond on-chain

      The agent does not take the seller's word for it. It reads the Bond Registry directly: the service is Active and 200 USDC of stake stands behind it.

      BondRegistry.get_service(a1f1c5c89c63…)
      
      state        Active
      stake        200.00 USDC
      terms_hash   69d78803…
      predicates   P1 P2 P3 P4 P6
      ↳ registry Active · stake 200.00 USDC · terms 69d78803…
    3. 402 with a signed warranty offer

      The agent asks for a quote. The seller answers 402 Payment Required with the usual x402 terms, plus a signed LOPW offer in extensions.lopw that pins the registered terms by hash.

      GET /v1/quote?pair=EUR-USD
      ← 402 Payment Required
      
      {
        "x402Version": 2,
        "accepts": [{ "scheme": "exact", "price": "$0.01", … }],
        "extensions": {
          "lopw": {
            "service_id": "a1f1c5c89c63…",
            "registry":   "CD32WBJS…",
            "terms_hash": "69d78803…",
            "price":      { "amount": "100000", "display": "$0.01" },
            "max_claim":  "50000000",   // 5 USDC
            "valid_until": …, "offer_nonce": "…",
            "key_version": …, "signature": "…"
          }
        }
      }
      ↳ 402 signed offer · price $0.01 · max_claim 5.00 USDC
    4. Verify the offer and the policy

      Before paying, the buyer SDK checks the offer against the chain and against the agent's own policy. If any check fails, it walks away without paying.

      offer signature     registered key           ✓
      service state       Active                   ✓
      stake ≥ minStake    200.00 ≥ 100.00 USDC     ✓
      covers P6           P1 P2 P3 P4 P6           ✓
      max_claim ≥ 1 USDC  5.00 USDC                ✓
      fresh offer         valid_until, new nonce   ✓
      ↳ policy Active · 200.00 ≥ 100.00 USDC · covers P6 · pay
    5. Pay $0.01 through x402

      Payment is ordinary x402: the agent signs a USDC transfer and the facilitator verifies and settles it on-chain. Nothing is held in escrow.

      GET /v1/quote?pair=EUR-USD
      PAYMENT-SIGNATURE: { "x402Version": 2, "scheme": "exact", … }
      
      facilitator   verify ✓   settle ✓
      transfer      0.01 USDC  agent → seller
      ↳ x402 0.01 USDC signed · verified and settled by the facilitator
    6. Quote and signed receipt

      The seller returns the quote and a signed receipt in PAYMENT-RESPONSE that binds the payment, the request, the response bytes and the terms. The rate is 10% below the oracle: this seller runs with FAULT=BAD_PRICE.

      HTTP/1.1 200 OK
      {"pair":"EUR-USD","rate":"1.01258970","rate_raw":"101258969676705","decimals":14,"as_of":1790993400}
      
      PAYMENT-RESPONSE → extensions.lopw = {
        "service_id":        "a1f1c5c89c63…",
        "offer_hash":        "…",
        "terms_hash":        "69d78803…",
        "buyer":             "GDO5YT…",
        "payment_reference": "93787e82b69d…",
        "request_hash": "…", "response_hash": "…",
        "status": 200, "response_bytes": …,
        "served_at": …, "data_as_of": …,
        "oracle": { "reported_value": "101258969676705", … },
        "signature": "…"
      }
      pay + fetch HTTP 200 {"pair":"EUR-USD","rate":"1.01258970","rate_raw":"101258969676705","decimals":14,"as_of":1790993400}receipt payment 93787e82b69d… buyer GDO5YT… terms 69d78803…
    7. Verify the receipt

      The agent checks that the receipt is genuine and is about this purchase. A receipt that fails here is flagged untrusted: no claim can be made on it, and the seller is not penalised.

      signature          service key at key_version      ✓
      offer_hash         the offer that was paid         ✓
      buyer              GDO5YT… (this agent)            ✓
      payment_reference  93787e82b69d… settlement        ✓
      request_hash       SHA-256 of the request sent     ✓
      response_hash      SHA-256 of the bytes received   ✓
      verify signature, offer, buyer, payment, request and response hashes all match
    8. Local check finds a P6 breach

      The SDK evaluates every predicate in the terms locally. P6 compares the reported rate with the SEP-40 oracle price the receipt cites: 10% apart, against a promised 0.5%.

      P1 equivocation    one receipt for this payment   kept
      P2 terms           receipt terms = offer terms    kept
      P3 freshness       within max_data_age            kept
      P4 status          200 is chargeable              kept
      P6 oracle          reported   1.01258970
                         oracle    ≈1.12509966  EUR/USD
                         deviation  1000 bps > 50 bps   BREACH
      breach predicates P6
    9. File the claim

      The agent submits the signed offer and receipt to the Claims contract. Anyone may file; the payout always goes to the buyer named in the receipt.

      Claims.claim(predicate: 6, offer, receipt)
      
      service not Closed              ✓
      offer and receipt signatures    ✓
      receipt cites the offer         ✓
      inside served_at + 1 h window   ✓
      payment not claimed before      ✓
      P6 listed in the terms          ✓
      ↳ claim P6 · offer + receipt → Claims CD5DBM2S…
    10. The validator reads the oracle

      Claims hands the evidence to the P6 validator, which reads the oracle price at the cited timestamp on-chain and decides from that alone. No one votes and no one reviews.

      ValidatorP6.validate(offer, receipt, terms)
        oracle.price(EUR, oracle_timestamp)   // SEP-40, on-chain
        |reported − oracle| × 10000 > 50 × oracle
        → Proven
      ↳ validator P6 reads the oracle on-chain · Proven
    11. The registry slashes

      The Claims contract instructs the Bond Registry to slash. The payout is min(max_claim, stake left): 5 USDC, transferred to the buyer in the same transaction.

      BondRegistry.slash(a1f1c5c89c63…, 5.00 USDC)
      event ClaimPaid { predicate: 6, amount: 50000000 }
      
      stake  200.00 → 195.00 USDC   state Active
      ↳ registry slash 5.00 USDC → GDO5YT…
    12. Agent paid 5 USDC; stake 200 → 195

      The buyer holds 5 USDC more and the seller's bond is 5 USDC lighter, still Active. The whole claim is one transaction anyone can open.

      agent         +5.00 USDC
      seller stake  195.00 USDC (Active)
      tx            9b10abc505b952fccf9b8dd02eef0d12
                    3600ac2783b279098aa38c21b6911a4a
      Open this claim on Stellar Expert ↗
      claim PAID 5.00 USDC tx 5d75c3a069e09b96ed0ba00ca739fdaa7d489e0788b0557dff28eb0f556225bbseller stake 195.00 USDC (Active)

    Live Scenario log

    The same story, replayed on a schedule.

    This walkthrough and its siblings run on a schedule against the live services with real payments; the two latest runs of each are below, and the full history is on the proofs page.

    The scenario log is read live from the LOPW API. What each scenario checks, why it matters and how a run is judged is described in Proofs and scenarios in the documentation.

    03 On-chain proof

    Every warranty type, paid on-chain.

    The same agent ran against seller faults covering all six predicates. Each breach was proven by its validator contract and paid from stake. Open any row to see the transaction.

    PredicateWhat the seller did wrongFaultPayoutTransaction
    P1 EquivocationFX quote APISigned two different receipts for the same paymentDUPLICATE_RECEIPT5 USDC3cfe29e4…1b7da282 ↗
    P2 Terms mismatchFX quote APIReceipt cited the offer but different termsWRONG_TERMS5 USDC7ca5efcf…9048589de2 ↗
    P3 Stale dataFX quote APIServed a quote an hour old against a 10-minute limitSTALE_DATA5 USDC0ef85a5d…5e42bafcb5 ↗
    P4 Bad statusLedger data APICharged for HTTP 203 when only 200 is chargeableBAD_STATUS1 USDC54c2e8f6…e95788e990 ↗
    P5 Size limitLedger data APIReturned a response over the 4 KiB limitOVERSIZE1 USDCb6f33404…2f79f4bc ↗
    P6 Oracle deviationFX quote APIQuoted EUR/USD 10% off the SEP-40 oracle; tolerance 0.5%BAD_PRICE5 USDC5d75c3a0…c21b6911a4a ↗
    Tampered receiptReceipt signature does not verifyBAD_SIGNATUREUntrustedNo claim possible, no penalty
    Honest responseNothingNORMALKeptWarranty kept, nothing to claim
    About these links. The transactions are on the Stellar test network (Stellar testnet). Each link opens the public Stellar Expert explorer, where you can read the Claims contract call, the ClaimPaid event and the USDC transfer to the buyer. P1, P2, P3 and P6 were paid by the FX quote API (5 USDC per receipt); P4 and P5 by a ledger data API bonded with a 1 USDC payout per receipt.

    04 The contracts

    Deployed, public and readable.

    Eight contracts did the work above. Each address opens on the Stellar Expert explorer for the Stellar testnet, where you can inspect its storage, calls and events.

    Contract

    Bond Registry

    Stake, terms and signing keys per service. Slashes on instruction from Claims.

    CBNGZB5GL3FEZKIQK73BTJYCQAC76N7SZCLN34JRMTQCUWER4GB3WHPL ↗
    Contract

    Claims

    Verifies the evidence, calls the validator, records the outcome and triggers the payout.

    CBUBZC2AHVKFKYTAO3DIF6CZFQVM4UYCNABYVTPQNUUJGLOIBSIWONSC ↗

    05 Run it yourself

    Your agent, your transaction.

    The demo agent is a short script on top of the buyer SDK. Point it at the FX quote API, choose a fault, and it prints the console above with a transaction hash of its own.

    Terminaldemo-agent
    AGENT_SECRET=... SERVICE_URL=https://fx.lopw.com FAULT=BAD_PRICE pnpm --filter @lopw/demo-agent start

    AGENT_SECRET is the agent's Stellar secret key; the account needs USDC on the same network as the contracts above. FAULT asks the seller to misbehave in one specific way:

    • BAD_PRICEQuote 10% off the oracle → P6
    • STALE_DATAQuote an hour old → P3
    • WRONG_TERMSReceipt cites other terms → P2
    • DUPLICATE_RECEIPTSecond receipt for one payment → P1
    • BAD_SIGNATURETampered receipt → untrusted, no claim
    • NORMALHonest response → warranty kept
    agent.ts@lopw/buyer-sdk
    import { LopwBuyer } from "@lopw/buyer-sdk";
    
    const agent = new LopwBuyer({
      secret: process.env.AGENT_SECRET,
      policy: {
        minStake: 100n * 10_000_000n,   // 100 USDC
        requiredPredicates: [6],
        minMaxClaim: 10_000_000n,       // 1 USDC
      },
    });
    
    const { response, body, warranty } = await agent.fetch(
      "https://fx.example.com/v1/quote?pair=EUR-USD"
    );
    
    if (warranty?.breaches.length) {
      const result = await agent.claim(warranty);
      // { outcome: { paid }, transaction }
    }