ACP · Assured Delivery
Pay on Base.
Deliver anywhere.
Release on proof.
An x402 authorization captures if and only if a Taifoon V5 proof shows the agreed event landed on another chain, bound to that specific payment. No arbiter reads evidence. No party is trusted to report on itself.
Why this did not exist
captureAuthorizer is a socket with no plug
x402’s auth-capture scheme holds funds and names an entity that may capture, void or refund — but never defines what a correct capture decision is, and ships no arbiter.
x402 has no cross-chain story
A PaymentRequirements names exactly one network. Pay on Base, work on another chain is not hard or untooled; it is not expressible in the protocol.
The binding
A gate that matches on amount and recipient alone pays for other people's work: a provider can point at somebody else's transfer, or reuse one transfer across a hundred payments. The delivery action must carry a commitment to this payment's own nonce.
keccak256("taifoon.x402.v1" ‖ nonce ‖ payTo ‖ chainId_delivery)The flow
The buyer agent requests a resource it intends to pay for.
scheme auth-capture, network eip155:8453, captureAuthorizer = the gate, extra.taifoon = the predicate the buyer must be able to verify.
Recompute the correlator, check the gate against an allowlist, check the deadline clears the delivery chain proof window. Refuse on any failure.
Funds sit in the AuthCaptureEscrow. Nothing has moved and nothing can move without a capture decision.
The on-chain action carries a commitment to this payment’s nonce. That commitment is what makes the gate a pure function instead of a judgement call.
The delivery event enters the chain’s MMR; the peak is committed to the superroot, which is anchored on Base.
Permissionless. The provider usually calls it because the provider wants paid; a keeper can call it for a tip; an honest buyer may call it to close the matter.
Root is known, six layers cohere, chain/emitter/topic match, the correlator binds, every Binding holds, finality per the chain’s own type, nonce unspent. Then capture.
What the gate checks — 12, in order
| 01 | captureAuthorizer == address(this) | Reject authorizations pointed at a different gate. |
| 02 | keccak256(predicate) == paymentInfo.predicateHash | The predicate is the one the buyer signed; terms cannot change after authorize. |
| 03 | block.timestamp <= captureDeadline | Past the deadline the buyer reclaims instead. |
| 04 | isKnownSuperroot(blob.L1) | The root is anchored on Base.settlement kernel |
| 05 | verifyEncoded(blob) | Six layers cohere: chain root walks to superroot, header walks to chain root.settlement kernel |
| 06 | blob.L2.chainId == predicate.deliveryChainId | The event is on the agreed chain. |
| 07 | L5.emitter and L5.topic0 match | The event came from the agreed contract and is the agreed event. |
| 08 | L5.field[correlatorField] == predicate.correlator | THE BINDING. Without it the gate pays for other people’s work. |
| 09 | every Binding holds | Amounts, recipients and thresholds are as agreed. |
| 10 | L6 shows native finality | Per the delivery chain’s own finality type, not a fixed confirmation count. |
| 11 | notBefore <= L2.timestamp <= notAfter | Delivery landed inside the agreed window. |
| 12 | nonce not already captured | One authorization, one capture. |
Nothing in that list is a judgement. Steps 4 and 5 are inherited from the settlement kernel; the rest is field comparison.
What this cannot decide
decides
Effects that land on a chain: a transfer, fill, mint, swap, settlement or state change occurred, bound to this payment, inside a window.
does not decide
Quality. Whether an essay was good, a model answer correct, or a dataset accurate. For those the honest offering is an on-chain commitment, which proves a hash was published and nothing more.
Available now
Robinhood Chain · 4663
Pay on Base in USDC, deliver on Robinhood Chain, release when a V5 proof shows the event landed. One delivery chain, real addresses, a stated proof window.
OPEN THE GATEWAY →