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 +38 -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,1417 @@
1
+ # @x402-avm/core and @x402-avm/avm Examples
2
+
3
+ ## Installation
4
+
5
+ ```bash
6
+ npm install @x402-avm/core @x402-avm/avm algosdk
7
+ ```
8
+
9
+ For browser wallet integration:
10
+
11
+ ```bash
12
+ npm install @x402-avm/avm algosdk @txnlab/use-wallet
13
+ ```
14
+
15
+ ---
16
+
17
+ ## Network Identifiers
18
+
19
+ ```typescript
20
+ import type { Network } from "@x402-avm/core/types";
21
+ import {
22
+ ALGORAND_TESTNET_CAIP2,
23
+ ALGORAND_MAINNET_CAIP2,
24
+ V1_ALGORAND_TESTNET,
25
+ V1_ALGORAND_MAINNET,
26
+ V1_TO_CAIP2,
27
+ CAIP2_TO_V1,
28
+ } from "@x402-avm/avm";
29
+
30
+ const testnet: Network = ALGORAND_TESTNET_CAIP2;
31
+ // => "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="
32
+
33
+ const mainnet: Network = ALGORAND_MAINNET_CAIP2;
34
+ // => "algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8="
35
+
36
+ const testnetV1 = V1_ALGORAND_TESTNET; // => "algorand-testnet"
37
+ const mainnetV1 = V1_ALGORAND_MAINNET; // => "algorand-mainnet"
38
+
39
+ const caip2 = V1_TO_CAIP2["algorand-testnet"];
40
+ // => "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="
41
+
42
+ const v1Name = CAIP2_TO_V1[ALGORAND_TESTNET_CAIP2];
43
+ // => "algorand-testnet"
44
+ ```
45
+
46
+ ---
47
+
48
+ ## PaymentRequirements (V2)
49
+
50
+ ```typescript
51
+ import type { PaymentRequirements } from "@x402-avm/core/types";
52
+ import { ALGORAND_TESTNET_CAIP2, USDC_TESTNET_ASA_ID } from "@x402-avm/avm";
53
+
54
+ const requirements: PaymentRequirements = {
55
+ scheme: "exact",
56
+ network: ALGORAND_TESTNET_CAIP2,
57
+ maxAmountRequired: "1000000",
58
+ resource: "https://api.example.com/premium/data",
59
+ description: "Access to premium API endpoint",
60
+ mimeType: "application/json",
61
+ payTo: "RECEIVER_ALGORAND_ADDRESS_58_CHARS_AAAAAAAAAAAAAAAAAAA",
62
+ maxTimeoutSeconds: 60,
63
+ asset: USDC_TESTNET_ASA_ID,
64
+ outputSchema: undefined,
65
+ extra: {
66
+ name: "USDC",
67
+ decimals: 6,
68
+ },
69
+ };
70
+
71
+ const algoRequirements: PaymentRequirements = {
72
+ scheme: "exact",
73
+ network: ALGORAND_TESTNET_CAIP2,
74
+ maxAmountRequired: "1000000",
75
+ resource: "https://api.example.com/premium/data",
76
+ description: "Access to premium data",
77
+ mimeType: "application/json",
78
+ payTo: "RECEIVER_ALGORAND_ADDRESS_58_CHARS_AAAAAAAAAAAAAAAAAAA",
79
+ maxTimeoutSeconds: 60,
80
+ asset: "0",
81
+ outputSchema: undefined,
82
+ extra: {
83
+ name: "ALGO",
84
+ decimals: 6,
85
+ },
86
+ };
87
+ ```
88
+
89
+ ---
90
+
91
+ ## PaymentRequirements (V1 Legacy)
92
+
93
+ ```typescript
94
+ import type { PaymentRequirementsV1 } from "@x402-avm/core/types";
95
+
96
+ const requirementsV1: PaymentRequirementsV1 = {
97
+ scheme: "exact",
98
+ network: "algorand-testnet",
99
+ maxAmountRequired: "1000000",
100
+ resource: "https://api.example.com/premium/data",
101
+ description: "Premium data access",
102
+ payTo: "RECEIVER_ALGORAND_ADDRESS_58_CHARS_AAAAAAAAAAAAAAAAAAA",
103
+ maxTimeoutSeconds: 60,
104
+ asset: "10458941",
105
+ outputSchema: null,
106
+ extra: {
107
+ name: "USDC",
108
+ decimals: 6,
109
+ },
110
+ };
111
+ ```
112
+
113
+ ---
114
+
115
+ ## PaymentPayload
116
+
117
+ ```typescript
118
+ import type { PaymentPayload } from "@x402-avm/core/types";
119
+ import { ALGORAND_TESTNET_CAIP2 } from "@x402-avm/avm";
120
+
121
+ const payload: PaymentPayload = {
122
+ x402Version: 2,
123
+ scheme: "exact",
124
+ network: ALGORAND_TESTNET_CAIP2,
125
+ payload: {
126
+ paymentGroup: [
127
+ "iaNhbXTOAAGGoKNmZWXNA...",
128
+ "iaNhbXTOAAGGoKNmZWXNA...",
129
+ ],
130
+ paymentIndex: 0,
131
+ },
132
+ };
133
+ ```
134
+
135
+ ---
136
+
137
+ ## PaymentRequired Response
138
+
139
+ ```typescript
140
+ import type { PaymentRequired } from "@x402-avm/core/types";
141
+
142
+ const paymentRequired: PaymentRequired = {
143
+ x402Version: 2,
144
+ resource: {
145
+ url: "https://api.example.com/premium/data",
146
+ description: "Premium data endpoint",
147
+ mimeType: "application/json",
148
+ },
149
+ accepts: [
150
+ {
151
+ scheme: "exact",
152
+ network: "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
153
+ maxAmountRequired: "1000000",
154
+ resource: "https://api.example.com/premium/data",
155
+ description: "Premium data endpoint",
156
+ mimeType: "application/json",
157
+ payTo: "RECEIVER_ALGORAND_ADDRESS_58_CHARS_AAAAAAAAAAAAAAAAAAA",
158
+ maxTimeoutSeconds: 60,
159
+ asset: "10458941",
160
+ outputSchema: undefined,
161
+ extra: { name: "USDC", decimals: 6 },
162
+ },
163
+ ],
164
+ error: "Payment required to access this resource",
165
+ };
166
+ ```
167
+
168
+ ---
169
+
170
+ ## Client with Private Key (Server-Side)
171
+
172
+ ```typescript
173
+ import { x402Client } from "@x402-avm/core/client";
174
+ import { registerExactAvmScheme } from "@x402-avm/avm/exact/client";
175
+ import type { ClientAvmSigner } from "@x402-avm/avm";
176
+ import algosdk from "algosdk";
177
+
178
+ const secretKey = Buffer.from(process.env.AVM_PRIVATE_KEY!, "base64");
179
+ const address = algosdk.encodeAddress(secretKey.slice(32));
180
+
181
+ const signer: ClientAvmSigner = {
182
+ address,
183
+ signTransactions: async (txns, indexesToSign) => {
184
+ return txns.map((txn, i) => {
185
+ if (indexesToSign && !indexesToSign.includes(i)) return null;
186
+ const decoded = algosdk.decodeUnsignedTransaction(txn);
187
+ const signed = algosdk.signTransaction(decoded, secretKey);
188
+ return signed.blob;
189
+ });
190
+ },
191
+ };
192
+
193
+ const client = new x402Client({ schemes: [] });
194
+
195
+ registerExactAvmScheme(client, {
196
+ signer,
197
+ algodConfig: {
198
+ algodUrl: "https://testnet-api.algonode.cloud",
199
+ },
200
+ });
201
+
202
+ async function accessPaidResource() {
203
+ const response = await client.fetch(
204
+ "https://api.example.com/premium/data"
205
+ );
206
+
207
+ if (response.ok) {
208
+ const data = await response.json();
209
+ console.log("Received:", data);
210
+ }
211
+ }
212
+ ```
213
+
214
+ ---
215
+
216
+ ## Client with @txnlab/use-wallet (Browser)
217
+
218
+ ```typescript
219
+ import type { ClientAvmSigner } from "@x402-avm/avm";
220
+ import { useWallet } from "@txnlab/use-wallet";
221
+
222
+ function PaymentComponent() {
223
+ const { activeAccount, signTransactions } = useWallet();
224
+
225
+ const signer: ClientAvmSigner | null = activeAccount
226
+ ? {
227
+ address: activeAccount.address,
228
+ signTransactions: async (txns, indexesToSign) => {
229
+ return signTransactions(txns, indexesToSign);
230
+ },
231
+ }
232
+ : null;
233
+
234
+ return signer ? <PaidContent signer={signer} /> : <ConnectWallet />;
235
+ }
236
+ ```
237
+
238
+ ---
239
+
240
+ ## Full React Browser Client
241
+
242
+ ```typescript
243
+ import React, { useState, useCallback } from "react";
244
+ import { x402Client } from "@x402-avm/core/client";
245
+ import { registerExactAvmScheme } from "@x402-avm/avm/exact/client";
246
+ import type { ClientAvmSigner } from "@x402-avm/avm";
247
+ import {
248
+ WalletProvider,
249
+ useWallet,
250
+ WalletId,
251
+ } from "@txnlab/use-wallet-react";
252
+
253
+ const walletProviders = {
254
+ wallets: [WalletId.PERA, WalletId.DEFLY],
255
+ };
256
+
257
+ function PayForWeather() {
258
+ const { activeAccount, signTransactions, connect, disconnect } = useWallet();
259
+ const [weather, setWeather] = useState<string | null>(null);
260
+ const [loading, setLoading] = useState(false);
261
+
262
+ const fetchWeather = useCallback(async () => {
263
+ if (!activeAccount) return;
264
+ setLoading(true);
265
+
266
+ try {
267
+ const signer: ClientAvmSigner = {
268
+ address: activeAccount.address,
269
+ signTransactions: async (txns, indexes) =>
270
+ signTransactions(txns, indexes),
271
+ };
272
+
273
+ const client = new x402Client({ schemes: [] });
274
+ registerExactAvmScheme(client, { signer });
275
+
276
+ const response = await client.fetch(
277
+ "https://api.example.com/weather"
278
+ );
279
+
280
+ if (response.ok) {
281
+ const data = await response.json();
282
+ setWeather(JSON.stringify(data, null, 2));
283
+ } else {
284
+ setWeather(`Error: ${response.status} ${response.statusText}`);
285
+ }
286
+ } catch (err) {
287
+ setWeather(`Error: ${(err as Error).message}`);
288
+ } finally {
289
+ setLoading(false);
290
+ }
291
+ }, [activeAccount, signTransactions]);
292
+
293
+ return (
294
+ <div>
295
+ <h1>Weather API (Paid with USDC on Algorand)</h1>
296
+
297
+ {!activeAccount ? (
298
+ <button onClick={() => connect(WalletId.PERA)}>
299
+ Connect Pera Wallet
300
+ </button>
301
+ ) : (
302
+ <div>
303
+ <p>Connected: {activeAccount.address.slice(0, 8)}...</p>
304
+ <button onClick={fetchWeather} disabled={loading}>
305
+ {loading ? "Paying..." : "Get Weather (0.10 USDC)"}
306
+ </button>
307
+ <button onClick={disconnect}>Disconnect</button>
308
+ </div>
309
+ )}
310
+
311
+ {weather && (
312
+ <pre>{weather}</pre>
313
+ )}
314
+ </div>
315
+ );
316
+ }
317
+
318
+ export default function App() {
319
+ return (
320
+ <WalletProvider value={walletProviders}>
321
+ <PayForWeather />
322
+ </WalletProvider>
323
+ );
324
+ }
325
+ ```
326
+
327
+ ---
328
+
329
+ ## Payment Policies
330
+
331
+ ```typescript
332
+ import { x402Client, PaymentPolicy } from "@x402-avm/core/client";
333
+ import { registerExactAvmScheme } from "@x402-avm/avm/exact/client";
334
+ import { ALGORAND_TESTNET_CAIP2 } from "@x402-avm/avm";
335
+
336
+ const preferTestnet: PaymentPolicy = (version, requirements) => {
337
+ return requirements.filter(r => r.network === ALGORAND_TESTNET_CAIP2);
338
+ };
339
+
340
+ const maxAmount: PaymentPolicy = (version, requirements) => {
341
+ const MAX_USDC = 5_000_000;
342
+ return requirements.filter(r => {
343
+ const amount = parseInt(r.maxAmountRequired, 10);
344
+ return amount <= MAX_USDC;
345
+ });
346
+ };
347
+
348
+ const preferAlgorand: PaymentPolicy = (version, requirements) => {
349
+ const algorandOptions = requirements.filter(r =>
350
+ r.network.startsWith("algorand:")
351
+ );
352
+ return algorandOptions.length > 0 ? algorandOptions : requirements;
353
+ };
354
+
355
+ const client = new x402Client({ schemes: [] });
356
+ registerExactAvmScheme(client, {
357
+ signer,
358
+ policies: [preferTestnet, maxAmount],
359
+ });
360
+
361
+ client.registerPolicy(preferAlgorand);
362
+ ```
363
+
364
+ ---
365
+
366
+ ## Resource Server (Transport-Agnostic)
367
+
368
+ ```typescript
369
+ import { x402ResourceServer, ResourceConfig } from "@x402-avm/core/server";
370
+ import { HTTPFacilitatorClient } from "@x402-avm/core/server";
371
+ import { registerExactAvmScheme } from "@x402-avm/avm/exact/server";
372
+ import { ALGORAND_TESTNET_CAIP2, USDC_TESTNET_ASA_ID } from "@x402-avm/avm";
373
+
374
+ const facilitatorClient = new HTTPFacilitatorClient({
375
+ url: "https://facilitator.example.com",
376
+ });
377
+
378
+ const server = new x402ResourceServer(facilitatorClient);
379
+ registerExactAvmScheme(server);
380
+
381
+ const resourceConfig: ResourceConfig = {
382
+ scheme: "exact",
383
+ payTo: "RECEIVER_ALGORAND_ADDRESS_58_CHARS_AAAAAAAAAAAAAAAAAAA",
384
+ price: {
385
+ asset: USDC_TESTNET_ASA_ID,
386
+ amount: "100000",
387
+ extra: { name: "USDC", decimals: 6 },
388
+ },
389
+ network: ALGORAND_TESTNET_CAIP2,
390
+ maxTimeoutSeconds: 60,
391
+ };
392
+
393
+ async function handleRequest(url: string, xPaymentHeader?: string) {
394
+ if (!xPaymentHeader) {
395
+ const paymentRequired = server.createPaymentRequired(
396
+ { url, description: "Premium API", mimeType: "application/json" },
397
+ [resourceConfig]
398
+ );
399
+ return { status: 402, body: paymentRequired };
400
+ }
401
+
402
+ const result = await server.processPayment(xPaymentHeader, resourceConfig);
403
+ if (result.verified) {
404
+ return { status: 200, body: { data: "premium content" } };
405
+ }
406
+ return { status: 402, body: result.error };
407
+ }
408
+ ```
409
+
410
+ ---
411
+
412
+ ## HTTP Resource Server with Routes
413
+
414
+ ```typescript
415
+ import {
416
+ x402HTTPResourceServer,
417
+ HTTPFacilitatorClient,
418
+ RouteConfig,
419
+ } from "@x402-avm/core/server";
420
+ import { registerExactAvmScheme } from "@x402-avm/avm/exact/server";
421
+ import { ALGORAND_TESTNET_CAIP2, USDC_TESTNET_ASA_ID } from "@x402-avm/avm";
422
+
423
+ const facilitatorClient = new HTTPFacilitatorClient({
424
+ url: "https://facilitator.example.com",
425
+ });
426
+
427
+ const routes: RouteConfig[] = [
428
+ {
429
+ path: "/api/premium/*",
430
+ config: {
431
+ scheme: "exact",
432
+ payTo: "RECEIVER_ALGORAND_ADDRESS_58_CHARS_AAAAAAAAAAAAAAAAAAA",
433
+ price: {
434
+ asset: USDC_TESTNET_ASA_ID,
435
+ amount: "100000",
436
+ extra: { name: "USDC", decimals: 6 },
437
+ },
438
+ network: ALGORAND_TESTNET_CAIP2,
439
+ maxTimeoutSeconds: 60,
440
+ },
441
+ description: "Premium API endpoints",
442
+ mimeType: "application/json",
443
+ },
444
+ {
445
+ path: "/api/expensive-analysis",
446
+ config: {
447
+ scheme: "exact",
448
+ payTo: "RECEIVER_ALGORAND_ADDRESS_58_CHARS_AAAAAAAAAAAAAAAAAAA",
449
+ price: {
450
+ asset: USDC_TESTNET_ASA_ID,
451
+ amount: "5000000",
452
+ extra: { name: "USDC", decimals: 6 },
453
+ },
454
+ network: ALGORAND_TESTNET_CAIP2,
455
+ maxTimeoutSeconds: 120,
456
+ },
457
+ description: "Expensive analysis endpoint",
458
+ mimeType: "application/json",
459
+ },
460
+ ];
461
+
462
+ const httpServer = new x402HTTPResourceServer(facilitatorClient, { routes });
463
+ registerExactAvmScheme(httpServer.resourceServer);
464
+ ```
465
+
466
+ ---
467
+
468
+ ## Facilitator
469
+
470
+ ```typescript
471
+ import { x402Facilitator } from "@x402-avm/core/facilitator";
472
+ import { registerExactAvmScheme } from "@x402-avm/avm/exact/facilitator";
473
+ import type { FacilitatorAvmSigner } from "@x402-avm/avm";
474
+ import { ALGORAND_TESTNET_CAIP2 } from "@x402-avm/avm";
475
+ import algosdk from "algosdk";
476
+
477
+ const secretKey = Buffer.from(process.env.AVM_PRIVATE_KEY!, "base64");
478
+ const address = algosdk.encodeAddress(secretKey.slice(32));
479
+ const algodClient = new algosdk.Algodv2("", "https://testnet-api.algonode.cloud", "");
480
+
481
+ const facilitatorSigner: FacilitatorAvmSigner = {
482
+ getAddresses: () => [address],
483
+ signTransaction: async (txn, senderAddress) => {
484
+ const decoded = algosdk.decodeUnsignedTransaction(txn);
485
+ const signed = algosdk.signTransaction(decoded, secretKey);
486
+ return signed.blob;
487
+ },
488
+ getAlgodClient: (network) => algodClient,
489
+ simulateTransactions: async (txns, network) => {
490
+ const stxns = txns.map((txnBytes) => {
491
+ try {
492
+ return algosdk.decodeSignedTransaction(txnBytes);
493
+ } catch {
494
+ const txn = algosdk.decodeUnsignedTransaction(txnBytes);
495
+ return new algosdk.SignedTransaction({ txn });
496
+ }
497
+ });
498
+ const request = new algosdk.modelsv2.SimulateRequest({
499
+ txnGroups: [new algosdk.modelsv2.SimulateRequestTransactionGroup({ txns: stxns })],
500
+ allowEmptySignatures: true,
501
+ });
502
+ return algodClient.simulateTransactions(request).do();
503
+ },
504
+ sendTransactions: async (signedTxns, network) => {
505
+ const combined = Buffer.concat(signedTxns.map(t => Buffer.from(t)));
506
+ const { txId } = await algodClient.sendRawTransaction(combined).do();
507
+ return txId;
508
+ },
509
+ waitForConfirmation: async (txId, network, waitRounds = 4) => {
510
+ return algosdk.waitForConfirmation(algodClient, txId, waitRounds);
511
+ },
512
+ };
513
+
514
+ const facilitator = new x402Facilitator();
515
+
516
+ registerExactAvmScheme(facilitator, {
517
+ signer: facilitatorSigner,
518
+ networks: ALGORAND_TESTNET_CAIP2,
519
+ });
520
+
521
+ async function handlePaymentVerification(paymentPayload: any, requirements: any) {
522
+ const verifyResult = await facilitator.verify(paymentPayload, requirements);
523
+
524
+ if (verifyResult.isValid) {
525
+ const settleResult = await facilitator.settle(paymentPayload, requirements);
526
+ return settleResult;
527
+ }
528
+
529
+ return { success: false, error: verifyResult.error };
530
+ }
531
+ ```
532
+
533
+ ---
534
+
535
+ ## HTTPFacilitatorClient
536
+
537
+ ```typescript
538
+ import { HTTPFacilitatorClient } from "@x402-avm/core/server";
539
+
540
+ const facilitatorClient = new HTTPFacilitatorClient({
541
+ url: "https://facilitator.example.com",
542
+ });
543
+
544
+ const authenticatedClient = new HTTPFacilitatorClient({
545
+ url: "https://facilitator.example.com",
546
+ headers: {
547
+ Authorization: `Bearer ${process.env.FACILITATOR_API_KEY}`,
548
+ },
549
+ });
550
+
551
+ const supported = await facilitatorClient.supported();
552
+ console.log("Supported networks:", supported.networks);
553
+
554
+ const verifyResult = await facilitatorClient.verify({
555
+ paymentPayload,
556
+ paymentRequirements,
557
+ });
558
+
559
+ const settleResult = await facilitatorClient.settle({
560
+ paymentPayload,
561
+ paymentRequirements,
562
+ });
563
+ ```
564
+
565
+ ---
566
+
567
+ ## ClientAvmSigner Interface
568
+
569
+ ```typescript
570
+ import type { ClientAvmSigner } from "@x402-avm/avm";
571
+
572
+ interface ClientAvmSigner {
573
+ address: string;
574
+ signTransactions(
575
+ txns: Uint8Array[],
576
+ indexesToSign?: number[],
577
+ ): Promise<(Uint8Array | null)[]>;
578
+ }
579
+
580
+ import { isAvmSignerWallet } from "@x402-avm/avm";
581
+
582
+ function checkWallet(wallet: unknown) {
583
+ if (isAvmSignerWallet(wallet)) {
584
+ console.log("Address:", wallet.address);
585
+ }
586
+ }
587
+ ```
588
+
589
+ ---
590
+
591
+ ## ClientAvmSigner from Private Key
592
+
593
+ ```typescript
594
+ import type { ClientAvmSigner } from "@x402-avm/avm";
595
+ import algosdk from "algosdk";
596
+
597
+ function createPrivateKeySigner(privateKeyBase64: string): ClientAvmSigner {
598
+ const secretKey = Buffer.from(privateKeyBase64, "base64");
599
+
600
+ if (secretKey.length !== 64) {
601
+ throw new Error(`Invalid key length: expected 64, got ${secretKey.length}`);
602
+ }
603
+
604
+ const address = algosdk.encodeAddress(secretKey.slice(32));
605
+
606
+ return {
607
+ address,
608
+ signTransactions: async (
609
+ txns: Uint8Array[],
610
+ indexesToSign?: number[],
611
+ ): Promise<(Uint8Array | null)[]> => {
612
+ return txns.map((txnBytes, i) => {
613
+ if (indexesToSign && !indexesToSign.includes(i)) {
614
+ return null;
615
+ }
616
+ const decoded = algosdk.decodeUnsignedTransaction(txnBytes);
617
+ const signed = algosdk.signTransaction(decoded, secretKey);
618
+ return signed.blob;
619
+ });
620
+ },
621
+ };
622
+ }
623
+
624
+ const signer = createPrivateKeySigner(process.env.AVM_PRIVATE_KEY!);
625
+ console.log("Signer address:", signer.address);
626
+ ```
627
+
628
+ ---
629
+
630
+ ## FacilitatorAvmSigner Interface
631
+
632
+ ```typescript
633
+ import type { FacilitatorAvmSigner } from "@x402-avm/avm";
634
+ import type { Network } from "@x402-avm/core/types";
635
+
636
+ interface FacilitatorAvmSigner {
637
+ getAddresses(): readonly string[];
638
+ signTransaction(txn: Uint8Array, senderAddress: string): Promise<Uint8Array>;
639
+ getAlgodClient(network: Network): unknown;
640
+ simulateTransactions(txns: Uint8Array[], network: Network): Promise<unknown>;
641
+ sendTransactions(signedTxns: Uint8Array[], network: Network): Promise<string>;
642
+ waitForConfirmation(
643
+ txId: string,
644
+ network: Network,
645
+ waitRounds?: number,
646
+ ): Promise<unknown>;
647
+ }
648
+ ```
649
+
650
+ ---
651
+
652
+ ## Production FacilitatorAvmSigner
653
+
654
+ ```typescript
655
+ import type { FacilitatorAvmSigner, FacilitatorAvmSignerConfig } from "@x402-avm/avm";
656
+ import type { Network } from "@x402-avm/core/types";
657
+ import {
658
+ ALGORAND_TESTNET_CAIP2,
659
+ ALGORAND_MAINNET_CAIP2,
660
+ createAlgodClient,
661
+ isAlgorandNetwork,
662
+ isTestnetNetwork,
663
+ } from "@x402-avm/avm";
664
+ import algosdk from "algosdk";
665
+
666
+ function createFacilitatorSigner(
667
+ privateKeyBase64: string,
668
+ config?: FacilitatorAvmSignerConfig,
669
+ ): FacilitatorAvmSigner {
670
+ const secretKey = Buffer.from(privateKeyBase64, "base64");
671
+ const address = algosdk.encodeAddress(secretKey.slice(32));
672
+
673
+ const clients: Record<string, algosdk.Algodv2> = {};
674
+
675
+ function getClient(network: Network): algosdk.Algodv2 {
676
+ if (!clients[network]) {
677
+ clients[network] = createAlgodClient(
678
+ network,
679
+ isTestnetNetwork(network) ? config?.testnetUrl : config?.mainnetUrl,
680
+ config?.algodToken,
681
+ );
682
+ }
683
+ return clients[network];
684
+ }
685
+
686
+ return {
687
+ getAddresses: () => [address],
688
+
689
+ signTransaction: async (txn: Uint8Array, _senderAddress: string) => {
690
+ const decoded = algosdk.decodeUnsignedTransaction(txn);
691
+ const signed = algosdk.signTransaction(decoded, secretKey);
692
+ return signed.blob;
693
+ },
694
+
695
+ getAlgodClient: (network: Network) => getClient(network),
696
+
697
+ simulateTransactions: async (txns: Uint8Array[], network: Network) => {
698
+ const client = getClient(network);
699
+
700
+ const signedTxns = txns.map((txnBytes) => {
701
+ try {
702
+ return algosdk.decodeSignedTransaction(txnBytes);
703
+ } catch {
704
+ const txn = algosdk.decodeUnsignedTransaction(txnBytes);
705
+ return new algosdk.SignedTransaction({ txn });
706
+ }
707
+ });
708
+
709
+ const request = new algosdk.modelsv2.SimulateRequest({
710
+ txnGroups: [
711
+ new algosdk.modelsv2.SimulateRequestTransactionGroup({
712
+ txns: signedTxns,
713
+ }),
714
+ ],
715
+ allowEmptySignatures: true,
716
+ });
717
+
718
+ const result = await client.simulateTransactions(request).do();
719
+
720
+ for (const group of result.txnGroups || []) {
721
+ if (group.failureMessage) {
722
+ throw new Error(`Simulation failed: ${group.failureMessage}`);
723
+ }
724
+ }
725
+
726
+ return result;
727
+ },
728
+
729
+ sendTransactions: async (signedTxns: Uint8Array[], network: Network) => {
730
+ const client = getClient(network);
731
+ const combined = Buffer.concat(signedTxns.map((t) => Buffer.from(t)));
732
+ const { txId } = await client.sendRawTransaction(combined).do();
733
+ return txId;
734
+ },
735
+
736
+ waitForConfirmation: async (
737
+ txId: string,
738
+ network: Network,
739
+ waitRounds: number = 4,
740
+ ) => {
741
+ const client = getClient(network);
742
+ return algosdk.waitForConfirmation(client, txId, waitRounds);
743
+ },
744
+ };
745
+ }
746
+
747
+ const facilitatorSigner = createFacilitatorSigner(
748
+ process.env.AVM_PRIVATE_KEY!,
749
+ {
750
+ testnetUrl: "https://testnet-api.algonode.cloud",
751
+ mainnetUrl: "https://mainnet-api.algonode.cloud",
752
+ },
753
+ );
754
+
755
+ console.log("Fee payer addresses:", facilitatorSigner.getAddresses());
756
+ ```
757
+
758
+ ---
759
+
760
+ ## Constants: Network Identifiers
761
+
762
+ ```typescript
763
+ import {
764
+ ALGORAND_MAINNET_CAIP2,
765
+ ALGORAND_TESTNET_CAIP2,
766
+ CAIP2_NETWORKS,
767
+ ALGORAND_MAINNET_GENESIS_HASH,
768
+ ALGORAND_TESTNET_GENESIS_HASH,
769
+ V1_ALGORAND_MAINNET,
770
+ V1_ALGORAND_TESTNET,
771
+ V1_NETWORKS,
772
+ V1_TO_CAIP2,
773
+ CAIP2_TO_V1,
774
+ } from "@x402-avm/avm";
775
+ ```
776
+
777
+ ---
778
+
779
+ ## Constants: USDC Configuration
780
+
781
+ ```typescript
782
+ import {
783
+ USDC_MAINNET_ASA_ID,
784
+ USDC_TESTNET_ASA_ID,
785
+ USDC_DECIMALS,
786
+ USDC_CONFIG,
787
+ } from "@x402-avm/avm";
788
+
789
+ const testnetUsdc = USDC_CONFIG[ALGORAND_TESTNET_CAIP2];
790
+ console.log(testnetUsdc);
791
+ // { asaId: "10458941", name: "USDC", decimals: 6 }
792
+ ```
793
+
794
+ ---
795
+
796
+ ## Constants: Algod Endpoints
797
+
798
+ ```typescript
799
+ import {
800
+ DEFAULT_ALGOD_MAINNET,
801
+ DEFAULT_ALGOD_TESTNET,
802
+ NETWORK_TO_ALGOD,
803
+ FALLBACK_ALGOD_MAINNET,
804
+ FALLBACK_ALGOD_TESTNET,
805
+ } from "@x402-avm/avm";
806
+ ```
807
+
808
+ ---
809
+
810
+ ## Constants: Transaction Limits and Address Validation
811
+
812
+ ```typescript
813
+ import {
814
+ MAX_ATOMIC_GROUP_SIZE,
815
+ MIN_TXN_FEE,
816
+ MAX_REASONABLE_FEE,
817
+ ALGORAND_ADDRESS_REGEX,
818
+ ALGORAND_ADDRESS_LENGTH,
819
+ } from "@x402-avm/avm";
820
+
821
+ const isValid = ALGORAND_ADDRESS_REGEX.test(someAddress);
822
+ ```
823
+
824
+ ---
825
+
826
+ ## Utility: Address Validation
827
+
828
+ ```typescript
829
+ import { isValidAlgorandAddress } from "@x402-avm/avm";
830
+
831
+ isValidAlgorandAddress("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
832
+ // => true
833
+
834
+ isValidAlgorandAddress("invalid");
835
+ // => false
836
+ ```
837
+
838
+ ---
839
+
840
+ ## Utility: Amount Conversion
841
+
842
+ ```typescript
843
+ import { convertToTokenAmount, convertFromTokenAmount } from "@x402-avm/avm";
844
+
845
+ convertToTokenAmount("1.50", 6); // => "1500000"
846
+ convertToTokenAmount("0.10", 6); // => "100000"
847
+ convertToTokenAmount("100", 6); // => "100000000"
848
+ convertToTokenAmount("0.000001", 6); // => "1"
849
+
850
+ convertFromTokenAmount("1500000", 6); // => "1.5"
851
+ convertFromTokenAmount("100000", 6); // => "0.1"
852
+ convertFromTokenAmount("1", 6); // => "0.000001"
853
+ convertFromTokenAmount("100000000", 6); // => "100"
854
+ ```
855
+
856
+ ---
857
+
858
+ ## Utility: Transaction Encoding/Decoding
859
+
860
+ ```typescript
861
+ import {
862
+ encodeTransaction,
863
+ decodeTransaction,
864
+ decodeSignedTransaction,
865
+ decodeUnsignedTransaction,
866
+ } from "@x402-avm/avm";
867
+
868
+ const base64Str = encodeTransaction(txnBytes);
869
+ // => "iaNhbXTOAAGGoKNm..."
870
+
871
+ const bytes = decodeTransaction(base64Str);
872
+ // => Uint8Array [...]
873
+
874
+ const signedTxn = decodeSignedTransaction(base64Str);
875
+ // => algosdk.SignedTransaction
876
+
877
+ const unsignedTxn = decodeUnsignedTransaction(base64Str);
878
+ // => algosdk.Transaction
879
+ ```
880
+
881
+ ---
882
+
883
+ ## Utility: Network Functions
884
+
885
+ ```typescript
886
+ import {
887
+ getNetworkFromCaip2,
888
+ isAlgorandNetwork,
889
+ isTestnetNetwork,
890
+ v1ToCaip2,
891
+ caip2ToV1,
892
+ createAlgodClient,
893
+ } from "@x402-avm/avm";
894
+
895
+ getNetworkFromCaip2("algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=");
896
+ // => "testnet"
897
+
898
+ getNetworkFromCaip2("algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=");
899
+ // => "mainnet"
900
+
901
+ getNetworkFromCaip2("eip155:8453");
902
+ // => null
903
+
904
+ isAlgorandNetwork("algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=");
905
+ // => true
906
+
907
+ isAlgorandNetwork("algorand-testnet");
908
+ // => true
909
+
910
+ isAlgorandNetwork("eip155:8453");
911
+ // => false
912
+
913
+ isTestnetNetwork("algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=");
914
+ // => true
915
+
916
+ v1ToCaip2("algorand-testnet");
917
+ // => "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="
918
+
919
+ caip2ToV1("algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=");
920
+ // => "algorand-testnet"
921
+
922
+ const algod = createAlgodClient("algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=");
923
+
924
+ const customAlgod = createAlgodClient(
925
+ "algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=",
926
+ "https://my-custom-node.example.com",
927
+ "my-api-token",
928
+ );
929
+ ```
930
+
931
+ ---
932
+
933
+ ## Utility: Transaction Inspection
934
+
935
+ ```typescript
936
+ import {
937
+ getSenderFromTransaction,
938
+ getTransactionId,
939
+ hasSignature,
940
+ getGenesisHashFromTransaction,
941
+ validateGroupId,
942
+ assignGroupId,
943
+ } from "@x402-avm/avm";
944
+
945
+ const sender = getSenderFromTransaction(signedTxnBytes, true);
946
+ const senderUnsigned = getSenderFromTransaction(unsignedTxnBytes, false);
947
+
948
+ const txId = getTransactionId(signedTxnBytes);
949
+
950
+ const signed = hasSignature(txnBytes);
951
+
952
+ const allMatch = validateGroupId([txn1Bytes, txn2Bytes, txn3Bytes]);
953
+
954
+ const groupedTxns = assignGroupId([txn1, txn2, txn3]);
955
+ ```
956
+
957
+ ---
958
+
959
+ ## Simple Payment Group
960
+
961
+ ```typescript
962
+ import algosdk from "algosdk";
963
+ import { ALGORAND_TESTNET_CAIP2, USDC_TESTNET_ASA_ID, createAlgodClient } from "@x402-avm/avm";
964
+
965
+ async function createSimplePayment(
966
+ senderAddress: string,
967
+ receiverAddress: string,
968
+ amount: number,
969
+ ) {
970
+ const algod = createAlgodClient(ALGORAND_TESTNET_CAIP2);
971
+ const params = await algod.getTransactionParams().do();
972
+
973
+ const txn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({
974
+ from: senderAddress,
975
+ to: receiverAddress,
976
+ amount,
977
+ assetIndex: parseInt(USDC_TESTNET_ASA_ID, 10),
978
+ suggestedParams: params,
979
+ });
980
+
981
+ return [txn.toByte()];
982
+ }
983
+ ```
984
+
985
+ ---
986
+
987
+ ## Fee-Abstracted Payment Group
988
+
989
+ ```typescript
990
+ import algosdk from "algosdk";
991
+ import {
992
+ ALGORAND_TESTNET_CAIP2,
993
+ USDC_TESTNET_ASA_ID,
994
+ MIN_TXN_FEE,
995
+ createAlgodClient,
996
+ encodeTransaction,
997
+ } from "@x402-avm/avm";
998
+
999
+ async function createFeeAbstractedPayment(
1000
+ senderAddress: string,
1001
+ receiverAddress: string,
1002
+ feePayerAddress: string,
1003
+ amount: number,
1004
+ ) {
1005
+ const algod = createAlgodClient(ALGORAND_TESTNET_CAIP2);
1006
+ const params = await algod.getTransactionParams().do();
1007
+
1008
+ const paymentTxn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({
1009
+ from: senderAddress,
1010
+ to: receiverAddress,
1011
+ amount,
1012
+ assetIndex: parseInt(USDC_TESTNET_ASA_ID, 10),
1013
+ suggestedParams: {
1014
+ ...params,
1015
+ fee: 0,
1016
+ flatFee: true,
1017
+ },
1018
+ });
1019
+
1020
+ const feePayerTxn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
1021
+ from: feePayerAddress,
1022
+ to: feePayerAddress,
1023
+ amount: 0,
1024
+ suggestedParams: {
1025
+ ...params,
1026
+ fee: MIN_TXN_FEE * 2,
1027
+ flatFee: true,
1028
+ },
1029
+ });
1030
+
1031
+ const grouped = algosdk.assignGroupID([paymentTxn, feePayerTxn]);
1032
+
1033
+ const paymentBytes = grouped[0].toByte();
1034
+ const feePayerBytes = grouped[1].toByte();
1035
+
1036
+ return {
1037
+ paymentGroup: [
1038
+ encodeTransaction(paymentBytes),
1039
+ encodeTransaction(feePayerBytes),
1040
+ ],
1041
+ paymentIndex: 0,
1042
+ rawBytes: [paymentBytes, feePayerBytes],
1043
+ };
1044
+ }
1045
+ ```
1046
+
1047
+ ---
1048
+
1049
+ ## Fee Abstraction with x402Client
1050
+
1051
+ ```typescript
1052
+ import { x402Client } from "@x402-avm/core/client";
1053
+ import { registerExactAvmScheme } from "@x402-avm/avm/exact/client";
1054
+ import type { ClientAvmSigner } from "@x402-avm/avm";
1055
+ import algosdk from "algosdk";
1056
+
1057
+ const signer: ClientAvmSigner = {
1058
+ address: myAddress,
1059
+ signTransactions: async (txns, indexesToSign) => {
1060
+ return txns.map((txn, i) => {
1061
+ if (indexesToSign && !indexesToSign.includes(i)) return null;
1062
+ const decoded = algosdk.decodeUnsignedTransaction(txn);
1063
+ return algosdk.signTransaction(decoded, secretKey).blob;
1064
+ });
1065
+ },
1066
+ };
1067
+
1068
+ const client = new x402Client({ schemes: [] });
1069
+ registerExactAvmScheme(client, { signer });
1070
+
1071
+ // Fee abstraction is automatic when PaymentRequirements include a feePayer
1072
+ const response = await client.fetch("https://api.example.com/paid-resource");
1073
+ ```
1074
+
1075
+ ---
1076
+
1077
+ ## ExactAvmScheme Registration: Client
1078
+
1079
+ ```typescript
1080
+ import { x402Client } from "@x402-avm/core/client";
1081
+ import { registerExactAvmScheme } from "@x402-avm/avm/exact/client";
1082
+
1083
+ const client = new x402Client({ schemes: [] });
1084
+
1085
+ registerExactAvmScheme(client, {
1086
+ signer: myClientSigner,
1087
+ algodConfig: {
1088
+ algodUrl: "https://testnet-api.algonode.cloud",
1089
+ },
1090
+ networks: ["algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="],
1091
+ policies: [preferTestnetPolicy],
1092
+ });
1093
+ ```
1094
+
1095
+ ---
1096
+
1097
+ ## ExactAvmScheme Registration: Server
1098
+
1099
+ ```typescript
1100
+ import { x402ResourceServer } from "@x402-avm/core/server";
1101
+ import { registerExactAvmScheme } from "@x402-avm/avm/exact/server";
1102
+
1103
+ const server = new x402ResourceServer(facilitatorClient);
1104
+
1105
+ registerExactAvmScheme(server, {
1106
+ networks: ["algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="],
1107
+ });
1108
+
1109
+ // Or with wildcard (default)
1110
+ registerExactAvmScheme(server);
1111
+ ```
1112
+
1113
+ ---
1114
+
1115
+ ## ExactAvmScheme Registration: Facilitator
1116
+
1117
+ ```typescript
1118
+ import { x402Facilitator } from "@x402-avm/core/facilitator";
1119
+ import { registerExactAvmScheme } from "@x402-avm/avm/exact/facilitator";
1120
+ import { ALGORAND_TESTNET_CAIP2, ALGORAND_MAINNET_CAIP2 } from "@x402-avm/avm";
1121
+
1122
+ const facilitator = new x402Facilitator();
1123
+
1124
+ registerExactAvmScheme(facilitator, {
1125
+ signer: myFacilitatorSigner,
1126
+ networks: ALGORAND_TESTNET_CAIP2,
1127
+ });
1128
+
1129
+ registerExactAvmScheme(facilitator, {
1130
+ signer: myFacilitatorSigner,
1131
+ networks: [ALGORAND_TESTNET_CAIP2, ALGORAND_MAINNET_CAIP2],
1132
+ });
1133
+ ```
1134
+
1135
+ ---
1136
+
1137
+ ## Complete End-to-End: Full Stack
1138
+
1139
+ ```typescript
1140
+ // ============================================================
1141
+ // shared/config.ts
1142
+ // ============================================================
1143
+ import { ALGORAND_TESTNET_CAIP2, USDC_TESTNET_ASA_ID } from "@x402-avm/avm";
1144
+
1145
+ export const NETWORK = ALGORAND_TESTNET_CAIP2;
1146
+ export const USDC_ASA = USDC_TESTNET_ASA_ID;
1147
+ export const RESOURCE_WALLET = "RECEIVER_ALGORAND_ADDRESS_58_CHARS_AAAAAAAAAAAAAAAAAAA";
1148
+ export const FACILITATOR_URL = "http://localhost:4000";
1149
+ export const RESOURCE_SERVER_URL = "http://localhost:3000";
1150
+
1151
+ // ============================================================
1152
+ // facilitator/index.ts
1153
+ // ============================================================
1154
+ import express from "express";
1155
+ import { x402Facilitator } from "@x402-avm/core/facilitator";
1156
+ import { registerExactAvmScheme } from "@x402-avm/avm/exact/facilitator";
1157
+ import type { FacilitatorAvmSigner } from "@x402-avm/avm";
1158
+ import algosdk from "algosdk";
1159
+ import { NETWORK } from "../shared/config";
1160
+
1161
+ const secretKey = Buffer.from(process.env.AVM_PRIVATE_KEY!, "base64");
1162
+ const address = algosdk.encodeAddress(secretKey.slice(32));
1163
+ const algodClient = new algosdk.Algodv2("", "https://testnet-api.algonode.cloud", "");
1164
+
1165
+ const signer: FacilitatorAvmSigner = {
1166
+ getAddresses: () => [address],
1167
+ signTransaction: async (txn, _addr) => {
1168
+ const decoded = algosdk.decodeUnsignedTransaction(txn);
1169
+ return algosdk.signTransaction(decoded, secretKey).blob;
1170
+ },
1171
+ getAlgodClient: () => algodClient,
1172
+ simulateTransactions: async (txns) => {
1173
+ const stxns = txns.map((t) => {
1174
+ try { return algosdk.decodeSignedTransaction(t); }
1175
+ catch { return new algosdk.SignedTransaction({ txn: algosdk.decodeUnsignedTransaction(t) }); }
1176
+ });
1177
+ const req = new algosdk.modelsv2.SimulateRequest({
1178
+ txnGroups: [new algosdk.modelsv2.SimulateRequestTransactionGroup({ txns: stxns })],
1179
+ allowEmptySignatures: true,
1180
+ });
1181
+ return algodClient.simulateTransactions(req).do();
1182
+ },
1183
+ sendTransactions: async (signedTxns) => {
1184
+ const combined = Buffer.concat(signedTxns.map((t) => Buffer.from(t)));
1185
+ const { txId } = await algodClient.sendRawTransaction(combined).do();
1186
+ return txId;
1187
+ },
1188
+ waitForConfirmation: async (txId, _net, rounds = 4) => {
1189
+ return algosdk.waitForConfirmation(algodClient, txId, rounds);
1190
+ },
1191
+ };
1192
+
1193
+ const facilitator = new x402Facilitator();
1194
+ registerExactAvmScheme(facilitator, { signer, networks: NETWORK });
1195
+
1196
+ const app = express();
1197
+ app.use(express.json());
1198
+
1199
+ app.get("/supported", async (_req, res) => {
1200
+ const supported = facilitator.getSupportedNetworks();
1201
+ res.json(supported);
1202
+ });
1203
+
1204
+ app.post("/verify", async (req, res) => {
1205
+ const { paymentPayload, paymentRequirements } = req.body;
1206
+ const result = await facilitator.verify(paymentPayload, paymentRequirements);
1207
+ res.json(result);
1208
+ });
1209
+
1210
+ app.post("/settle", async (req, res) => {
1211
+ const { paymentPayload, paymentRequirements } = req.body;
1212
+ const result = await facilitator.settle(paymentPayload, paymentRequirements);
1213
+ res.json(result);
1214
+ });
1215
+
1216
+ app.listen(4000, () => console.log("Facilitator running on :4000"));
1217
+
1218
+ // ============================================================
1219
+ // server/index.ts
1220
+ // ============================================================
1221
+ import express from "express";
1222
+ import {
1223
+ x402HTTPResourceServer,
1224
+ HTTPFacilitatorClient,
1225
+ } from "@x402-avm/core/server";
1226
+ import { registerExactAvmScheme as registerServerScheme } from "@x402-avm/avm/exact/server";
1227
+ import {
1228
+ NETWORK,
1229
+ USDC_ASA,
1230
+ RESOURCE_WALLET,
1231
+ FACILITATOR_URL,
1232
+ } from "../shared/config";
1233
+
1234
+ const facilitatorClient = new HTTPFacilitatorClient({ url: FACILITATOR_URL });
1235
+
1236
+ const httpServer = new x402HTTPResourceServer(facilitatorClient, {
1237
+ routes: [
1238
+ {
1239
+ path: "/api/weather",
1240
+ config: {
1241
+ scheme: "exact",
1242
+ payTo: RESOURCE_WALLET,
1243
+ price: { asset: USDC_ASA, amount: "10000", extra: { name: "USDC", decimals: 6 } },
1244
+ network: NETWORK,
1245
+ maxTimeoutSeconds: 60,
1246
+ },
1247
+ description: "Weather data API",
1248
+ mimeType: "application/json",
1249
+ },
1250
+ ],
1251
+ });
1252
+ registerServerScheme(httpServer.resourceServer);
1253
+
1254
+ const app = express();
1255
+
1256
+ app.get("/api/weather", async (req, res) => {
1257
+ const result = await httpServer.processRequest({
1258
+ url: req.url,
1259
+ method: req.method,
1260
+ headers: req.headers,
1261
+ adapter: {
1262
+ getHeader: (name: string) => req.headers[name.toLowerCase()] as string,
1263
+ },
1264
+ });
1265
+
1266
+ if (result.status === 402) {
1267
+ return res.status(402).json(result.body);
1268
+ }
1269
+
1270
+ res.json({
1271
+ temperature: 72,
1272
+ condition: "Sunny",
1273
+ location: "San Francisco",
1274
+ });
1275
+ });
1276
+
1277
+ app.listen(3000, () => console.log("Resource server running on :3000"));
1278
+
1279
+ // ============================================================
1280
+ // client/index.ts
1281
+ // ============================================================
1282
+ import { x402Client } from "@x402-avm/core/client";
1283
+ import { registerExactAvmScheme as registerClientScheme } from "@x402-avm/avm/exact/client";
1284
+ import type { ClientAvmSigner } from "@x402-avm/avm";
1285
+ import algosdk from "algosdk";
1286
+ import { RESOURCE_SERVER_URL } from "../shared/config";
1287
+
1288
+ const clientSecretKey = Buffer.from(process.env.CLIENT_AVM_PRIVATE_KEY!, "base64");
1289
+ const clientAddress = algosdk.encodeAddress(clientSecretKey.slice(32));
1290
+
1291
+ const clientSigner: ClientAvmSigner = {
1292
+ address: clientAddress,
1293
+ signTransactions: async (txns, indexesToSign) => {
1294
+ return txns.map((txn, i) => {
1295
+ if (indexesToSign && !indexesToSign.includes(i)) return null;
1296
+ const decoded = algosdk.decodeUnsignedTransaction(txn);
1297
+ return algosdk.signTransaction(decoded, clientSecretKey).blob;
1298
+ });
1299
+ },
1300
+ };
1301
+
1302
+ const client = new x402Client({ schemes: [] });
1303
+ registerClientScheme(client, { signer: clientSigner });
1304
+
1305
+ async function getWeather() {
1306
+ const response = await client.fetch(`${RESOURCE_SERVER_URL}/api/weather`);
1307
+
1308
+ if (response.ok) {
1309
+ const weather = await response.json();
1310
+ console.log("Weather:", weather);
1311
+ } else {
1312
+ console.error("Failed:", response.status, response.statusText);
1313
+ }
1314
+ }
1315
+
1316
+ getWeather();
1317
+ ```
1318
+
1319
+ ---
1320
+
1321
+ ## Node.js Facilitator Service
1322
+
1323
+ ```typescript
1324
+ import express from "express";
1325
+ import { x402Facilitator } from "@x402-avm/core/facilitator";
1326
+ import { registerExactAvmScheme } from "@x402-avm/avm/exact/facilitator";
1327
+ import { ALGORAND_TESTNET_CAIP2, ALGORAND_MAINNET_CAIP2 } from "@x402-avm/avm";
1328
+ import algosdk from "algosdk";
1329
+
1330
+ const secretKey = Buffer.from(process.env.AVM_PRIVATE_KEY!, "base64");
1331
+ const address = algosdk.encodeAddress(secretKey.slice(32));
1332
+
1333
+ const algodTestnet = new algosdk.Algodv2("", "https://testnet-api.algonode.cloud", "");
1334
+ const algodMainnet = new algosdk.Algodv2("", "https://mainnet-api.algonode.cloud", "");
1335
+
1336
+ function getClient(network: string) {
1337
+ return network === ALGORAND_MAINNET_CAIP2 ? algodMainnet : algodTestnet;
1338
+ }
1339
+
1340
+ const signer = {
1341
+ getAddresses: () => [address] as const,
1342
+ signTransaction: async (txn: Uint8Array) => {
1343
+ const decoded = algosdk.decodeUnsignedTransaction(txn);
1344
+ return algosdk.signTransaction(decoded, secretKey).blob;
1345
+ },
1346
+ getAlgodClient: (network: string) => getClient(network),
1347
+ simulateTransactions: async (txns: Uint8Array[], network: string) => {
1348
+ const client = getClient(network);
1349
+ const stxns = txns.map((t) => {
1350
+ try { return algosdk.decodeSignedTransaction(t); }
1351
+ catch { return new algosdk.SignedTransaction({ txn: algosdk.decodeUnsignedTransaction(t) }); }
1352
+ });
1353
+ const req = new algosdk.modelsv2.SimulateRequest({
1354
+ txnGroups: [new algosdk.modelsv2.SimulateRequestTransactionGroup({ txns: stxns })],
1355
+ allowEmptySignatures: true,
1356
+ });
1357
+ const result = await client.simulateTransactions(req).do();
1358
+ for (const g of result.txnGroups || []) {
1359
+ if (g.failureMessage) throw new Error(`Simulation failed: ${g.failureMessage}`);
1360
+ }
1361
+ return result;
1362
+ },
1363
+ sendTransactions: async (signedTxns: Uint8Array[], network: string) => {
1364
+ const client = getClient(network);
1365
+ const combined = Buffer.concat(signedTxns.map((t) => Buffer.from(t)));
1366
+ const { txId } = await client.sendRawTransaction(combined).do();
1367
+ return txId;
1368
+ },
1369
+ waitForConfirmation: async (txId: string, network: string, rounds = 4) => {
1370
+ return algosdk.waitForConfirmation(getClient(network), txId, rounds);
1371
+ },
1372
+ };
1373
+
1374
+ const facilitator = new x402Facilitator();
1375
+ registerExactAvmScheme(facilitator, {
1376
+ signer,
1377
+ networks: [ALGORAND_TESTNET_CAIP2, ALGORAND_MAINNET_CAIP2],
1378
+ });
1379
+
1380
+ const app = express();
1381
+ app.use(express.json({ limit: "1mb" }));
1382
+
1383
+ app.get("/supported", async (_req, res) => {
1384
+ try {
1385
+ res.json(facilitator.getSupportedNetworks());
1386
+ } catch (err) {
1387
+ res.status(500).json({ error: (err as Error).message });
1388
+ }
1389
+ });
1390
+
1391
+ app.post("/verify", async (req, res) => {
1392
+ try {
1393
+ const { paymentPayload, paymentRequirements } = req.body;
1394
+ const result = await facilitator.verify(paymentPayload, paymentRequirements);
1395
+ res.json(result);
1396
+ } catch (err) {
1397
+ res.status(500).json({ error: (err as Error).message });
1398
+ }
1399
+ });
1400
+
1401
+ app.post("/settle", async (req, res) => {
1402
+ try {
1403
+ const { paymentPayload, paymentRequirements } = req.body;
1404
+ const result = await facilitator.settle(paymentPayload, paymentRequirements);
1405
+ res.json(result);
1406
+ } catch (err) {
1407
+ res.status(500).json({ error: (err as Error).message });
1408
+ }
1409
+ });
1410
+
1411
+ const PORT = parseInt(process.env.PORT || "4000", 10);
1412
+ app.listen(PORT, () => {
1413
+ console.log(`Facilitator service running on port ${PORT}`);
1414
+ console.log(`Fee payer address: ${address}`);
1415
+ console.log(`Networks: Testnet + Mainnet`);
1416
+ });
1417
+ ```