agent402-client 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +39 -0
  2. package/index.js +94 -0
  3. package/package.json +40 -11
package/README.md CHANGED
@@ -63,6 +63,21 @@ const { messages } = await a.getWorkflowPrompt("security-audit", { domain: "stri
63
63
  // → feed messages straight to any LLM
64
64
  ```
65
65
 
66
+ ## Discover the live x402 economy
67
+
68
+ Want to see who's actually getting paid on x402 right now — not just what tools
69
+ this service exposes? `topSellers()` returns the live leaderboard of sellers
70
+ settling USDC (primarily on Base) in the last ~24h, derived from on-chain transfers. Free
71
+ to call (no payment, no proof-of-work):
72
+
73
+ ```js
74
+ const { window, asOf, results, totalSellers } = await a.topSellers({ limit: 10 });
75
+ // → { window: "24h", asOf, totalSellers, results: [{ rank, name, wallet, totalUsd, callsSettled, uniqueBuyers, ... }] }
76
+
77
+ // Rank by call volume instead of USDC, and include the host's own wallet:
78
+ await a.topSellers({ sort: "calls", include: "all" });
79
+ ```
80
+
66
81
  ## API
67
82
 
68
83
  | Method | What |
@@ -71,6 +86,7 @@ const { messages } = await a.getWorkflowPrompt("security-audit", { domain: "stri
71
86
  | `await a.find(task, { k = 5 })` | Resolve a plain-language task to the best-matching tools (route, price, schema, example) |
72
87
  | `await a.findWorkflows(task, { k = 2 })` | Resolve a task to matching multi-tool workflow templates (skill packs) |
73
88
  | `await a.getWorkflowPrompt(slug, args)` | Fetch the rendered prompt messages for a skill pack with arguments substituted in |
89
+ | `await a.topSellers({ limit?, sort?, include? })` | Live x402 leaderboard: which sellers are settling the most USDC (primarily on Base) in the last ~24h (free, no payment) |
74
90
  | `await a.call(slug, params, { idempotencyKey?, cache? })` | Call a tool; auto-pays (PoW for free tools, x402 for wallet-only); returns the JSON result |
75
91
  | `Agent402.solvePow(pow)` | Solve a proof-of-work challenge object → an `X-Pow-Solution` value |
76
92
  | `a.clearCache()` | Drop the in-memory result cache |
@@ -78,3 +94,26 @@ const { messages } = await a.getWorkflowPrompt("security-audit", { domain: "stri
78
94
  - **Zero dependencies** for the free/proof-of-work path (uses `node:crypto`).
79
95
  - **Non-custodial:** paid settlement is your `@x402/fetch` + wallet; this client never sees your key.
80
96
  - MIT licensed. Part of [Agent402](https://github.com/MikeyPetrillo/Agent402).
97
+
98
+ ## Pick the settlement chain (`withNetworkPreference`)
99
+
100
+ Multi-chain sellers list Base first, so an unmodified x402 client effectively
101
+ always settles there. To pin a chain — e.g. **USDG on Robinhood Chain** —
102
+ wrap your client before building the fetch:
103
+
104
+ ```js
105
+ import { withNetworkPreference } from "agent402-client";
106
+ import { x402Client } from "@x402/core/client";
107
+ import { registerExactEvmScheme } from "@x402/evm/exact/client";
108
+ import { wrapFetchWithPayment } from "@x402/fetch";
109
+
110
+ const client = new x402Client();
111
+ registerExactEvmScheme(client, { signer });
112
+ withNetworkPreference(client, ["robinhood"]); // or ["base","solana"], or ["eip155:4663"]
113
+ const payFetch = wrapFetchWithPayment(fetch, client);
114
+ ```
115
+
116
+ Short names map to CAIP-2 (`base`, `solana`, `polygon`, `arbitrum`,
117
+ `robinhood`); unknown entries pass through verbatim so future chains work
118
+ without a package update. If the preference matches none of a seller's
119
+ payment options it throws **before** any payment is signed.
package/index.js CHANGED
@@ -77,6 +77,59 @@ export class Agent402 {
77
77
  return r.json();
78
78
  }
79
79
 
80
+ /**
81
+ * Live x402 leaderboard — the sellers earning the most USDC (or serving the
82
+ * most calls) on Base in the last ~24h, derived from on-chain USDC
83
+ * transfers. Free; no payment, no wallet, no proof-of-work. Useful when
84
+ * building agents that want to discover the live x402 economy beyond a
85
+ * single service's catalog. Hourly snapshot — safe to call freely.
86
+ *
87
+ * @param {object} [opts]
88
+ * @param {number} [opts.limit=10] max rows (1-50)
89
+ * @param {"usd"|"calls"} [opts.sort="usd"] rank by USDC settled or call count
90
+ * @param {"external"|"all"} [opts.include="external"] hide this service's own wallet (default) or include it
91
+ * @returns {Promise<{window:string, asOf:string, sort:string, include:string, totalSellers:number, results:Array<object>, source:string}>}
92
+ */
93
+ async topSellers({ limit = 10, sort = "usd", include = "external" } = {}) {
94
+ const top = Math.min(Math.max(parseInt(limit, 10) || 10, 1), 50);
95
+ const sortParam = sort === "calls" ? "calls" : "usd";
96
+ const includeParam = include === "all" ? "all" : "external";
97
+ const url = `${this.baseUrl}/api/leaderboard?top=${top}&sort=${sortParam}&include=${includeParam}`;
98
+ const r = await this.f(url);
99
+ if (!r.ok) throw new Error(`topSellers failed: HTTP ${r.status}`);
100
+ const snap = await r.json();
101
+ return {
102
+ window: snap.windowLabel || snap.windowServed || "24h",
103
+ asOf: snap.asOf,
104
+ sort: snap.sortServed || sortParam,
105
+ include: snap.include || includeParam,
106
+ totalSellers: snap.totalSellers ?? (snap.leaderboard || []).length,
107
+ results: snap.leaderboard || [],
108
+ ...(snap.warming || snap.scanSkipped ? { warming: true } : {}),
109
+ source: `${this.baseUrl}/api/leaderboard`,
110
+ };
111
+ }
112
+
113
+ /**
114
+ * Register a wallet address for Base builder code attribution. Idempotent:
115
+ * the same wallet always returns the same code. No authentication required.
116
+ *
117
+ * @param {string} walletAddress the caller's wallet address (e.g. "0x…")
118
+ * @param {object} [opts]
119
+ * @param {typeof fetch} [opts.fetchImpl] plain fetch (defaults to global fetch)
120
+ * @returns {Promise<{builderCode:string, walletAddress:string}>}
121
+ */
122
+ static async registerBuilderCode(walletAddress, { fetchImpl = globalThis.fetch } = {}) {
123
+ if (!walletAddress || typeof walletAddress !== "string") throw new Error("walletAddress is required");
124
+ const r = await fetchImpl("https://api.base.dev/v1/agents/builder-codes", {
125
+ method: "POST",
126
+ headers: { "Content-Type": "application/json" },
127
+ body: JSON.stringify({ walletAddress }),
128
+ });
129
+ if (!r.ok) throw new Error(`builder code registration failed: HTTP ${r.status}`);
130
+ return r.json();
131
+ }
132
+
80
133
  /** Solve a proof-of-work challenge object (from a 402 body) into an X-Pow-Solution value. */
81
134
  static solvePow(pow) {
82
135
  let n = 0;
@@ -145,4 +198,45 @@ export class Agent402 {
145
198
  clearCache() { this._cache?.clear(); }
146
199
  }
147
200
 
201
+ /**
202
+ * Restrict + order which chains an @x402 client will pay on (duck-typed — any
203
+ * client version with createPaymentPayload works, zero new dependencies).
204
+ * Multi-chain sellers list Base first, so an unmodified client effectively
205
+ * always settles there; this makes rails like USDG on Robinhood Chain
206
+ * (eip155:4663) reachable:
207
+ *
208
+ * import { withNetworkPreference } from "agent402-client";
209
+ * withNetworkPreference(x402client, ["robinhood"]); // or ["eip155:4663"]
210
+ * const payFetch = wrapFetchWithPayment(fetch, x402client);
211
+ *
212
+ * Short names map to CAIP-2; unknown entries pass through verbatim so future
213
+ * chains work without a package update. Throws (before paying) when the
214
+ * preference matches none of a seller's payment options.
215
+ */
216
+ export const NETWORK_CAIP2 = {
217
+ base: "eip155:8453",
218
+ polygon: "eip155:137",
219
+ arbitrum: "eip155:42161",
220
+ "base-sepolia": "eip155:84532",
221
+ robinhood: "eip155:4663",
222
+ solana: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
223
+ "solana-devnet": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
224
+ };
225
+
226
+ export function withNetworkPreference(client, networks) {
227
+ const prefs = (networks || []).map((n) => NETWORK_CAIP2[String(n).trim().toLowerCase()] || String(n).trim());
228
+ if (!prefs.length) return client;
229
+ const orig = client.createPaymentPayload.bind(client);
230
+ client.createPaymentPayload = (paymentRequired) => {
231
+ const list = Array.isArray(paymentRequired?.accepts) ? paymentRequired.accepts : [];
232
+ const picked = prefs.flatMap((caip2) => list.filter((a) => String(a?.network || "").toLowerCase() === caip2.toLowerCase()));
233
+ if (!picked.length) {
234
+ const offered = [...new Set(list.map((a) => a?.network).filter(Boolean))];
235
+ throw new Error(`network preference [${prefs.join(", ")}] matched none of the seller's payment options [${offered.join(", ")}]`);
236
+ }
237
+ return orig({ ...paymentRequired, accepts: picked });
238
+ };
239
+ return client;
240
+ }
241
+
148
242
  export default Agent402;
package/package.json CHANGED
@@ -1,19 +1,48 @@
1
1
  {
2
2
  "name": "agent402-client",
3
- "version": "0.2.1",
4
- "description": "Tiny buyer-side client for Agent402 (x402): resolve a task to a tool and call it with payment handled for you — free tools settle via built-in proof-of-work (no wallet), wallet-only tools via your x402 fetch. Caching + idempotent retries.",
3
+ "version": "0.4.0",
4
+ "description": "Buyer-side SDK for Agent402.Tools (x402): resolve a task to a tool across 1,338 pay-per-call endpoints and call it with payment handled for you — free tools settle via built-in proof-of-work (no wallet), wallet-only tools via your x402 fetch — with a withNetworkPreference helper to pick the settlement chain (USDC on Base/Solana/Polygon/Arbitrum or USDG on Robinhood Chain). Caching, idempotent retries, cross-seller Smart Order Router.",
5
5
  "type": "module",
6
6
  "main": "index.js",
7
- "exports": { ".": "./index.js" },
8
- "files": ["index.js", "README.md"],
9
- "engines": { "node": ">=18" },
10
- "scripts": { "test": "node test.js" },
7
+ "exports": {
8
+ ".": "./index.js"
9
+ },
10
+ "files": [
11
+ "index.js",
12
+ "README.md"
13
+ ],
14
+ "engines": {
15
+ "node": ">=18"
16
+ },
17
+ "scripts": {
18
+ "test": "node test.js"
19
+ },
11
20
  "keywords": [
12
- "x402", "ai-agents", "agent-tools", "llm-tools", "usdc", "base",
13
- "proof-of-work", "http-402", "micropayments", "mcp", "client", "sdk"
21
+ "x402",
22
+ "ai-agents",
23
+ "agent-tools",
24
+ "llm-tools",
25
+ "usdc",
26
+ "base",
27
+ "proof-of-work",
28
+ "http-402",
29
+ "micropayments",
30
+ "mcp",
31
+ "client",
32
+ "sdk",
33
+ "agent402",
34
+ "tool-discovery",
35
+ "smart-order-router",
36
+ "robinhood-chain",
37
+ "usdg",
38
+ "multi-chain"
14
39
  ],
15
- "author": "Mikey Petrillo (https://github.com/MikeyPetrillo)",
40
+ "author": "Mike Petrillo <mike@agent402.tools> (https://github.com/MikeyPetrillo)",
16
41
  "license": "MIT",
17
- "repository": { "type": "git", "url": "https://github.com/MikeyPetrillo/Agent402.git", "directory": "client" },
18
- "homepage": "https://github.com/MikeyPetrillo/Agent402/tree/main/client"
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "https://github.com/MikeyPetrillo/Agent402.git",
45
+ "directory": "client"
46
+ },
47
+ "homepage": "https://agent402.tools"
19
48
  }