Sol.College

Full lesson

agentswap

Open-source MCP and SDK for AgentSwap autonomous agent payments

What it does

From the project README:

Latest release: v0.3.0 — auditable payment intents. Release notes and upgrade instructions.
Original
pu0238/agentswap
SuperStack fork
Blockchains/agentswap @ d411ef0
Stars
0
Last push (original)
2026-10-08
Languages
TypeScript, JavaScript
Detected stack
@solana/kit
Categories
AI & AgentsDeFi
Licence
MIT
Homepage
https://agentswap.forge-3.workers.dev

Architecture

21 source files. By extension: .ts ×20, .py ×1.

Top-level directorySource files
src17
tests3
examples1

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/agentswap/. 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.

pu0238/agentswap · src/agentswap.ts L181–204 @ d411ef0 · MIT · original
      }      receipt.outcome = "payment_unknown";      await save(); // Persist the SAME signed authorization before a potentially ambiguous paid request.      const headers = new Headers(init?.headers);      for (const [key, value] of Object.entries(state.paymentHeaders)) headers.set(key, value);      log("Paying seller via x402", { intentId, network: chain.caip2, retry: receipt.retry });      const response = await globalThis.fetch(url, { ...init, headers, redirect: "error" });      const encoded = response.headers.get("PAYMENT-RESPONSE") ?? response.headers.get("X-PAYMENT-RESPONSE");      const settlement = encoded ? decodePaymentResponseHeader(encoded) : undefined;      receipt.seller = { httpStatus: response.status, ...(settlement ? { settlement } : {}) };      // A seller's 200 alone is not cryptographic settlement confirmation. Keep unknown outcomes explicit.      receipt.outcome = settlement?.success === true ? "confirmed" : settlement?.success === false || response.status === 402 ? "rejected" : "payment_unknown";      if (settlement?.transaction) log("Payment transaction", `${chain.explorerTx}${settlement.transaction}`);      await save();      return { response, receipt: structuredClone(receipt) };    } catch (error) {      if (state) {        if (state.receipt.funding.signature && error instanceof Error && /failed:/.test(error.message)) state.receipt.outcome = "failed";        // Keep the original exception if journaling itself fails; never broadcast after an unsuccessful save.        try { await save(); } catch { /* caller must reconcile the receipt/signature below */ }        throw new AgentSwapPaymentError(error instanceof Error ? error.message : String(error), structuredClone(state.receipt), { cause: error });      }      throw error;    } finally {
  1. Line 186 log("Paying seller via x402", { intentId, network: chain.caip2, retry: receipt.retry });: Uses x402, an HTTP 402 pattern where an agent pays per request with an on-chain payment.
  2. Line 187 const response = await globalThis.fetch(url, { ...init, headers, redirect: "error" });: Creates and pays for a new account. Space and payer must be specified.

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
.npm run buildtsc -p tsconfig.json
.npm run testtsc -p tsconfig.json && node --import tsx tests/client.test.ts && node --import tsx tests/sdk.test.ts && node --import t

What you could build from it

Used in lessons