diff --git a/docs/build/agentic-payments/x402/README.mdx b/docs/build/agentic-payments/x402/README.mdx index be5e26050..0126f2140 100644 --- a/docs/build/agentic-payments/x402/README.mdx +++ b/docs/build/agentic-payments/x402/README.mdx @@ -36,6 +36,26 @@ Freighter Mobile does not currently support x402; use the Freighter browser exte ::: +## Supported Assets + +x402 on Stellar supports any [SEP-41](https://stellar.org/protocol/sep-41) compliant token. The default is USDC. + +### Testnet USDC + +| Property | Value | +| --------------- | ---------------------------------------------------------- | +| Asset Code | `USDC` | +| Issuer | `GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5` | +| SEP-41 Contract | `CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA` | + +### Mainnet USDC + +| Property | Value | +| --------------- | ---------------------------------------------------------- | +| Asset Code | `USDC` | +| Issuer | `GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN` | +| SEP-41 Contract | `CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75` | + ## x402 Facilitators You can use a facilitator to verify and settle x402 payments. Two options are available for Stellar: diff --git a/docs/build/agentic-payments/x402/built-on-stellar.mdx b/docs/build/agentic-payments/x402/built-on-stellar.mdx index 0cf4b6126..cc9f0ded7 100644 --- a/docs/build/agentic-payments/x402/built-on-stellar.mdx +++ b/docs/build/agentic-payments/x402/built-on-stellar.mdx @@ -29,14 +29,23 @@ Built with the [OpenZeppelin Relayer][oz-relayer] and the [x402 Facilitator Plug | **x402 scheme** | `exact` | `exact` | | **Supported assets** | Any [SEP-41] token (defaults to USDC) | Any [SEP-41] token (defaults to USDC) | +Verify endpoint availability: + +```bash +curl -I https://channels.openzeppelin.com/x402/supported +# Expected: HTTP 200 with supported assets/networks +``` + ## Get started ### 1. Generate an API key Generate an API key for the network you want to use: -- **Testnet**: https://channels.openzeppelin.com/testnet/gen -- **Mainnet**: https://channels.openzeppelin.com/gen +- **Testnet**: https://channels.openzeppelin.com/testnet/gen (no authentication required) +- **Mainnet**: https://channels.openzeppelin.com/gen (requires GitHub OAuth) + +Store the generated API key securely. It cannot be retrieved after creation. ### 2. Configure the facilitator URL @@ -137,6 +146,25 @@ When a payment is received, the facilitator: After verification, the facilitator submits the payment on-chain via the OpenZeppelin Relayer and returns confirmation to the server. +## Understanding Soroban authorization + +x402 on Stellar uses Soroban's authorization model rather than pre-signed transactions. When a client pays for a resource, they sign an **authorization entry** - a statement that authorizes a specific contract call. + +### What the client signs + +The authorization entry contains: + +- **Contract ID**: The USDC token contract +- **Function**: `transfer` +- **Arguments**: `from` (payer), `to` (recipient), `amount` +- **Expiration**: When this authorization expires + +This approach provides several benefits: + +- The facilitator can wrap the auth entry with sponsored fees +- No sequence number conflicts +- Built-in replay protection via expiration + ## Supported features - **Networks**: `stellar:testnet`, `stellar:pubnet` ([CAIP-2](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-2.md) identifiers) diff --git a/docs/build/agentic-payments/x402/quickstart-guide.mdx b/docs/build/agentic-payments/x402/quickstart-guide.mdx index 82032e38f..45b7ecff3 100644 --- a/docs/build/agentic-payments/x402/quickstart-guide.mdx +++ b/docs/build/agentic-payments/x402/quickstart-guide.mdx @@ -190,16 +190,42 @@ main().catch((error) => { }); ``` +### Handling payment responses + +When integrating x402 into your own client, handle the key response states: + +```js +const response = await fetch(protectedUrl, { headers: paymentHeaders }); + +if (response.status === 402) { + const paymentRequired = response.headers.get("X-Payment"); + console.error("Payment required:", paymentRequired); + // Re-initiate payment flow +} else if (response.status === 200) { + const data = await response.json(); + console.log("Access granted:", data); +} else { + console.error("Unexpected error:", response.status); +} +``` + ### Setting up a testnet wallet Next, create a fresh account and fund it with testnet XLM and testnet USDC using Stellar Lab: - [Fund a testnet account in Stellar Lab](https://lab.stellar.org/account/fund) -1. Create a new keypair using Stellar Lab: https://lab.stellar.org/account/create +1. Create a new keypair using [Stellar Lab](https://lab.stellar.org/account/create) or the CLI: + +```bash +stellar keys generate --network testnet my-x402-wallet +stellar keys address my-x402-wallet # Returns G... public key +stellar keys show my-x402-wallet # Returns S... secret key +``` + 2. Fund with testnet XLM (Native Stellar Token): https://lab.stellar.org/account/fund -3. Create the USDC trustline (there's a button on the fund page above), sign and submit that transaction -4. Visit the circle faucet, select Stellar Testnet from the networks and add your public key for the wallet address input: https://faucet.circle.com +3. Create the USDC trustline (there's a button on the fund page above), sign and submit that transaction (for detailed instructions, [see below](#step-3-establish-usdc-trustline)) +4. Visit the Circle faucet, select Stellar Testnet from the networks and add your public key for the wallet address input: https://faucet.circle.com Create a local environment file for the client and add your Stellar testnet secret key: @@ -215,6 +241,55 @@ Secret keys provide full access to any digital assets held within the wallet. Us ::: +### Step 3 (expanded): Establish USDC trustline + +A trustline tells Stellar your account accepts USDC. Without it, you cannot receive payments. + +**Testnet USDC Issuer:** `GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5` + +#### Using Stellar Lab + +1. Go to [Transaction Builder](https://laboratory.stellar.org/#txbuilder?network=test) +2. Enter your public key as source account +3. Click "Fetch next sequence number" +4. Add Operation → "Change Trust" +5. Asset Code: `USDC` +6. Issuer: `GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5` +7. Sign and submit + +#### Using code + +```javascript +import { + Keypair, + Networks, + TransactionBuilder, + Operation, + Asset, + Horizon, +} from "@stellar/stellar-sdk"; + +const server = new Horizon.Server("https://horizon-testnet.stellar.org"); +const keypair = Keypair.fromSecret(process.env.STELLAR_PRIVATE_KEY); +const account = await server.loadAccount(keypair.publicKey()); + +const USDC = new Asset( + "USDC", + "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", +); + +const tx = new TransactionBuilder(account, { + fee: "100", + networkPassphrase: Networks.TESTNET, +}) + .addOperation(Operation.changeTrust({ asset: USDC })) + .setTimeout(30) + .build(); + +tx.sign(keypair); +await server.submitTransaction(tx); +``` + ## Run The Client Once the account is funded and the secret key is in `.env`, run the client in a second terminal: