Sol.College

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 directorySource files
agent-brake-frontend551
x402-adapter17
agent-python13
mcp-server4
x402-facilitator1
demo-merchant1

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.

Bdysj/agentbrake · 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++) {
  1. Line 85 const { value: latest } = await rpc.getLatestBlockhash({ commitment: "confirmed" }).send(): Fetches a recent blockhash. Transactions expire if it gets too old.
  2. Line 94 await rpc.sendTransaction(getBase64EncodedWireTransaction(signed), { encoding: "base64" }): Submits the signed transaction to the cluster.
Bdysj/agentbrake · x402-adapter/scripts/fund-facilitator.ts L49–72 @ 7a2a74c · MIT · original
const 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++) {
  1. Line 61 const { value: latest } = await rpc.getLatestBlockhash({ commitment: "confirmed" }).send(): Fetches a recent blockhash. Transactions expire if it gets too old.
  2. 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.

DirectoryCommandRuns
mcp-servernpm run buildrm -rf dist && tsc -p tsconfig.json && chmod +x dist/bin.js
x402-facilitatornpm run starttsx src/server.ts
x402-adapternpm run devtsx watch src/server.ts
x402-adapternpm run starttsx src/server.ts
agent-brake-frontendnpm run devturbo-run dev
agent-brake-frontendnpm run buildcross-env NODE_OPTIONS=--max-old-space-size=8192 turbo build
agent-brake-frontendnpm run lintvsh lint
demo-merchantnpm run devtsx watch src/server.ts
demo-merchantnpm run starttsx src/server.ts

What you could build from it

Used in lessons