@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,554 @@
1
+ # x402-avm Python Core and AVM Examples
2
+
3
+ ## ClientAvmSigner Protocol
4
+
5
+ ```python
6
+ from x402.mechanisms.avm.signer import ClientAvmSigner
7
+
8
+ class ClientAvmSigner(Protocol):
9
+ @property
10
+ def address(self) -> str:
11
+ """58-character Algorand address."""
12
+ ...
13
+
14
+ def sign_transactions(
15
+ self,
16
+ unsigned_txns: list[bytes],
17
+ indexes_to_sign: list[int],
18
+ ) -> list[bytes | None]:
19
+ """Sign specified transactions in a group.
20
+
21
+ Args:
22
+ unsigned_txns: List of unsigned transaction bytes (msgpack encoded).
23
+ indexes_to_sign: Indexes of transactions this signer should sign.
24
+
25
+ Returns:
26
+ List parallel to unsigned_txns, with signed bytes at
27
+ indexes_to_sign and None elsewhere.
28
+ """
29
+ ...
30
+ ```
31
+
32
+ ---
33
+
34
+ ## Client Signer Implementation
35
+
36
+ ```python
37
+ import os
38
+ import base64
39
+ from x402.mechanisms.avm.signer import ClientAvmSigner
40
+ from algosdk import encoding
41
+
42
+
43
+ class PrivateKeySigner:
44
+ """
45
+ ClientAvmSigner implementation using a base64-encoded private key.
46
+
47
+ Key format: 64 bytes = [32-byte seed][32-byte public key]
48
+ algosdk expects base64-encoded 64-byte key for signing.
49
+ """
50
+
51
+ def __init__(self, private_key_b64: str):
52
+ self._secret_key = base64.b64decode(private_key_b64)
53
+ if len(self._secret_key) != 64:
54
+ raise ValueError(
55
+ f"Invalid key length: expected 64, got {len(self._secret_key)}"
56
+ )
57
+ self._address = encoding.encode_address(self._secret_key[32:])
58
+ # algosdk.Transaction.sign() expects base64 string
59
+ self._signing_key = base64.b64encode(self._secret_key).decode()
60
+
61
+ @property
62
+ def address(self) -> str:
63
+ return self._address
64
+
65
+ def sign_transactions(
66
+ self,
67
+ unsigned_txns: list[bytes],
68
+ indexes_to_sign: list[int],
69
+ ) -> list[bytes | None]:
70
+ result: list[bytes | None] = []
71
+ for i, txn_bytes in enumerate(unsigned_txns):
72
+ if i not in indexes_to_sign:
73
+ result.append(None)
74
+ continue
75
+
76
+ # IMPORTANT: algosdk.encoding.msgpack_decode expects base64 string
77
+ b64_txn = base64.b64encode(txn_bytes).decode("utf-8")
78
+ txn_obj = encoding.msgpack_decode(b64_txn)
79
+
80
+ # Sign: Transaction.sign() expects base64 private key string
81
+ signed_txn = txn_obj.sign(self._signing_key)
82
+
83
+ # IMPORTANT: algosdk.encoding.msgpack_encode returns base64 string
84
+ signed_b64 = encoding.msgpack_encode(signed_txn)
85
+ signed_bytes = base64.b64decode(signed_b64)
86
+
87
+ result.append(signed_bytes)
88
+ return result
89
+
90
+
91
+ # Usage:
92
+ signer = PrivateKeySigner(os.environ["AVM_PRIVATE_KEY"])
93
+ print(f"Signer address: {signer.address}")
94
+ ```
95
+
96
+ ---
97
+
98
+ ## FacilitatorAvmSigner Protocol
99
+
100
+ ```python
101
+ from x402.mechanisms.avm.signer import FacilitatorAvmSigner
102
+
103
+ class FacilitatorAvmSigner(Protocol):
104
+ def get_addresses(self) -> list[str]:
105
+ """Get all managed fee payer addresses."""
106
+ ...
107
+
108
+ def sign_transaction(
109
+ self, txn_bytes: bytes, fee_payer: str, network: str,
110
+ ) -> bytes:
111
+ """Sign a single transaction with the fee payer's key."""
112
+ ...
113
+
114
+ def sign_group(
115
+ self,
116
+ group_bytes: list[bytes],
117
+ fee_payer: str,
118
+ indexes_to_sign: list[int],
119
+ network: str,
120
+ ) -> list[bytes]:
121
+ """Sign specified transactions in a group."""
122
+ ...
123
+
124
+ def simulate_group(
125
+ self, group_bytes: list[bytes], network: str,
126
+ ) -> None:
127
+ """Simulate a transaction group (raises on failure)."""
128
+ ...
129
+
130
+ def send_group(
131
+ self, group_bytes: list[bytes], network: str,
132
+ ) -> str:
133
+ """Send a transaction group, returns txid."""
134
+ ...
135
+
136
+ def confirm_transaction(
137
+ self, txid: str, network: str, rounds: int = 4,
138
+ ) -> None:
139
+ """Wait for transaction confirmation."""
140
+ ...
141
+ ```
142
+
143
+ ---
144
+
145
+ ## Facilitator Signer Implementation
146
+
147
+ ```python
148
+ import base64
149
+ from x402.mechanisms.avm.signer import FacilitatorAvmSigner
150
+ from x402.mechanisms.avm.constants import NETWORK_CONFIGS
151
+ from algosdk import encoding, transaction
152
+ from algosdk.v2client import algod
153
+
154
+
155
+ class AlgorandFacilitatorSigner:
156
+ def __init__(self, private_key_b64: str, algod_url: str = "", algod_token: str = ""):
157
+ self._secret_key = base64.b64decode(private_key_b64)
158
+ self._address = encoding.encode_address(self._secret_key[32:])
159
+ self._signing_key = base64.b64encode(self._secret_key).decode()
160
+ self._clients: dict[str, algod.AlgodClient] = {}
161
+ if algod_url:
162
+ self._default_client = algod.AlgodClient(algod_token, algod_url)
163
+ else:
164
+ self._default_client = None
165
+
166
+ def _get_client(self, network: str) -> algod.AlgodClient:
167
+ if network not in self._clients:
168
+ if self._default_client:
169
+ self._clients[network] = self._default_client
170
+ else:
171
+ config = NETWORK_CONFIGS.get(network, {})
172
+ url = config.get("algod_url", "https://testnet-api.algonode.cloud")
173
+ self._clients[network] = algod.AlgodClient("", url)
174
+ return self._clients[network]
175
+
176
+ def get_addresses(self) -> list[str]:
177
+ return [self._address]
178
+
179
+ def sign_transaction(self, txn_bytes, fee_payer, network):
180
+ b64 = base64.b64encode(txn_bytes).decode("utf-8")
181
+ txn_obj = encoding.msgpack_decode(b64)
182
+ signed = txn_obj.sign(self._signing_key)
183
+ return base64.b64decode(encoding.msgpack_encode(signed))
184
+
185
+ def sign_group(self, group_bytes, fee_payer, indexes_to_sign, network):
186
+ result = list(group_bytes)
187
+ for i in indexes_to_sign:
188
+ result[i] = self.sign_transaction(group_bytes[i], fee_payer, network)
189
+ return result
190
+
191
+ def simulate_group(self, group_bytes, network):
192
+ client = self._get_client(network)
193
+ stxns = []
194
+ for txn_bytes in group_bytes:
195
+ b64 = base64.b64encode(txn_bytes).decode("utf-8")
196
+ obj = encoding.msgpack_decode(b64)
197
+ if isinstance(obj, transaction.SignedTransaction):
198
+ stxns.append(obj)
199
+ else:
200
+ stxns.append(transaction.SignedTransaction(obj, None))
201
+ req = transaction.SimulateRequest(
202
+ txn_groups=[transaction.SimulateRequestTransactionGroup(txns=stxns)],
203
+ allow_empty_signatures=True,
204
+ )
205
+ result = client.simulate_raw_transactions(req)
206
+ for group in result.get("txn-groups", []):
207
+ if group.get("failure-message"):
208
+ raise Exception(f"Simulation failed: {group['failure-message']}")
209
+
210
+ def send_group(self, group_bytes, network):
211
+ client = self._get_client(network)
212
+ return client.send_raw_transaction(base64.b64encode(b"".join(group_bytes)))
213
+
214
+ def confirm_transaction(self, txid, network, rounds=4):
215
+ client = self._get_client(network)
216
+ transaction.wait_for_confirmation(client, txid, rounds)
217
+ ```
218
+
219
+ ---
220
+
221
+ ## Constants
222
+
223
+ ### Network Identifiers
224
+
225
+ ```python
226
+ from x402.mechanisms.avm.constants import (
227
+ ALGORAND_MAINNET_CAIP2, # "algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8="
228
+ ALGORAND_TESTNET_CAIP2, # "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="
229
+ SUPPORTED_NETWORKS, # [MAINNET_CAIP2, TESTNET_CAIP2]
230
+ MAINNET_GENESIS_HASH,
231
+ TESTNET_GENESIS_HASH,
232
+ V1_NETWORKS,
233
+ V1_TO_V2_NETWORK_MAP,
234
+ V2_TO_V1_NETWORK_MAP,
235
+ )
236
+ ```
237
+
238
+ ### USDC Configuration
239
+
240
+ ```python
241
+ from x402.mechanisms.avm.constants import (
242
+ USDC_MAINNET_ASA_ID, # 31566704
243
+ USDC_TESTNET_ASA_ID, # 10458941
244
+ DEFAULT_DECIMALS, # 6
245
+ NETWORK_CONFIGS,
246
+ )
247
+
248
+ testnet_config = NETWORK_CONFIGS[ALGORAND_TESTNET_CAIP2]
249
+ usdc_info = testnet_config["default_asset"]
250
+ # {"asa_id": 10458941, "name": "USDC", "decimals": 6}
251
+ ```
252
+
253
+ ### Algod Endpoints
254
+
255
+ ```python
256
+ from x402.mechanisms.avm.constants import (
257
+ MAINNET_ALGOD_URL,
258
+ TESTNET_ALGOD_URL,
259
+ FALLBACK_ALGOD_MAINNET, # "https://mainnet-api.algonode.cloud"
260
+ FALLBACK_ALGOD_TESTNET, # "https://testnet-api.algonode.cloud"
261
+ )
262
+ ```
263
+
264
+ ### Transaction Limits
265
+
266
+ ```python
267
+ from x402.mechanisms.avm.constants import (
268
+ MAX_GROUP_SIZE, # 16
269
+ MIN_TXN_FEE, # 1000
270
+ )
271
+ ```
272
+
273
+ ### Address Validation
274
+
275
+ ```python
276
+ from x402.mechanisms.avm.constants import AVM_ADDRESS_REGEX
277
+ import re
278
+
279
+ is_valid = bool(re.match(AVM_ADDRESS_REGEX, some_address))
280
+ ```
281
+
282
+ ---
283
+
284
+ ## Utility Functions
285
+
286
+ ### Address Validation
287
+
288
+ ```python
289
+ from x402.mechanisms.avm.utils import is_valid_address
290
+
291
+ is_valid_address("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
292
+ # => True
293
+
294
+ is_valid_address("invalid")
295
+ # => False
296
+ ```
297
+
298
+ ### Amount Conversion
299
+
300
+ ```python
301
+ from x402.mechanisms.avm.utils import to_atomic_amount, from_atomic_amount
302
+
303
+ to_atomic_amount(1.50) # => 1500000
304
+ to_atomic_amount(0.10) # => 100000
305
+ to_atomic_amount(0.000001) # => 1
306
+
307
+ from_atomic_amount(1500000) # => 1.5
308
+ from_atomic_amount(100000) # => 0.1
309
+ from_atomic_amount(1) # => 1e-06
310
+ ```
311
+
312
+ ### Transaction Encoding/Decoding
313
+
314
+ ```python
315
+ from x402.mechanisms.avm.utils import (
316
+ decode_transaction_bytes,
317
+ decode_base64_transaction,
318
+ decode_payment_group,
319
+ encode_transaction_group,
320
+ )
321
+
322
+ # Decode raw bytes
323
+ info = decode_transaction_bytes(raw_txn_bytes)
324
+ print(info.type) # "axfer" or "pay"
325
+ print(info.sender) # Algorand address
326
+ print(info.fee) # in microAlgos
327
+ print(info.is_signed) # True/False
328
+ print(info.asset_amount) # for asset transfers
329
+ print(info.receiver) # for payments
330
+
331
+ # Decode from base64 string
332
+ info = decode_base64_transaction(base64_txn_string)
333
+
334
+ # Decode a full payment group
335
+ group_info = decode_payment_group(
336
+ payment_group=["base64txn1...", "base64txn2..."],
337
+ payment_index=0,
338
+ )
339
+ print(group_info.transactions)
340
+ print(group_info.group_id)
341
+ print(group_info.total_fee)
342
+ print(group_info.has_fee_payer)
343
+
344
+ # Encode to base64
345
+ encoded = encode_transaction_group([raw_bytes_1, raw_bytes_2])
346
+ ```
347
+
348
+ ### Network Utilities
349
+
350
+ ```python
351
+ from x402.mechanisms.avm.utils import (
352
+ normalize_network,
353
+ is_valid_network,
354
+ get_network_config,
355
+ get_usdc_asa_id,
356
+ get_genesis_hash,
357
+ network_from_genesis_hash,
358
+ )
359
+
360
+ normalize_network("algorand-testnet")
361
+ # => "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="
362
+
363
+ is_valid_network("algorand-testnet") # True
364
+ is_valid_network("unknown-network") # False
365
+
366
+ config = get_network_config("algorand-testnet")
367
+ # {"algod_url": "...", "genesis_hash": "...", "default_asset": {...}}
368
+
369
+ get_usdc_asa_id("algorand-testnet") # 10458941
370
+ ```
371
+
372
+ ### Security Validation
373
+
374
+ ```python
375
+ from x402.mechanisms.avm.utils import (
376
+ validate_no_security_risks,
377
+ validate_fee_payer_transaction,
378
+ is_blocked_transaction_type,
379
+ )
380
+
381
+ info = decode_transaction_bytes(txn_bytes)
382
+ error_code = validate_no_security_risks(info)
383
+ if error_code:
384
+ raise ValueError(f"Security risk: {error_code}")
385
+
386
+ error_code = validate_fee_payer_transaction(info, expected_fee_payer="ABC...")
387
+ if error_code:
388
+ raise ValueError(f"Invalid fee payer: {error_code}")
389
+
390
+ is_blocked_transaction_type("keyreg") # True
391
+ is_blocked_transaction_type("axfer") # False
392
+ ```
393
+
394
+ ---
395
+
396
+ ## Transaction Group Creation
397
+
398
+ ### Simple Payment Group
399
+
400
+ ```python
401
+ import base64
402
+ from algosdk import transaction, encoding
403
+ from algosdk.v2client import algod
404
+ from x402.mechanisms.avm.constants import (
405
+ ALGORAND_TESTNET_CAIP2,
406
+ USDC_TESTNET_ASA_ID,
407
+ NETWORK_CONFIGS,
408
+ )
409
+
410
+
411
+ def create_simple_payment(sender, receiver, amount):
412
+ config = NETWORK_CONFIGS[ALGORAND_TESTNET_CAIP2]
413
+ client = algod.AlgodClient("", config["algod_url"])
414
+ params = client.suggested_params()
415
+
416
+ txn = transaction.AssetTransferTxn(
417
+ sender=sender, sp=params, receiver=receiver,
418
+ amt=amount, index=USDC_TESTNET_ASA_ID,
419
+ )
420
+ return [base64.b64decode(encoding.msgpack_encode(txn))]
421
+ ```
422
+
423
+ ### Fee-Abstracted Payment Group
424
+
425
+ ```python
426
+ import base64
427
+ from algosdk import transaction, encoding
428
+ from algosdk.v2client import algod
429
+ from x402.mechanisms.avm.constants import (
430
+ ALGORAND_TESTNET_CAIP2,
431
+ USDC_TESTNET_ASA_ID,
432
+ MIN_TXN_FEE,
433
+ NETWORK_CONFIGS,
434
+ )
435
+ from x402.mechanisms.avm.utils import encode_transaction_group
436
+
437
+
438
+ def create_fee_abstracted_payment(sender, receiver, fee_payer, amount):
439
+ config = NETWORK_CONFIGS[ALGORAND_TESTNET_CAIP2]
440
+ client = algod.AlgodClient("", config["algod_url"])
441
+ params = client.suggested_params()
442
+
443
+ # Transaction 0: USDC transfer (fee = 0)
444
+ payment_params = transaction.SuggestedParams(
445
+ fee=0, first=params.first, last=params.last,
446
+ gh=params.gh, gen=params.gen, flat_fee=True,
447
+ )
448
+ payment_txn = transaction.AssetTransferTxn(
449
+ sender=sender, sp=payment_params, receiver=receiver,
450
+ amt=amount, index=USDC_TESTNET_ASA_ID,
451
+ )
452
+
453
+ # Transaction 1: Fee payer (self-payment, covers both fees)
454
+ fee_params = transaction.SuggestedParams(
455
+ fee=MIN_TXN_FEE * 2, first=params.first, last=params.last,
456
+ gh=params.gh, gen=params.gen, flat_fee=True,
457
+ )
458
+ fee_payer_txn = transaction.PaymentTxn(
459
+ sender=fee_payer, sp=fee_params,
460
+ receiver=fee_payer, amt=0,
461
+ )
462
+
463
+ # Assign group ID
464
+ gid = transaction.calculate_group_id([payment_txn, fee_payer_txn])
465
+ payment_txn.group = gid
466
+ fee_payer_txn.group = gid
467
+
468
+ payment_bytes = base64.b64decode(encoding.msgpack_encode(payment_txn))
469
+ fee_payer_bytes = base64.b64decode(encoding.msgpack_encode(fee_payer_txn))
470
+
471
+ return {
472
+ "paymentGroup": encode_transaction_group([payment_bytes, fee_payer_bytes]),
473
+ "paymentIndex": 0,
474
+ "rawBytes": [payment_bytes, fee_payer_bytes],
475
+ }
476
+ ```
477
+
478
+ ---
479
+
480
+ ## ExactAvmScheme Registration
481
+
482
+ ### Client Registration
483
+
484
+ ```python
485
+ from x402 import x402Client
486
+ from x402.mechanisms.avm.exact import register_exact_avm_client
487
+
488
+ client = x402Client()
489
+ register_exact_avm_client(client, signer)
490
+ ```
491
+
492
+ ### Server Registration
493
+
494
+ ```python
495
+ from x402 import x402ResourceServer
496
+ from x402.mechanisms.avm.exact import register_exact_avm_server
497
+
498
+ server = x402ResourceServer(facilitator_url="https://facilitator.example.com")
499
+ register_exact_avm_server(server)
500
+ ```
501
+
502
+ ### Facilitator Registration
503
+
504
+ ```python
505
+ from x402 import x402Facilitator
506
+ from x402.mechanisms.avm.exact import register_exact_avm_facilitator
507
+ from x402.mechanisms.avm import ALGORAND_TESTNET_CAIP2, ALGORAND_MAINNET_CAIP2
508
+
509
+ facilitator = x402Facilitator()
510
+
511
+ # Single network
512
+ register_exact_avm_facilitator(
513
+ facilitator, signer, networks=[ALGORAND_TESTNET_CAIP2]
514
+ )
515
+
516
+ # Multiple networks
517
+ register_exact_avm_facilitator(
518
+ facilitator, signer, networks=[ALGORAND_TESTNET_CAIP2, ALGORAND_MAINNET_CAIP2]
519
+ )
520
+ ```
521
+
522
+ ---
523
+
524
+ ## Client-Side Fee Abstraction
525
+
526
+ ```python
527
+ from x402 import x402Client
528
+ from x402.mechanisms.avm.exact import register_exact_avm_client
529
+
530
+ signer = MyClientSigner(os.environ["AVM_PRIVATE_KEY"])
531
+ client = x402Client()
532
+ register_exact_avm_client(client, signer)
533
+
534
+ # Fee abstraction is automatic when PaymentRequirements include feePayer info
535
+ response = await client.fetch("https://api.example.com/paid-resource")
536
+ ```
537
+
538
+ ---
539
+
540
+ ## algosdk Encoding Boundary Patterns
541
+
542
+ ```python
543
+ import base64
544
+ from algosdk import encoding
545
+
546
+ # Raw bytes -> algosdk object (DECODE)
547
+ raw_bytes: bytes = ...
548
+ b64_string = base64.b64encode(raw_bytes).decode("utf-8")
549
+ txn_obj = encoding.msgpack_decode(b64_string)
550
+
551
+ # algosdk object -> raw bytes (ENCODE)
552
+ b64_string = encoding.msgpack_encode(txn_obj)
553
+ raw_bytes = base64.b64decode(b64_string)
554
+ ```