-
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
-
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…
-
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
-
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
-
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
-
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…
-
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
-
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
-
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…
-
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
-
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…
-
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 ↗