@goplausible/openclaw-algorand-plugin 0.5.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 (112) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +112 -0
  3. package/index.ts +361 -0
  4. package/lib/mcp-servers.ts +14 -0
  5. package/lib/x402-fetch.ts +213 -0
  6. package/memory/algorand-plugin.md +82 -0
  7. package/openclaw.plugin.json +30 -0
  8. package/package.json +41 -0
  9. package/setup.ts +80 -0
  10. package/skills/algorand-development/SKILL.md +90 -0
  11. package/skills/algorand-development/references/build-smart-contracts-reference.md +79 -0
  12. package/skills/algorand-development/references/build-smart-contracts.md +52 -0
  13. package/skills/algorand-development/references/create-project-reference.md +86 -0
  14. package/skills/algorand-development/references/create-project.md +89 -0
  15. package/skills/algorand-development/references/implement-arc-standards-arc32-arc56.md +396 -0
  16. package/skills/algorand-development/references/implement-arc-standards-arc4.md +265 -0
  17. package/skills/algorand-development/references/implement-arc-standards.md +92 -0
  18. package/skills/algorand-development/references/search-algorand-examples-reference.md +119 -0
  19. package/skills/algorand-development/references/search-algorand-examples.md +89 -0
  20. package/skills/algorand-development/references/troubleshoot-errors-contract.md +373 -0
  21. package/skills/algorand-development/references/troubleshoot-errors-transaction.md +599 -0
  22. package/skills/algorand-development/references/troubleshoot-errors.md +105 -0
  23. package/skills/algorand-development/references/use-algokit-cli-reference.md +228 -0
  24. package/skills/algorand-development/references/use-algokit-cli.md +64 -0
  25. package/skills/algorand-interaction/SKILL.md +223 -0
  26. package/skills/algorand-interaction/references/algorand-mcp.md +743 -0
  27. package/skills/algorand-interaction/references/examples-algorand-mcp.md +647 -0
  28. package/skills/algorand-python/SKILL.md +95 -0
  29. package/skills/algorand-python/references/build-smart-contracts-decorators.md +413 -0
  30. package/skills/algorand-python/references/build-smart-contracts-reference.md +55 -0
  31. package/skills/algorand-python/references/build-smart-contracts-storage.md +452 -0
  32. package/skills/algorand-python/references/build-smart-contracts-transactions.md +445 -0
  33. package/skills/algorand-python/references/build-smart-contracts-types.md +438 -0
  34. package/skills/algorand-python/references/build-smart-contracts.md +82 -0
  35. package/skills/algorand-python/references/create-project-reference.md +55 -0
  36. package/skills/algorand-python/references/create-project.md +75 -0
  37. package/skills/algorand-python/references/implement-arc-standards-arc32-arc56.md +101 -0
  38. package/skills/algorand-python/references/implement-arc-standards-arc4.md +154 -0
  39. package/skills/algorand-python/references/implement-arc-standards.md +39 -0
  40. package/skills/algorand-python/references/troubleshoot-errors-contract.md +355 -0
  41. package/skills/algorand-python/references/troubleshoot-errors-transaction.md +430 -0
  42. package/skills/algorand-python/references/troubleshoot-errors.md +46 -0
  43. package/skills/algorand-python/references/use-algokit-utils-reference.md +350 -0
  44. package/skills/algorand-python/references/use-algokit-utils.md +76 -0
  45. package/skills/algorand-typescript/SKILL.md +131 -0
  46. package/skills/algorand-typescript/references/algorand-ts-migration-from-beta.md +448 -0
  47. package/skills/algorand-typescript/references/algorand-ts-migration-from-tealscript.md +487 -0
  48. package/skills/algorand-typescript/references/algorand-ts-migration.md +102 -0
  49. package/skills/algorand-typescript/references/algorand-typescript-syntax-methods-and-abi.md +134 -0
  50. package/skills/algorand-typescript/references/algorand-typescript-syntax-reference.md +58 -0
  51. package/skills/algorand-typescript/references/algorand-typescript-syntax-storage.md +154 -0
  52. package/skills/algorand-typescript/references/algorand-typescript-syntax-transactions.md +187 -0
  53. package/skills/algorand-typescript/references/algorand-typescript-syntax-types-and-values.md +150 -0
  54. package/skills/algorand-typescript/references/algorand-typescript-syntax.md +84 -0
  55. package/skills/algorand-typescript/references/build-smart-contracts-reference.md +52 -0
  56. package/skills/algorand-typescript/references/build-smart-contracts.md +74 -0
  57. package/skills/algorand-typescript/references/call-smart-contracts-reference.md +237 -0
  58. package/skills/algorand-typescript/references/call-smart-contracts.md +183 -0
  59. package/skills/algorand-typescript/references/create-project-reference.md +53 -0
  60. package/skills/algorand-typescript/references/create-project.md +86 -0
  61. package/skills/algorand-typescript/references/deploy-react-frontend-examples.md +527 -0
  62. package/skills/algorand-typescript/references/deploy-react-frontend-reference.md +412 -0
  63. package/skills/algorand-typescript/references/deploy-react-frontend.md +239 -0
  64. package/skills/algorand-typescript/references/implement-arc-standards-arc32-arc56.md +73 -0
  65. package/skills/algorand-typescript/references/implement-arc-standards-arc4.md +126 -0
  66. package/skills/algorand-typescript/references/implement-arc-standards.md +44 -0
  67. package/skills/algorand-typescript/references/test-smart-contracts-examples.md +245 -0
  68. package/skills/algorand-typescript/references/test-smart-contracts-unit-tests.md +147 -0
  69. package/skills/algorand-typescript/references/test-smart-contracts.md +127 -0
  70. package/skills/algorand-typescript/references/troubleshoot-errors-contract.md +296 -0
  71. package/skills/algorand-typescript/references/troubleshoot-errors-transaction.md +438 -0
  72. package/skills/algorand-typescript/references/troubleshoot-errors.md +56 -0
  73. package/skills/algorand-typescript/references/use-algokit-utils-reference.md +342 -0
  74. package/skills/algorand-typescript/references/use-algokit-utils.md +74 -0
  75. package/skills/algorand-x402-python/SKILL.md +113 -0
  76. package/skills/algorand-x402-python/references/create-python-x402-client-examples.md +469 -0
  77. package/skills/algorand-x402-python/references/create-python-x402-client-reference.md +313 -0
  78. package/skills/algorand-x402-python/references/create-python-x402-client.md +207 -0
  79. package/skills/algorand-x402-python/references/create-python-x402-facilitator-examples.md +924 -0
  80. package/skills/algorand-x402-python/references/create-python-x402-facilitator-reference.md +629 -0
  81. package/skills/algorand-x402-python/references/create-python-x402-facilitator.md +408 -0
  82. package/skills/algorand-x402-python/references/create-python-x402-server-examples.md +703 -0
  83. package/skills/algorand-x402-python/references/create-python-x402-server-reference.md +303 -0
  84. package/skills/algorand-x402-python/references/create-python-x402-server.md +221 -0
  85. package/skills/algorand-x402-python/references/explain-algorand-x402-python-examples.md +605 -0
  86. package/skills/algorand-x402-python/references/explain-algorand-x402-python-reference.md +315 -0
  87. package/skills/algorand-x402-python/references/explain-algorand-x402-python.md +167 -0
  88. package/skills/algorand-x402-python/references/use-python-x402-core-avm-examples.md +554 -0
  89. package/skills/algorand-x402-python/references/use-python-x402-core-avm-reference.md +278 -0
  90. package/skills/algorand-x402-python/references/use-python-x402-core-avm.md +166 -0
  91. package/skills/algorand-x402-typescript/SKILL.md +129 -0
  92. package/skills/algorand-x402-typescript/references/create-typescript-x402-client-examples.md +879 -0
  93. package/skills/algorand-x402-typescript/references/create-typescript-x402-client-reference.md +371 -0
  94. package/skills/algorand-x402-typescript/references/create-typescript-x402-client.md +236 -0
  95. package/skills/algorand-x402-typescript/references/create-typescript-x402-facilitator-examples.md +875 -0
  96. package/skills/algorand-x402-typescript/references/create-typescript-x402-facilitator-reference.md +461 -0
  97. package/skills/algorand-x402-typescript/references/create-typescript-x402-facilitator.md +270 -0
  98. package/skills/algorand-x402-typescript/references/create-typescript-x402-nextjs-examples.md +1181 -0
  99. package/skills/algorand-x402-typescript/references/create-typescript-x402-nextjs-reference.md +360 -0
  100. package/skills/algorand-x402-typescript/references/create-typescript-x402-nextjs.md +251 -0
  101. package/skills/algorand-x402-typescript/references/create-typescript-x402-paywall-examples.md +870 -0
  102. package/skills/algorand-x402-typescript/references/create-typescript-x402-paywall-reference.md +323 -0
  103. package/skills/algorand-x402-typescript/references/create-typescript-x402-paywall.md +281 -0
  104. package/skills/algorand-x402-typescript/references/create-typescript-x402-server-examples.md +1135 -0
  105. package/skills/algorand-x402-typescript/references/create-typescript-x402-server-reference.md +382 -0
  106. package/skills/algorand-x402-typescript/references/create-typescript-x402-server.md +216 -0
  107. package/skills/algorand-x402-typescript/references/explain-algorand-x402-typescript-examples.md +616 -0
  108. package/skills/algorand-x402-typescript/references/explain-algorand-x402-typescript-reference.md +323 -0
  109. package/skills/algorand-x402-typescript/references/explain-algorand-x402-typescript.md +232 -0
  110. package/skills/algorand-x402-typescript/references/use-typescript-x402-core-avm-examples.md +1417 -0
  111. package/skills/algorand-x402-typescript/references/use-typescript-x402-core-avm-reference.md +504 -0
  112. package/skills/algorand-x402-typescript/references/use-typescript-x402-core-avm.md +158 -0
@@ -0,0 +1,875 @@
1
+ # x402 Facilitator Examples
2
+
3
+ ## FacilitatorAvmSigner Implementation
4
+
5
+ ```typescript
6
+ import algosdk from "algosdk";
7
+ import type { FacilitatorAvmSigner } from "@x402-avm/avm";
8
+
9
+ const secretKey = Buffer.from(process.env.AVM_PRIVATE_KEY!, "base64");
10
+ const address = algosdk.encodeAddress(secretKey.slice(32));
11
+ const algodClient = new algosdk.Algodv2("", "https://testnet-api.algonode.cloud", "");
12
+
13
+ const facilitatorSigner: FacilitatorAvmSigner = {
14
+ getAddresses: () => [address],
15
+
16
+ signTransaction: async (txn: Uint8Array, senderAddress: string) => {
17
+ const decoded = algosdk.decodeUnsignedTransaction(txn);
18
+ const signed = algosdk.signTransaction(decoded, secretKey);
19
+ return signed.blob;
20
+ },
21
+
22
+ getAlgodClient: (network: string) => algodClient,
23
+
24
+ simulateTransactions: async (txns: Uint8Array[], network: string) => {
25
+ const stxns = txns.map((txnBytes) => {
26
+ try {
27
+ return algosdk.decodeSignedTransaction(txnBytes);
28
+ } catch {
29
+ const txn = algosdk.decodeUnsignedTransaction(txnBytes);
30
+ return new algosdk.SignedTransaction({ txn });
31
+ }
32
+ });
33
+ const request = new algosdk.modelsv2.SimulateRequest({
34
+ txnGroups: [
35
+ new algosdk.modelsv2.SimulateRequestTransactionGroup({ txns: stxns }),
36
+ ],
37
+ allowEmptySignatures: true,
38
+ });
39
+ return algodClient.simulateTransactions(request).do();
40
+ },
41
+
42
+ sendTransactions: async (signedTxns: Uint8Array[], network: string) => {
43
+ const combined = Buffer.concat(signedTxns.map((t) => Buffer.from(t)));
44
+ const { txId } = await algodClient.sendRawTransaction(combined).do();
45
+ return txId;
46
+ },
47
+
48
+ waitForConfirmation: async (txId: string, network: string, waitRounds = 4) => {
49
+ return algosdk.waitForConfirmation(algodClient, txId, waitRounds);
50
+ },
51
+ };
52
+ ```
53
+
54
+ ---
55
+
56
+ ## Facilitator Setup and Scheme Registration
57
+
58
+ ```typescript
59
+ import { x402Facilitator } from "@x402-avm/core/facilitator";
60
+ import { registerExactAvmScheme } from "@x402-avm/avm/exact/facilitator";
61
+ import { ALGORAND_TESTNET_CAIP2 } from "@x402-avm/avm";
62
+
63
+ const facilitator = new x402Facilitator();
64
+
65
+ registerExactAvmScheme(facilitator, {
66
+ signer: facilitatorSigner,
67
+ networks: ALGORAND_TESTNET_CAIP2,
68
+ });
69
+ ```
70
+
71
+ ---
72
+
73
+ ## Basic Express.js Facilitator Server
74
+
75
+ ```typescript
76
+ import express from "express";
77
+ import { x402Facilitator } from "@x402-avm/core/facilitator";
78
+ import { registerExactAvmScheme } from "@x402-avm/avm/exact/facilitator";
79
+ import { ALGORAND_TESTNET_CAIP2 } from "@x402-avm/avm";
80
+ import algosdk from "algosdk";
81
+
82
+ const secretKey = Buffer.from(process.env.AVM_PRIVATE_KEY!, "base64");
83
+ const address = algosdk.encodeAddress(secretKey.slice(32));
84
+ const algodClient = new algosdk.Algodv2("", "https://testnet-api.algonode.cloud", "");
85
+
86
+ const signer = {
87
+ getAddresses: () => [address],
88
+ signTransaction: async (txn: Uint8Array, _addr: string) => {
89
+ const decoded = algosdk.decodeUnsignedTransaction(txn);
90
+ return algosdk.signTransaction(decoded, secretKey).blob;
91
+ },
92
+ getAlgodClient: () => algodClient,
93
+ simulateTransactions: async (txns: Uint8Array[]) => {
94
+ const stxns = txns.map((t) => {
95
+ try { return algosdk.decodeSignedTransaction(t); }
96
+ catch { return new algosdk.SignedTransaction({ txn: algosdk.decodeUnsignedTransaction(t) }); }
97
+ });
98
+ const req = new algosdk.modelsv2.SimulateRequest({
99
+ txnGroups: [new algosdk.modelsv2.SimulateRequestTransactionGroup({ txns: stxns })],
100
+ allowEmptySignatures: true,
101
+ });
102
+ return algodClient.simulateTransactions(req).do();
103
+ },
104
+ sendTransactions: async (signedTxns: Uint8Array[]) => {
105
+ const combined = Buffer.concat(signedTxns.map((t) => Buffer.from(t)));
106
+ const { txId } = await algodClient.sendRawTransaction(combined).do();
107
+ return txId;
108
+ },
109
+ waitForConfirmation: async (txId: string, _net: string, rounds = 4) => {
110
+ return algosdk.waitForConfirmation(algodClient, txId, rounds);
111
+ },
112
+ };
113
+
114
+ const facilitator = new x402Facilitator();
115
+ registerExactAvmScheme(facilitator, { signer, networks: ALGORAND_TESTNET_CAIP2 });
116
+
117
+ const app = express();
118
+ app.use(express.json());
119
+
120
+ app.get("/supported", async (_req, res) => {
121
+ const supported = facilitator.getSupportedNetworks();
122
+ res.json(supported);
123
+ });
124
+
125
+ app.post("/verify", async (req, res) => {
126
+ const { paymentPayload, paymentRequirements } = req.body;
127
+ const result = await facilitator.verify(paymentPayload, paymentRequirements);
128
+ res.json(result);
129
+ });
130
+
131
+ app.post("/settle", async (req, res) => {
132
+ const { paymentPayload, paymentRequirements } = req.body;
133
+ const result = await facilitator.settle(paymentPayload, paymentRequirements);
134
+ res.json(result);
135
+ });
136
+
137
+ app.listen(4000, () => console.log("Facilitator running on :4000"));
138
+ ```
139
+
140
+ ---
141
+
142
+ ## Facilitator with Lifecycle Hooks
143
+
144
+ ```typescript
145
+ const facilitator = new x402Facilitator();
146
+ registerExactAvmScheme(facilitator, { signer, networks: ALGORAND_TESTNET_CAIP2 });
147
+
148
+ facilitator.onBeforeVerify(async (context) => {
149
+ console.log(`Verifying payment for ${context.requirements.resource}`);
150
+ });
151
+
152
+ facilitator.onAfterSettle(async (context) => {
153
+ if (context.result.success) {
154
+ console.log(`Settled: ${context.result.txId}`);
155
+ } else {
156
+ console.error(`Settlement failed: ${context.result.error}`);
157
+ }
158
+ });
159
+ ```
160
+
161
+ ---
162
+
163
+ ## Bazaar: Declaring Discovery Extension (Resource Server)
164
+
165
+ ```typescript
166
+ import {
167
+ declareDiscoveryExtension,
168
+ BAZAAR,
169
+ } from "@x402-avm/extensions";
170
+
171
+ // GET endpoint with query parameters
172
+ const weatherExtension = declareDiscoveryExtension({
173
+ input: { city: "San Francisco", units: "metric" },
174
+ inputSchema: {
175
+ properties: {
176
+ city: { type: "string", description: "City name" },
177
+ units: {
178
+ type: "string",
179
+ enum: ["metric", "imperial"],
180
+ description: "Temperature units",
181
+ },
182
+ },
183
+ required: ["city"],
184
+ },
185
+ output: {
186
+ example: {
187
+ temperature: 18.5,
188
+ condition: "Partly Cloudy",
189
+ humidity: 65,
190
+ },
191
+ schema: {
192
+ properties: {
193
+ temperature: { type: "number" },
194
+ condition: { type: "string" },
195
+ humidity: { type: "number" },
196
+ },
197
+ },
198
+ },
199
+ });
200
+ ```
201
+
202
+ ---
203
+
204
+ ## Bazaar: GET Endpoint with No Input
205
+
206
+ ```typescript
207
+ const priceExtension = declareDiscoveryExtension({
208
+ output: {
209
+ example: {
210
+ price: 42000.50,
211
+ currency: "USD",
212
+ timestamp: "2025-01-01T00:00:00Z",
213
+ },
214
+ },
215
+ });
216
+ ```
217
+
218
+ ---
219
+
220
+ ## Bazaar: POST Endpoint with JSON Body
221
+
222
+ ```typescript
223
+ const analysisExtension = declareDiscoveryExtension({
224
+ bodyType: "json",
225
+ input: {
226
+ text: "Analyze this text for sentiment",
227
+ language: "en",
228
+ },
229
+ inputSchema: {
230
+ properties: {
231
+ text: { type: "string", maxLength: 10000 },
232
+ language: { type: "string", enum: ["en", "es", "fr", "de"] },
233
+ },
234
+ required: ["text"],
235
+ },
236
+ output: {
237
+ example: {
238
+ sentiment: "positive",
239
+ confidence: 0.92,
240
+ keywords: ["analyze", "sentiment"],
241
+ },
242
+ },
243
+ });
244
+ ```
245
+
246
+ ---
247
+
248
+ ## Bazaar: POST Endpoint with Form-Data Body
249
+
250
+ ```typescript
251
+ const uploadExtension = declareDiscoveryExtension({
252
+ bodyType: "form-data",
253
+ input: {
254
+ file: "(binary)",
255
+ description: "A photo to process",
256
+ },
257
+ inputSchema: {
258
+ properties: {
259
+ file: { type: "string", format: "binary" },
260
+ description: { type: "string" },
261
+ },
262
+ required: ["file"],
263
+ },
264
+ output: {
265
+ example: {
266
+ processedUrl: "https://cdn.example.com/processed/abc123.jpg",
267
+ width: 1920,
268
+ height: 1080,
269
+ },
270
+ },
271
+ });
272
+ ```
273
+
274
+ ---
275
+
276
+ ## Bazaar: Resource Server Extension Registration
277
+
278
+ ```typescript
279
+ import {
280
+ x402HTTPResourceServer,
281
+ HTTPFacilitatorClient,
282
+ } from "@x402-avm/core/server";
283
+ import { registerExactAvmScheme } from "@x402-avm/avm/exact/server";
284
+ import {
285
+ bazaarResourceServerExtension,
286
+ declareDiscoveryExtension,
287
+ } from "@x402-avm/extensions";
288
+ import { ALGORAND_TESTNET_CAIP2, USDC_TESTNET_ASA_ID } from "@x402-avm/avm";
289
+
290
+ const facilitatorClient = new HTTPFacilitatorClient({
291
+ url: "https://facilitator.example.com",
292
+ });
293
+
294
+ const httpServer = new x402HTTPResourceServer(facilitatorClient, {
295
+ routes: [
296
+ {
297
+ path: "/api/weather",
298
+ config: {
299
+ scheme: "exact",
300
+ payTo: "RECEIVER_ALGORAND_ADDRESS_58_CHARS_AAAAAAAAAAAAAAAAAAA",
301
+ price: {
302
+ asset: USDC_TESTNET_ASA_ID,
303
+ amount: "10000",
304
+ extra: { name: "USDC", decimals: 6 },
305
+ },
306
+ network: ALGORAND_TESTNET_CAIP2,
307
+ maxTimeoutSeconds: 60,
308
+ },
309
+ description: "Weather data API",
310
+ mimeType: "application/json",
311
+ },
312
+ ],
313
+ });
314
+
315
+ registerExactAvmScheme(httpServer.resourceServer);
316
+ httpServer.resourceServer.registerExtension(bazaarResourceServerExtension);
317
+ ```
318
+
319
+ ---
320
+
321
+ ## Bazaar: Extracting Discovery Info (Facilitator)
322
+
323
+ ```typescript
324
+ import {
325
+ extractDiscoveryInfo,
326
+ validateDiscoveryExtension,
327
+ validateAndExtract,
328
+ extractDiscoveryInfoFromExtension,
329
+ type DiscoveryInfo,
330
+ type DiscoveredResource,
331
+ type ValidationResult,
332
+ } from "@x402-avm/extensions";
333
+ import type { PaymentPayload, PaymentRequirements } from "@x402-avm/core/types";
334
+
335
+ // Method 1: Full extraction from payload + requirements
336
+ async function processPaymentWithDiscovery(
337
+ paymentPayload: PaymentPayload,
338
+ paymentRequirements: PaymentRequirements,
339
+ ) {
340
+ const discovered: DiscoveredResource | null = extractDiscoveryInfo(
341
+ paymentPayload,
342
+ paymentRequirements,
343
+ );
344
+
345
+ if (discovered) {
346
+ console.log("Resource URL:", discovered.resourceUrl);
347
+ console.log("HTTP Method:", discovered.method);
348
+ console.log("x402 Version:", discovered.x402Version);
349
+ console.log("Description:", discovered.description);
350
+ console.log("MIME Type:", discovered.mimeType);
351
+ console.log("Discovery Info:", discovered.discoveryInfo);
352
+ }
353
+ }
354
+
355
+ // Method 2: Validate and extract in one step
356
+ function processExtension(extension: unknown) {
357
+ const { valid, info, errors } = validateAndExtract(extension as any);
358
+
359
+ if (valid && info) {
360
+ console.log("Method:", info.input.method);
361
+ console.log("Type:", info.input.type);
362
+
363
+ if ("queryParams" in info.input) {
364
+ console.log("Query params:", info.input.queryParams);
365
+ }
366
+ if ("body" in info.input) {
367
+ console.log("Body type:", (info.input as any).bodyType);
368
+ }
369
+ } else {
370
+ console.error("Invalid:", errors);
371
+ }
372
+ }
373
+
374
+ // Method 3: Direct validation
375
+ function validateExtension(extension: unknown) {
376
+ const result: ValidationResult = validateDiscoveryExtension(extension as any);
377
+
378
+ if (result.valid) {
379
+ console.log("Extension is valid");
380
+ } else {
381
+ console.error("Validation errors:", result.errors);
382
+ }
383
+ }
384
+
385
+ // Method 4: Skip validation (trusted source)
386
+ function extractWithoutValidation(
387
+ paymentPayload: PaymentPayload,
388
+ paymentRequirements: PaymentRequirements,
389
+ ) {
390
+ const discovered = extractDiscoveryInfo(
391
+ paymentPayload,
392
+ paymentRequirements,
393
+ false,
394
+ );
395
+
396
+ if (discovered) {
397
+ console.log("Resource:", discovered.resourceUrl);
398
+ }
399
+ }
400
+ ```
401
+
402
+ ---
403
+
404
+ ## Bazaar: Facilitator Client Querying the Bazaar
405
+
406
+ ```typescript
407
+ import { HTTPFacilitatorClient } from "@x402-avm/core/server";
408
+ import {
409
+ withBazaar,
410
+ type DiscoveryResourcesResponse,
411
+ type DiscoveryResource,
412
+ } from "@x402-avm/extensions";
413
+
414
+ const facilitatorClient = new HTTPFacilitatorClient({
415
+ url: "https://facilitator.example.com",
416
+ });
417
+
418
+ const client = withBazaar(facilitatorClient);
419
+
420
+ // List all discovered resources
421
+ const allResources: DiscoveryResourcesResponse =
422
+ await client.extensions.discovery.listResources();
423
+
424
+ console.log("Total resources:", allResources.pagination.total);
425
+ for (const resource of allResources.items) {
426
+ console.log(`- ${resource.resource} (${resource.type})`);
427
+ console.log(` Payment: ${resource.accepts.length} method(s)`);
428
+ console.log(` Updated: ${resource.lastUpdated}`);
429
+ }
430
+
431
+ // Filtered query
432
+ const httpResources = await client.extensions.discovery.listResources({
433
+ type: "http",
434
+ limit: 10,
435
+ offset: 0,
436
+ });
437
+
438
+ // Pagination
439
+ async function getAllResources() {
440
+ const allItems: DiscoveryResource[] = [];
441
+ let offset = 0;
442
+ const limit = 50;
443
+
444
+ while (true) {
445
+ const page = await client.extensions.discovery.listResources({
446
+ limit,
447
+ offset,
448
+ });
449
+
450
+ allItems.push(...page.items);
451
+
452
+ if (allItems.length >= page.pagination.total) {
453
+ break;
454
+ }
455
+ offset += limit;
456
+ }
457
+
458
+ return allItems;
459
+ }
460
+
461
+ // Finding Algorand-compatible resources
462
+ async function findAlgorandResources() {
463
+ const resources = await client.extensions.discovery.listResources({
464
+ type: "http",
465
+ });
466
+
467
+ return resources.items.filter((resource) =>
468
+ resource.accepts.some((req) =>
469
+ req.network.startsWith("algorand:"),
470
+ ),
471
+ );
472
+ }
473
+ ```
474
+
475
+ ---
476
+
477
+ ## Bazaar: WithExtensions Type Utility
478
+
479
+ ```typescript
480
+ import { WithExtensions } from "@x402-avm/extensions";
481
+ import { HTTPFacilitatorClient } from "@x402-avm/core/server";
482
+
483
+ type ClientWithBazaar = WithExtensions<
484
+ HTTPFacilitatorClient,
485
+ { discovery: { listResources(): Promise<any> } }
486
+ >;
487
+
488
+ type ClientWithBazaarAndAuth = WithExtensions<
489
+ ClientWithBazaar,
490
+ { auth: { login(): Promise<void> } }
491
+ >;
492
+ ```
493
+
494
+ ---
495
+
496
+ ## Bazaar: Chaining Multiple Extensions
497
+
498
+ ```typescript
499
+ import { HTTPFacilitatorClient } from "@x402-avm/core/server";
500
+ import { withBazaar } from "@x402-avm/extensions";
501
+
502
+ interface MyCustomExtension {
503
+ custom: {
504
+ doSomething(): Promise<string>;
505
+ };
506
+ }
507
+
508
+ function withCustom<T extends HTTPFacilitatorClient>(
509
+ client: T,
510
+ ): T & { extensions: MyCustomExtension } {
511
+ const extended = client as T & { extensions: MyCustomExtension };
512
+ const existingExtensions = (client as any).extensions ?? {};
513
+
514
+ extended.extensions = {
515
+ ...existingExtensions,
516
+ custom: {
517
+ async doSomething() {
518
+ return "done";
519
+ },
520
+ },
521
+ } as any;
522
+
523
+ return extended;
524
+ }
525
+
526
+ const client = withBazaar(withCustom(new HTTPFacilitatorClient({
527
+ url: "https://facilitator.example.com",
528
+ })));
529
+
530
+ const resources = await client.extensions.discovery.listResources();
531
+ const result = await client.extensions.custom.doSomething();
532
+ ```
533
+
534
+ ---
535
+
536
+ ## Complete Resource Server with Bazaar Discovery
537
+
538
+ ```typescript
539
+ import express from "express";
540
+ import {
541
+ x402HTTPResourceServer,
542
+ HTTPFacilitatorClient,
543
+ } from "@x402-avm/core/server";
544
+ import { registerExactAvmScheme } from "@x402-avm/avm/exact/server";
545
+ import {
546
+ bazaarResourceServerExtension,
547
+ declareDiscoveryExtension,
548
+ } from "@x402-avm/extensions";
549
+ import { ALGORAND_TESTNET_CAIP2, USDC_TESTNET_ASA_ID } from "@x402-avm/avm";
550
+
551
+ const app = express();
552
+
553
+ const facilitatorClient = new HTTPFacilitatorClient({
554
+ url: process.env.FACILITATOR_URL || "https://facilitator.example.com",
555
+ });
556
+
557
+ const httpServer = new x402HTTPResourceServer(facilitatorClient, {
558
+ routes: [
559
+ {
560
+ path: "/api/weather",
561
+ config: {
562
+ scheme: "exact",
563
+ payTo: process.env.RECEIVER_ADDRESS!,
564
+ price: {
565
+ asset: USDC_TESTNET_ASA_ID,
566
+ amount: "10000",
567
+ extra: { name: "USDC", decimals: 6 },
568
+ },
569
+ network: ALGORAND_TESTNET_CAIP2,
570
+ maxTimeoutSeconds: 60,
571
+ },
572
+ description: "Real-time weather data",
573
+ mimeType: "application/json",
574
+ },
575
+ {
576
+ path: "/api/analyze",
577
+ config: {
578
+ scheme: "exact",
579
+ payTo: process.env.RECEIVER_ADDRESS!,
580
+ price: {
581
+ asset: USDC_TESTNET_ASA_ID,
582
+ amount: "500000",
583
+ extra: { name: "USDC", decimals: 6 },
584
+ },
585
+ network: ALGORAND_TESTNET_CAIP2,
586
+ maxTimeoutSeconds: 120,
587
+ },
588
+ description: "AI text analysis",
589
+ mimeType: "application/json",
590
+ },
591
+ ],
592
+ });
593
+
594
+ registerExactAvmScheme(httpServer.resourceServer);
595
+ httpServer.resourceServer.registerExtension(bazaarResourceServerExtension);
596
+
597
+ const weatherDiscovery = declareDiscoveryExtension({
598
+ input: { city: "San Francisco", units: "metric" },
599
+ inputSchema: {
600
+ properties: {
601
+ city: { type: "string" },
602
+ units: { type: "string", enum: ["metric", "imperial"] },
603
+ },
604
+ required: ["city"],
605
+ },
606
+ output: {
607
+ example: {
608
+ temperature: 18.5,
609
+ condition: "Partly Cloudy",
610
+ humidity: 65,
611
+ windSpeed: 12.3,
612
+ },
613
+ },
614
+ });
615
+
616
+ const analysisDiscovery = declareDiscoveryExtension({
617
+ bodyType: "json",
618
+ input: { text: "Sample text for analysis", language: "en" },
619
+ inputSchema: {
620
+ properties: {
621
+ text: { type: "string", maxLength: 50000 },
622
+ language: { type: "string" },
623
+ },
624
+ required: ["text"],
625
+ },
626
+ output: {
627
+ example: {
628
+ sentiment: "neutral",
629
+ confidence: 0.85,
630
+ entities: ["person", "location"],
631
+ summary: "A brief summary of the analyzed text.",
632
+ },
633
+ },
634
+ });
635
+
636
+ app.get("/api/weather", async (req, res) => {
637
+ const result = await httpServer.processRequest({
638
+ url: req.url,
639
+ method: req.method,
640
+ headers: req.headers,
641
+ adapter: {
642
+ getHeader: (name: string) => req.headers[name.toLowerCase()] as string,
643
+ },
644
+ extensions: weatherDiscovery,
645
+ });
646
+
647
+ if (result.status === 402) {
648
+ return res.status(402).json(result.body);
649
+ }
650
+
651
+ const city = (req.query.city as string) || "San Francisco";
652
+ res.json({
653
+ temperature: 18.5,
654
+ condition: "Partly Cloudy",
655
+ humidity: 65,
656
+ windSpeed: 12.3,
657
+ city,
658
+ });
659
+ });
660
+
661
+ app.post("/api/analyze", express.json(), async (req, res) => {
662
+ const result = await httpServer.processRequest({
663
+ url: req.url,
664
+ method: req.method,
665
+ headers: req.headers,
666
+ adapter: {
667
+ getHeader: (name: string) => req.headers[name.toLowerCase()] as string,
668
+ },
669
+ extensions: analysisDiscovery,
670
+ });
671
+
672
+ if (result.status === 402) {
673
+ return res.status(402).json(result.body);
674
+ }
675
+
676
+ const { text, language } = req.body;
677
+ res.json({
678
+ sentiment: "neutral",
679
+ confidence: 0.85,
680
+ entities: ["person", "location"],
681
+ summary: `Analysis of ${text.length} characters in ${language || "en"}.`,
682
+ });
683
+ });
684
+
685
+ const PORT = parseInt(process.env.PORT || "3000", 10);
686
+ app.listen(PORT, () => {
687
+ console.log(`Resource server with Bazaar discovery on port ${PORT}`);
688
+ });
689
+ ```
690
+
691
+ ---
692
+
693
+ ## Complete Facilitator with Bazaar Cataloging
694
+
695
+ ```typescript
696
+ import express from "express";
697
+ import { x402Facilitator } from "@x402-avm/core/facilitator";
698
+ import { registerExactAvmScheme } from "@x402-avm/avm/exact/facilitator";
699
+ import { ALGORAND_TESTNET_CAIP2 } from "@x402-avm/avm";
700
+ import {
701
+ extractDiscoveryInfo,
702
+ type DiscoveredResource,
703
+ } from "@x402-avm/extensions";
704
+ import algosdk from "algosdk";
705
+
706
+ // In-memory catalog (use a database in production)
707
+ const catalog: Map<string, DiscoveredResource & { settledCount: number }> = new Map();
708
+
709
+ const secretKey = Buffer.from(process.env.AVM_PRIVATE_KEY!, "base64");
710
+ const address = algosdk.encodeAddress(secretKey.slice(32));
711
+ const algodClient = new algosdk.Algodv2("", "https://testnet-api.algonode.cloud", "");
712
+
713
+ const signer = {
714
+ getAddresses: () => [address],
715
+ signTransaction: async (txn: Uint8Array, _addr: string) => {
716
+ const decoded = algosdk.decodeUnsignedTransaction(txn);
717
+ return algosdk.signTransaction(decoded, secretKey).blob;
718
+ },
719
+ getAlgodClient: () => algodClient,
720
+ simulateTransactions: async (txns: Uint8Array[]) => {
721
+ const stxns = txns.map((t) => {
722
+ try { return algosdk.decodeSignedTransaction(t); }
723
+ catch { return new algosdk.SignedTransaction({ txn: algosdk.decodeUnsignedTransaction(t) }); }
724
+ });
725
+ const req = new algosdk.modelsv2.SimulateRequest({
726
+ txnGroups: [new algosdk.modelsv2.SimulateRequestTransactionGroup({ txns: stxns })],
727
+ allowEmptySignatures: true,
728
+ });
729
+ return algodClient.simulateTransactions(req).do();
730
+ },
731
+ sendTransactions: async (signedTxns: Uint8Array[]) => {
732
+ const combined = Buffer.concat(signedTxns.map((t) => Buffer.from(t)));
733
+ const { txId } = await algodClient.sendRawTransaction(combined).do();
734
+ return txId;
735
+ },
736
+ waitForConfirmation: async (txId: string, _net: string, rounds = 4) => {
737
+ return algosdk.waitForConfirmation(algodClient, txId, rounds);
738
+ },
739
+ };
740
+
741
+ const facilitator = new x402Facilitator();
742
+ registerExactAvmScheme(facilitator, {
743
+ signer,
744
+ networks: ALGORAND_TESTNET_CAIP2,
745
+ });
746
+
747
+ // Register after-settle hook to catalog discovered resources
748
+ facilitator.onAfterSettle(async (context) => {
749
+ if (context.result.success) {
750
+ const discovered = extractDiscoveryInfo(
751
+ context.paymentPayload,
752
+ context.requirements,
753
+ );
754
+
755
+ if (discovered) {
756
+ const key = `${discovered.method}:${discovered.resourceUrl}`;
757
+ const existing = catalog.get(key);
758
+
759
+ if (existing) {
760
+ existing.settledCount += 1;
761
+ } else {
762
+ catalog.set(key, { ...discovered, settledCount: 1 });
763
+ }
764
+
765
+ console.log(`Cataloged: ${key} (${catalog.get(key)!.settledCount} settlements)`);
766
+ }
767
+ }
768
+ });
769
+
770
+ const app = express();
771
+ app.use(express.json());
772
+
773
+ app.post("/verify", async (req, res) => {
774
+ const { paymentPayload, paymentRequirements } = req.body;
775
+ const result = await facilitator.verify(paymentPayload, paymentRequirements);
776
+ res.json(result);
777
+ });
778
+
779
+ app.post("/settle", async (req, res) => {
780
+ const { paymentPayload, paymentRequirements } = req.body;
781
+ const result = await facilitator.settle(paymentPayload, paymentRequirements);
782
+ res.json(result);
783
+ });
784
+
785
+ app.get("/discovery/resources", (req, res) => {
786
+ const type = req.query.type as string | undefined;
787
+ const limit = parseInt(req.query.limit as string || "50", 10);
788
+ const offset = parseInt(req.query.offset as string || "0", 10);
789
+
790
+ let items = Array.from(catalog.values());
791
+
792
+ if (type) {
793
+ items = items.filter(
794
+ (r) => r.discoveryInfo.input.type === type,
795
+ );
796
+ }
797
+
798
+ const total = items.length;
799
+ const paged = items.slice(offset, offset + limit);
800
+
801
+ res.json({
802
+ x402Version: 2,
803
+ items: paged.map((r) => ({
804
+ resource: r.resourceUrl,
805
+ type: r.discoveryInfo.input.type,
806
+ x402Version: r.x402Version,
807
+ accepts: [],
808
+ lastUpdated: new Date().toISOString(),
809
+ metadata: {
810
+ method: r.method,
811
+ description: r.description,
812
+ mimeType: r.mimeType,
813
+ settledCount: r.settledCount,
814
+ },
815
+ })),
816
+ pagination: { limit, offset, total },
817
+ });
818
+ });
819
+
820
+ app.listen(4000, () => {
821
+ console.log("Facilitator with Bazaar discovery on port 4000");
822
+ });
823
+ ```
824
+
825
+ ---
826
+
827
+ ## Full Stack: Shared Config
828
+
829
+ ```typescript
830
+ // shared/config.ts
831
+ import { ALGORAND_TESTNET_CAIP2, USDC_TESTNET_ASA_ID } from "@x402-avm/avm";
832
+
833
+ export const NETWORK = ALGORAND_TESTNET_CAIP2;
834
+ export const USDC_ASA = USDC_TESTNET_ASA_ID;
835
+ export const RESOURCE_WALLET = "RECEIVER_ALGORAND_ADDRESS_58_CHARS_AAAAAAAAAAAAAAAAAAA";
836
+ export const FACILITATOR_URL = "http://localhost:4000";
837
+ export const RESOURCE_SERVER_URL = "http://localhost:3000";
838
+ ```
839
+
840
+ ---
841
+
842
+ ## HTTPFacilitatorClient
843
+
844
+ ```typescript
845
+ import { HTTPFacilitatorClient } from "@x402-avm/core/server";
846
+
847
+ // Basic configuration
848
+ const facilitatorClient = new HTTPFacilitatorClient({
849
+ url: "https://facilitator.example.com",
850
+ });
851
+
852
+ // With authentication
853
+ const authenticatedClient = new HTTPFacilitatorClient({
854
+ url: "https://facilitator.example.com",
855
+ headers: {
856
+ Authorization: `Bearer ${process.env.FACILITATOR_API_KEY}`,
857
+ },
858
+ });
859
+
860
+ // Check supported networks
861
+ const supported = await facilitatorClient.supported();
862
+ console.log("Supported networks:", supported.networks);
863
+
864
+ // Verify a payment directly
865
+ const verifyResult = await facilitatorClient.verify({
866
+ paymentPayload,
867
+ paymentRequirements,
868
+ });
869
+
870
+ // Settle a payment directly
871
+ const settleResult = await facilitatorClient.settle({
872
+ paymentPayload,
873
+ paymentRequirements,
874
+ });
875
+ ```