Full lesson
agentbrake
Buyer-side verification for x402 AI-agent payments on Solana: owner-signed grants, live quote checks, one payment per purchase, chain-verified outcomes.
What it does
From the project README:
It is a buyer-side purchase execution and verification layer for x402 V2 `exact` payments on Solana (devnet, USDC). Agents never hold a wallet key: they can only ask the gateway to buy a catalog resource under a purchase id issued by a trusted orchestrator, and the gateway decides whether that exact payment may be signed, then proves on chain what happened.
- Original
- Bdysj/agentbrake
- SuperStack fork
- Blockchains/agentbrake @
7a2a74c - Stars
- 5
- Last push (original)
- 2026-10-12
- Languages
- TypeScript, Vue, Python, CSS, JavaScript, Shell
- Detected stack
- @solana/kitsolana-py
- Categories
- AI & AgentsPayments
- Licence
- MIT
Architecture
587 source files. By extension: .ts ×573, .py ×13, .js ×1.
| Top-level directory | Source files |
|---|---|
agent-brake-frontend | 551 |
x402-adapter | 17 |
agent-python | 13 |
mcp-server | 4 |
x402-facilitator | 1 |
demo-merchant | 1 |
Dapp: devnet deploy pending
⏳ Devnet deploy pending — goes live when the devnet wallet is topped up. This fork's own dapp is not deployed yet, so there is no program address or transaction to show. It is queued in dapp-queue.txt; once devnet SOL is available it is deployed, exercised with real devnet transactions, and this section switches to the live dapp at /dapps/agentbrake/. Until then, the lesson and step-by-step guide below are complete, and you can run it locally with the commands below.
Key code, explained
Excerpts chosen automatically where the code uses the most Solana concepts, pinned to the fork's commit.
x402-adapter/scripts/setup-merchant-ata.ts L73–96 @ 7a2a74c · MIT · original { address: payer.address, role: AccountRole.WRITABLE_SIGNER }, { address: ata, role: AccountRole.WRITABLE }, { address: address(owner), role: AccountRole.READONLY }, { address: address(mint), role: AccountRole.READONLY }, { address: address(SYSTEM_PROGRAM), role: AccountRole.READONLY }, { address: address(TOKEN_PROGRAM), role: AccountRole.READONLY }, ], data: new Uint8Array([1]), // CreateIdempotent });}if (instructions.length === 0) process.exit(0); const { value: latest } = await rpc.getLatestBlockhash({ commitment: "confirmed" }).send();const message = pipe( createTransactionMessage({ version: 0 }), (m) => setTransactionMessageFeePayerSigner(payer, m), (m) => setTransactionMessageLifetimeUsingBlockhash(latest, m), (m) => appendTransactionMessageInstructions(instructions, m),);const signed = await signTransactionMessageWithSigners(message);const sig = getSignatureFromTransaction(signed);await rpc.sendTransaction(getBase64EncodedWireTransaction(signed), { encoding: "base64" }).send();console.log(`sent ${sig}`);for (let i = 0; i < 40; i++) {- Line 85
const { value: latest } = await rpc.getLatestBlockhash({ commitment: "confirmed" }).send(): Fetches a recent blockhash. Transactions expire if it gets too old. - Line 94
await rpc.sendTransaction(getBase64EncodedWireTransaction(signed), { encoding: "base64" }): Submits the signed transaction to the cluster.
x402-adapter/scripts/fund-facilitator.ts L49–72 @ 7a2a74c · MIT · originalconst view = new DataView(data.buffer);view.setUint32(0, 2, true);view.setBigUint64(4, amount, true);const transfer: Instruction = { programAddress: address(SYSTEM_PROGRAM), accounts: [ { address: buyer.address, role: AccountRole.WRITABLE_SIGNER }, { address: address(feePayer), role: AccountRole.WRITABLE }, ], data,}; const { value: latest } = await rpc.getLatestBlockhash({ commitment: "confirmed" }).send();const message = pipe( createTransactionMessage({ version: 0 }), (m) => setTransactionMessageFeePayerSigner(buyer, m), (m) => setTransactionMessageLifetimeUsingBlockhash(latest, m), (m) => appendTransactionMessageInstructions([transfer], m),);const signed = await signTransactionMessageWithSigners(message);const sig = getSignatureFromTransaction(signed);await rpc.sendTransaction(getBase64EncodedWireTransaction(signed), { encoding: "base64" }).send();console.log(`sending ${Number(amount) / 1e9} SOL buyer -> fee payer: ${sig}`);for (let i = 0; i < 40; i++) {- Line 61
const { value: latest } = await rpc.getLatestBlockhash({ commitment: "confirmed" }).send(): Fetches a recent blockhash. Transactions expire if it gets too old. - Line 70
await rpc.sendTransaction(getBase64EncodedWireTransaction(signed), { encoding: "base64" }): Submits the signed transaction to the cluster.
How to run, build and test
These commands come from the repo's own manifests (package.json scripts, Anchor.toml, Cargo, go.mod, Makefile). Check the README for prerequisites and environment variables.
| Directory | Command | Runs |
|---|---|---|
mcp-server | npm run build | rm -rf dist && tsc -p tsconfig.json && chmod +x dist/bin.js |
x402-facilitator | npm run start | tsx src/server.ts |
x402-adapter | npm run dev | tsx watch src/server.ts |
x402-adapter | npm run start | tsx src/server.ts |
agent-brake-frontend | npm run dev | turbo-run dev |
agent-brake-frontend | npm run build | cross-env NODE_OPTIONS=--max-old-space-size=8192 turbo build |
agent-brake-frontend | npm run lint | vsh lint |
demo-merchant | npm run dev | tsx watch src/server.ts |
demo-merchant | npm run start | tsx src/server.ts |
What you could build from it
- Fork the SuperStack copy and extend it within the AI & Agents gaps listed on the idea page.
- Learn the pattern first: AI agents on Solana
- Learn the pattern first: Building and sending transactions from a client