# x402

> The legalContext extension, the request commitment, and the x402 pairings.

Source: https://lcp.integraledger.com/guides/x402

[x402](https://github.com/coinbase/x402) is HTTP 402 payment: the seller answers a request with a `PaymentRequired`
document listing the options it accepts, and the buyer retries with a payment for one of them. This package reads and
writes x402 version 2 documents. Import the x402 pieces from `@integraledger/lcp/x402`.

## The `legalContext` extension

Every x402 pairing advertises H in the same place: the document's `extensions.legalContext`, as x402's extension
mechanism defines it (an `info` object and a JSON Schema for it).

```json no-check
{
  "extensions": {
    "legalContext": {
      "info": {
        "type": "sha256",
        "value": "0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
        "legalContextUrl": "https://atr.seller.example/0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
      },
      "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object" }
    }
  }
}
```

`LEGAL_CONTEXT` is the extension's key and `LEGAL_CONTEXT_SCHEMA` the full schema every pairing writes. The buyer
echoes `extensions` unchanged in its payment, as x402 requires. Where the pairing's payment carries H in nothing
public, `info` also carries `legalContextAgreementUrl`
([the agreement URL](https://lcp.integraledger.com/concepts/buyer-gate#the-agreement-url)).

One document has one legal context. Each pairing that advertises into the same document with the same H and link
leaves it as it is; a different H or link is refused as `x402/legal-context-conflict`. A challenge offering options
on several rails therefore carries one H, and the buyer's payment on any of them is bound to the same ATR.

## The request commitment

`requestCommitment({ method, target, body })` commits to the request the challenge answers: the method as received,
the request-target split at its first `?` into `path` and `query`, and `bodyDigest`, SHA-256 over the body bytes
exactly as received. The target is at most 8 KiB of visible ASCII starting with `/`, and the body at most 1 MiB.

`tie(accepts, request)` is the ATR's binding slot for every x402 pairing: `["x402", { accepts, request }]`, with every
option exactly as issued. `issuedDigest` is SHA-256 over the RFC 8785 form of one option or one commitment, for a
seller that keeps a digest of what it issued.

## Advertising several options

This example advertises one H into a challenge with two EVM options, one for EIP-3009 and one for Permit2, and shows
which pairing serves each option:

```ts
import { hash, pairingOf } from "@integraledger/lcp";
import {
  exactEip3009,
  exactPermit2,
  requestCommitment,
  type PaymentRequired,
  type PaymentRequirements,
} from "@integraledger/lcp/x402";

const base: PaymentRequirements = {
  scheme: "exact",
  network: "eip155:84532",
  amount: "10000",
  asset: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
  payTo: "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
  maxTimeoutSeconds: 60,
  extra: { name: "USDC", version: "2" },
};
const viaPermit2: PaymentRequirements = { ...base, extra: { ...base.extra, assetTransferMethod: "permit2" } };
const doc: PaymentRequired = {
  x402Version: 2,
  resource: { url: "https://api.seller.example/v1/quote" },
  accepts: [base, viaPermit2],
};

const h = await hash(new TextEncoder().encode("the ATR's bytes"));
const link = `https://atr.seller.example/${h}`;

const first = exactEip3009.advertise(doc, h, link, base);
if ("refused" in first) throw new Error(first.code);
const both = exactPermit2.advertise(first, h, link, viaPermit2);
if ("refused" in both) throw new Error(both.code);

console.log(pairingOf(base), pairingOf(viaPermit2));
const read = exactPermit2.read(both);
console.log("refused" in read ? read.code : `${read.offer.options.length} option, H ${read.h === h ? "matches" : "differs"}`);

const other = await hash(new TextEncoder().encode("another ATR"));
const clash = exactPermit2.advertise(first, other, link, viaPermit2);
console.log("refused" in clash ? clash.code : "placed");

console.log(await requestCommitment({ method: "POST", target: "/v1/quote?tier=1", body: new TextEncoder().encode("{}") }));
```

```text
x402/exact/eip155/eip3009 x402/exact/eip155/permit2
1 option, H matches
x402/legal-context-conflict
{
  method: 'POST',
  path: '/v1/quote',
  query: 'tier=1',
  bodyDigest: '0x44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a'
}
```

## The x402 pairings

The x402 pairings, by scheme. The [pairings reference](https://lcp.integraledger.com/reference/pairings) states what each one proves, and
[Rails](https://lcp.integraledger.com/guides/rails) gives each rail's field.

| Scheme                   | Pairings                                                                                                                                   | Where H rides                                                                                                                                         |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `exact` on EVM           | `x402/exact/eip155/eip3009`, `x402/exact/eip155/permit2`                                                                                   | The signed authorization's nonce.                                                                                                                     |
| `exact` on EVM, ERC-7710 | `x402/exact/eip155/erc7710-salt`, `x402/exact/eip155/erc7710`                                                                              | The salt of the redeemed leaf delegation, through MetaMask's DelegationManager; or, where the delegation signs no hash, the echoed extension only.    |
| `upto` on EVM            | `x402/upto/eip155/permit2`                                                                                                                 | The Permit2 nonce, for a signed maximum.                                                                                                              |
| `auth-capture` on EVM    | `x402/auth-capture/eip155/eip3009`, `x402/auth-capture/eip155/permit2`                                                                     | The escrow payment's salt, or its salt nonce when the option binds a receiver authorizer or policy.                                                   |
| `batch-settlement`       | `x402/batch-settlement/eip155`, `x402/batch-settlement/solana`, `x402/batch-settlement/cloudflare`                                         | The channel's salt, the opening transaction's memo, or each request's echoed extension. See [Channels, sessions and subscriptions](https://lcp.integraledger.com/guides/sessions). |
| `exact` on other rails   | Solana, Stellar, XRPL, Hedera, Algorand, Aptos, Cardano, Casper, Concordium, NEAR, Polkadot Asset Hub, Starknet, Sui, Tron, TON, Lightning | Each rail's own field; see [Rails](https://lcp.integraledger.com/guides/rails).                                                                                                    |
| `upto` on Solana         | `x402/upto/solana`                                                                                                                         | The Memo instruction of the transaction that opens a one-request payment channel.                                                                     |

## Building on x402

`build(choice, h)` takes the document, the chosen option, the payer's account and the time in Unix seconds:

```ts no-check
interface X402Choice {
  required: PaymentRequired;
  accepted: PaymentRequirements;
  from: Hex;
  now: number;
}
```

It returns what the buyer's signer signs, in the rail's own form, and `complete`, which turns the signer's answer into
the x402 payment. On `x402/exact/eip155/eip3009` that is EIP-712 typed data; on the other EVM pairings a request whose
`kind` names the form (`"eip712"`, or `"erc7710"` for a delegation); on other rails a transaction or message to sign.

## Reading the payment

`bound(payment)` reads H from the payment; `reference(payment)` gives the keys to find its settlement;
`status(ref, reader)` reads the settlement through an `EvmReader` you supply, which answers three JSON-RPC calls:
`eth_getTransactionReceipt`, `eth_getBlockByNumber` for the `safe` and `finalized` marks, and
`eth_getTransactionByHash`. A reader that throws `ReaderError`, or answers for another network, leaves the payment
pending, never failed. `pairingOfPayment(payment)` names the pairing that serves a presented EVM payment.
