@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.
- package/LICENSE +21 -0
- package/README.md +112 -0
- package/index.ts +361 -0
- package/lib/mcp-servers.ts +14 -0
- package/lib/x402-fetch.ts +213 -0
- package/memory/algorand-plugin.md +82 -0
- package/openclaw.plugin.json +30 -0
- package/package.json +41 -0
- package/setup.ts +80 -0
- package/skills/algorand-development/SKILL.md +90 -0
- package/skills/algorand-development/references/build-smart-contracts-reference.md +79 -0
- package/skills/algorand-development/references/build-smart-contracts.md +52 -0
- package/skills/algorand-development/references/create-project-reference.md +86 -0
- package/skills/algorand-development/references/create-project.md +89 -0
- package/skills/algorand-development/references/implement-arc-standards-arc32-arc56.md +396 -0
- package/skills/algorand-development/references/implement-arc-standards-arc4.md +265 -0
- package/skills/algorand-development/references/implement-arc-standards.md +92 -0
- package/skills/algorand-development/references/search-algorand-examples-reference.md +119 -0
- package/skills/algorand-development/references/search-algorand-examples.md +89 -0
- package/skills/algorand-development/references/troubleshoot-errors-contract.md +373 -0
- package/skills/algorand-development/references/troubleshoot-errors-transaction.md +599 -0
- package/skills/algorand-development/references/troubleshoot-errors.md +105 -0
- package/skills/algorand-development/references/use-algokit-cli-reference.md +228 -0
- package/skills/algorand-development/references/use-algokit-cli.md +64 -0
- package/skills/algorand-interaction/SKILL.md +223 -0
- package/skills/algorand-interaction/references/algorand-mcp.md +743 -0
- package/skills/algorand-interaction/references/examples-algorand-mcp.md +647 -0
- package/skills/algorand-python/SKILL.md +95 -0
- package/skills/algorand-python/references/build-smart-contracts-decorators.md +413 -0
- package/skills/algorand-python/references/build-smart-contracts-reference.md +55 -0
- package/skills/algorand-python/references/build-smart-contracts-storage.md +452 -0
- package/skills/algorand-python/references/build-smart-contracts-transactions.md +445 -0
- package/skills/algorand-python/references/build-smart-contracts-types.md +438 -0
- package/skills/algorand-python/references/build-smart-contracts.md +82 -0
- package/skills/algorand-python/references/create-project-reference.md +55 -0
- package/skills/algorand-python/references/create-project.md +75 -0
- package/skills/algorand-python/references/implement-arc-standards-arc32-arc56.md +101 -0
- package/skills/algorand-python/references/implement-arc-standards-arc4.md +154 -0
- package/skills/algorand-python/references/implement-arc-standards.md +39 -0
- package/skills/algorand-python/references/troubleshoot-errors-contract.md +355 -0
- package/skills/algorand-python/references/troubleshoot-errors-transaction.md +430 -0
- package/skills/algorand-python/references/troubleshoot-errors.md +46 -0
- package/skills/algorand-python/references/use-algokit-utils-reference.md +350 -0
- package/skills/algorand-python/references/use-algokit-utils.md +76 -0
- package/skills/algorand-typescript/SKILL.md +131 -0
- package/skills/algorand-typescript/references/algorand-ts-migration-from-beta.md +448 -0
- package/skills/algorand-typescript/references/algorand-ts-migration-from-tealscript.md +487 -0
- package/skills/algorand-typescript/references/algorand-ts-migration.md +102 -0
- package/skills/algorand-typescript/references/algorand-typescript-syntax-methods-and-abi.md +134 -0
- package/skills/algorand-typescript/references/algorand-typescript-syntax-reference.md +58 -0
- package/skills/algorand-typescript/references/algorand-typescript-syntax-storage.md +154 -0
- package/skills/algorand-typescript/references/algorand-typescript-syntax-transactions.md +187 -0
- package/skills/algorand-typescript/references/algorand-typescript-syntax-types-and-values.md +150 -0
- package/skills/algorand-typescript/references/algorand-typescript-syntax.md +84 -0
- package/skills/algorand-typescript/references/build-smart-contracts-reference.md +52 -0
- package/skills/algorand-typescript/references/build-smart-contracts.md +74 -0
- package/skills/algorand-typescript/references/call-smart-contracts-reference.md +237 -0
- package/skills/algorand-typescript/references/call-smart-contracts.md +183 -0
- package/skills/algorand-typescript/references/create-project-reference.md +53 -0
- package/skills/algorand-typescript/references/create-project.md +86 -0
- package/skills/algorand-typescript/references/deploy-react-frontend-examples.md +527 -0
- package/skills/algorand-typescript/references/deploy-react-frontend-reference.md +412 -0
- package/skills/algorand-typescript/references/deploy-react-frontend.md +239 -0
- package/skills/algorand-typescript/references/implement-arc-standards-arc32-arc56.md +73 -0
- package/skills/algorand-typescript/references/implement-arc-standards-arc4.md +126 -0
- package/skills/algorand-typescript/references/implement-arc-standards.md +44 -0
- package/skills/algorand-typescript/references/test-smart-contracts-examples.md +245 -0
- package/skills/algorand-typescript/references/test-smart-contracts-unit-tests.md +147 -0
- package/skills/algorand-typescript/references/test-smart-contracts.md +127 -0
- package/skills/algorand-typescript/references/troubleshoot-errors-contract.md +296 -0
- package/skills/algorand-typescript/references/troubleshoot-errors-transaction.md +438 -0
- package/skills/algorand-typescript/references/troubleshoot-errors.md +56 -0
- package/skills/algorand-typescript/references/use-algokit-utils-reference.md +342 -0
- package/skills/algorand-typescript/references/use-algokit-utils.md +74 -0
- package/skills/algorand-x402-python/SKILL.md +113 -0
- package/skills/algorand-x402-python/references/create-python-x402-client-examples.md +469 -0
- package/skills/algorand-x402-python/references/create-python-x402-client-reference.md +313 -0
- package/skills/algorand-x402-python/references/create-python-x402-client.md +207 -0
- package/skills/algorand-x402-python/references/create-python-x402-facilitator-examples.md +924 -0
- package/skills/algorand-x402-python/references/create-python-x402-facilitator-reference.md +629 -0
- package/skills/algorand-x402-python/references/create-python-x402-facilitator.md +408 -0
- package/skills/algorand-x402-python/references/create-python-x402-server-examples.md +703 -0
- package/skills/algorand-x402-python/references/create-python-x402-server-reference.md +303 -0
- package/skills/algorand-x402-python/references/create-python-x402-server.md +221 -0
- package/skills/algorand-x402-python/references/explain-algorand-x402-python-examples.md +605 -0
- package/skills/algorand-x402-python/references/explain-algorand-x402-python-reference.md +315 -0
- package/skills/algorand-x402-python/references/explain-algorand-x402-python.md +167 -0
- package/skills/algorand-x402-python/references/use-python-x402-core-avm-examples.md +554 -0
- package/skills/algorand-x402-python/references/use-python-x402-core-avm-reference.md +278 -0
- package/skills/algorand-x402-python/references/use-python-x402-core-avm.md +166 -0
- package/skills/algorand-x402-typescript/SKILL.md +129 -0
- package/skills/algorand-x402-typescript/references/create-typescript-x402-client-examples.md +879 -0
- package/skills/algorand-x402-typescript/references/create-typescript-x402-client-reference.md +371 -0
- package/skills/algorand-x402-typescript/references/create-typescript-x402-client.md +236 -0
- package/skills/algorand-x402-typescript/references/create-typescript-x402-facilitator-examples.md +875 -0
- package/skills/algorand-x402-typescript/references/create-typescript-x402-facilitator-reference.md +461 -0
- package/skills/algorand-x402-typescript/references/create-typescript-x402-facilitator.md +270 -0
- package/skills/algorand-x402-typescript/references/create-typescript-x402-nextjs-examples.md +1181 -0
- package/skills/algorand-x402-typescript/references/create-typescript-x402-nextjs-reference.md +360 -0
- package/skills/algorand-x402-typescript/references/create-typescript-x402-nextjs.md +251 -0
- package/skills/algorand-x402-typescript/references/create-typescript-x402-paywall-examples.md +870 -0
- package/skills/algorand-x402-typescript/references/create-typescript-x402-paywall-reference.md +323 -0
- package/skills/algorand-x402-typescript/references/create-typescript-x402-paywall.md +281 -0
- package/skills/algorand-x402-typescript/references/create-typescript-x402-server-examples.md +1135 -0
- package/skills/algorand-x402-typescript/references/create-typescript-x402-server-reference.md +382 -0
- package/skills/algorand-x402-typescript/references/create-typescript-x402-server.md +216 -0
- package/skills/algorand-x402-typescript/references/explain-algorand-x402-typescript-examples.md +616 -0
- package/skills/algorand-x402-typescript/references/explain-algorand-x402-typescript-reference.md +323 -0
- package/skills/algorand-x402-typescript/references/explain-algorand-x402-typescript.md +232 -0
- package/skills/algorand-x402-typescript/references/use-typescript-x402-core-avm-examples.md +1417 -0
- package/skills/algorand-x402-typescript/references/use-typescript-x402-core-avm-reference.md +504 -0
- package/skills/algorand-x402-typescript/references/use-typescript-x402-core-avm.md +158 -0
package/skills/algorand-x402-typescript/references/explain-algorand-x402-typescript-examples.md
ADDED
|
@@ -0,0 +1,616 @@
|
|
|
1
|
+
# x402-avm TypeScript Examples
|
|
2
|
+
|
|
3
|
+
## Network Identifiers
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import type { Network } from "@x402-avm/core/types";
|
|
7
|
+
import {
|
|
8
|
+
ALGORAND_TESTNET_CAIP2,
|
|
9
|
+
ALGORAND_MAINNET_CAIP2,
|
|
10
|
+
V1_ALGORAND_TESTNET,
|
|
11
|
+
V1_ALGORAND_MAINNET,
|
|
12
|
+
V1_TO_CAIP2,
|
|
13
|
+
CAIP2_TO_V1,
|
|
14
|
+
} from "@x402-avm/avm";
|
|
15
|
+
|
|
16
|
+
const testnet: Network = ALGORAND_TESTNET_CAIP2;
|
|
17
|
+
// => "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="
|
|
18
|
+
|
|
19
|
+
const mainnet: Network = ALGORAND_MAINNET_CAIP2;
|
|
20
|
+
// => "algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8="
|
|
21
|
+
|
|
22
|
+
const caip2 = V1_TO_CAIP2["algorand-testnet"];
|
|
23
|
+
const v1Name = CAIP2_TO_V1[ALGORAND_TESTNET_CAIP2];
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## PaymentRequirements (V2)
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import type { PaymentRequirements } from "@x402-avm/core/types";
|
|
30
|
+
import { ALGORAND_TESTNET_CAIP2, USDC_TESTNET_ASA_ID } from "@x402-avm/avm";
|
|
31
|
+
|
|
32
|
+
const requirements: PaymentRequirements = {
|
|
33
|
+
scheme: "exact",
|
|
34
|
+
network: ALGORAND_TESTNET_CAIP2,
|
|
35
|
+
maxAmountRequired: "1000000",
|
|
36
|
+
resource: "https://api.example.com/premium/data",
|
|
37
|
+
description: "Access to premium API endpoint",
|
|
38
|
+
mimeType: "application/json",
|
|
39
|
+
payTo: "RECEIVER_ALGORAND_ADDRESS_58_CHARS_AAAAAAAAAAAAAAAAAAA",
|
|
40
|
+
maxTimeoutSeconds: 60,
|
|
41
|
+
asset: USDC_TESTNET_ASA_ID,
|
|
42
|
+
outputSchema: undefined,
|
|
43
|
+
extra: {
|
|
44
|
+
name: "USDC",
|
|
45
|
+
decimals: 6,
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## PaymentPayload
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import type { PaymentPayload } from "@x402-avm/core/types";
|
|
54
|
+
import { ALGORAND_TESTNET_CAIP2 } from "@x402-avm/avm";
|
|
55
|
+
|
|
56
|
+
const payload: PaymentPayload = {
|
|
57
|
+
x402Version: 2,
|
|
58
|
+
scheme: "exact",
|
|
59
|
+
network: ALGORAND_TESTNET_CAIP2,
|
|
60
|
+
payload: {
|
|
61
|
+
paymentGroup: [
|
|
62
|
+
"iaNhbXTOAAGGoKNm...",
|
|
63
|
+
"iaNhbXTOAAGGoKNm...",
|
|
64
|
+
],
|
|
65
|
+
paymentIndex: 0,
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## ClientAvmSigner Interface
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import type { ClientAvmSigner } from "@x402-avm/avm";
|
|
74
|
+
|
|
75
|
+
interface ClientAvmSigner {
|
|
76
|
+
address: string;
|
|
77
|
+
signTransactions(
|
|
78
|
+
txns: Uint8Array[],
|
|
79
|
+
indexesToSign?: number[],
|
|
80
|
+
): Promise<(Uint8Array | null)[]>;
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## ClientAvmSigner with @txnlab/use-wallet (Browser)
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import type { ClientAvmSigner } from "@x402-avm/avm";
|
|
88
|
+
import { useWallet } from "@txnlab/use-wallet";
|
|
89
|
+
|
|
90
|
+
function PaymentComponent() {
|
|
91
|
+
const { activeAccount, signTransactions } = useWallet();
|
|
92
|
+
|
|
93
|
+
const signer: ClientAvmSigner | null = activeAccount
|
|
94
|
+
? {
|
|
95
|
+
address: activeAccount.address,
|
|
96
|
+
signTransactions: async (txns, indexesToSign) => {
|
|
97
|
+
return signTransactions(txns, indexesToSign);
|
|
98
|
+
},
|
|
99
|
+
}
|
|
100
|
+
: null;
|
|
101
|
+
|
|
102
|
+
return signer ? <PaidContent signer={signer} /> : <ConnectWallet />;
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Full React Example with Wallet
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import React, { useCallback } from "react";
|
|
110
|
+
import { x402Client } from "@x402-avm/core/client";
|
|
111
|
+
import { registerExactAvmScheme } from "@x402-avm/avm/exact/client";
|
|
112
|
+
import type { ClientAvmSigner } from "@x402-avm/avm";
|
|
113
|
+
import { WalletProvider, useWallet, WalletId } from "@txnlab/use-wallet-react";
|
|
114
|
+
|
|
115
|
+
const walletConfig = {
|
|
116
|
+
wallets: [WalletId.PERA, WalletId.DEFLY, WalletId.KIBISIS],
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
function PaidContent() {
|
|
120
|
+
const { activeAccount, signTransactions } = useWallet();
|
|
121
|
+
|
|
122
|
+
const fetchPaidResource = useCallback(async () => {
|
|
123
|
+
if (!activeAccount) return;
|
|
124
|
+
|
|
125
|
+
const signer: ClientAvmSigner = {
|
|
126
|
+
address: activeAccount.address,
|
|
127
|
+
signTransactions: async (txns, indexes) => signTransactions(txns, indexes),
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const client = new x402Client({ schemes: [] });
|
|
131
|
+
registerExactAvmScheme(client, { signer });
|
|
132
|
+
|
|
133
|
+
const response = await client.fetch("https://api.example.com/premium");
|
|
134
|
+
if (response.ok) {
|
|
135
|
+
const data = await response.json();
|
|
136
|
+
console.log("Data:", data);
|
|
137
|
+
}
|
|
138
|
+
}, [activeAccount, signTransactions]);
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<button onClick={fetchPaidResource} disabled={!activeAccount}>
|
|
142
|
+
Fetch Paid Resource
|
|
143
|
+
</button>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export default function App() {
|
|
148
|
+
return (
|
|
149
|
+
<WalletProvider value={walletConfig}>
|
|
150
|
+
<PaidContent />
|
|
151
|
+
</WalletProvider>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## ClientAvmSigner with algosdk Private Key (Server-Side)
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
import type { ClientAvmSigner } from "@x402-avm/avm";
|
|
160
|
+
import algosdk from "algosdk";
|
|
161
|
+
|
|
162
|
+
function createPrivateKeySigner(privateKeyBase64: string): ClientAvmSigner {
|
|
163
|
+
const secretKey = Buffer.from(privateKeyBase64, "base64");
|
|
164
|
+
|
|
165
|
+
if (secretKey.length !== 64) {
|
|
166
|
+
throw new Error(`Invalid key length: expected 64, got ${secretKey.length}`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const address = algosdk.encodeAddress(secretKey.slice(32));
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
address,
|
|
173
|
+
signTransactions: async (
|
|
174
|
+
txns: Uint8Array[],
|
|
175
|
+
indexesToSign?: number[],
|
|
176
|
+
): Promise<(Uint8Array | null)[]> => {
|
|
177
|
+
return txns.map((txnBytes, i) => {
|
|
178
|
+
if (indexesToSign && !indexesToSign.includes(i)) {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
const decoded = algosdk.decodeUnsignedTransaction(txnBytes);
|
|
182
|
+
const signed = algosdk.signTransaction(decoded, secretKey);
|
|
183
|
+
return signed.blob;
|
|
184
|
+
});
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const signer = createPrivateKeySigner(process.env.AVM_PRIVATE_KEY!);
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## FacilitatorAvmSigner Interface
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
import type { FacilitatorAvmSigner } from "@x402-avm/avm";
|
|
196
|
+
import type { Network } from "@x402-avm/core/types";
|
|
197
|
+
|
|
198
|
+
interface FacilitatorAvmSigner {
|
|
199
|
+
getAddresses(): readonly string[];
|
|
200
|
+
signTransaction(txn: Uint8Array, senderAddress: string): Promise<Uint8Array>;
|
|
201
|
+
getAlgodClient(network: Network): unknown;
|
|
202
|
+
simulateTransactions(txns: Uint8Array[], network: Network): Promise<unknown>;
|
|
203
|
+
sendTransactions(signedTxns: Uint8Array[], network: Network): Promise<string>;
|
|
204
|
+
waitForConfirmation(txId: string, network: Network, waitRounds?: number): Promise<unknown>;
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## FacilitatorAvmSigner Implementation
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
import type { FacilitatorAvmSigner } from "@x402-avm/avm";
|
|
212
|
+
import type { Network } from "@x402-avm/core/types";
|
|
213
|
+
import {
|
|
214
|
+
ALGORAND_TESTNET_CAIP2,
|
|
215
|
+
ALGORAND_MAINNET_CAIP2,
|
|
216
|
+
createAlgodClient,
|
|
217
|
+
isTestnetNetwork,
|
|
218
|
+
} from "@x402-avm/avm";
|
|
219
|
+
import algosdk from "algosdk";
|
|
220
|
+
|
|
221
|
+
function createFacilitatorSigner(privateKeyBase64: string): FacilitatorAvmSigner {
|
|
222
|
+
const secretKey = Buffer.from(privateKeyBase64, "base64");
|
|
223
|
+
const address = algosdk.encodeAddress(secretKey.slice(32));
|
|
224
|
+
const clients: Record<string, algosdk.Algodv2> = {};
|
|
225
|
+
|
|
226
|
+
function getClient(network: Network): algosdk.Algodv2 {
|
|
227
|
+
if (!clients[network]) {
|
|
228
|
+
clients[network] = createAlgodClient(network);
|
|
229
|
+
}
|
|
230
|
+
return clients[network];
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return {
|
|
234
|
+
getAddresses: () => [address],
|
|
235
|
+
|
|
236
|
+
signTransaction: async (txn: Uint8Array, _senderAddress: string) => {
|
|
237
|
+
const decoded = algosdk.decodeUnsignedTransaction(txn);
|
|
238
|
+
return algosdk.signTransaction(decoded, secretKey).blob;
|
|
239
|
+
},
|
|
240
|
+
|
|
241
|
+
getAlgodClient: (network: Network) => getClient(network),
|
|
242
|
+
|
|
243
|
+
simulateTransactions: async (txns: Uint8Array[], network: Network) => {
|
|
244
|
+
const client = getClient(network);
|
|
245
|
+
const signedTxns = txns.map((txnBytes) => {
|
|
246
|
+
try {
|
|
247
|
+
return algosdk.decodeSignedTransaction(txnBytes);
|
|
248
|
+
} catch {
|
|
249
|
+
const txn = algosdk.decodeUnsignedTransaction(txnBytes);
|
|
250
|
+
return new algosdk.SignedTransaction({ txn });
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
const request = new algosdk.modelsv2.SimulateRequest({
|
|
254
|
+
txnGroups: [
|
|
255
|
+
new algosdk.modelsv2.SimulateRequestTransactionGroup({ txns: signedTxns }),
|
|
256
|
+
],
|
|
257
|
+
allowEmptySignatures: true,
|
|
258
|
+
});
|
|
259
|
+
return client.simulateTransactions(request).do();
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
sendTransactions: async (signedTxns: Uint8Array[], network: Network) => {
|
|
263
|
+
const client = getClient(network);
|
|
264
|
+
const combined = Buffer.concat(signedTxns.map((t) => Buffer.from(t)));
|
|
265
|
+
const { txId } = await client.sendRawTransaction(combined).do();
|
|
266
|
+
return txId;
|
|
267
|
+
},
|
|
268
|
+
|
|
269
|
+
waitForConfirmation: async (txId: string, network: Network, waitRounds = 4) => {
|
|
270
|
+
const client = getClient(network);
|
|
271
|
+
return algosdk.waitForConfirmation(client, txId, waitRounds);
|
|
272
|
+
},
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const facilitatorSigner = createFacilitatorSigner(process.env.AVM_PRIVATE_KEY!);
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## Client Registration
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
import { x402Client } from "@x402-avm/core/client";
|
|
283
|
+
import { registerExactAvmScheme } from "@x402-avm/avm/exact/client";
|
|
284
|
+
|
|
285
|
+
const client = new x402Client({ schemes: [] });
|
|
286
|
+
|
|
287
|
+
registerExactAvmScheme(client, {
|
|
288
|
+
signer: myClientSigner,
|
|
289
|
+
algodConfig: {
|
|
290
|
+
algodUrl: "https://testnet-api.algonode.cloud",
|
|
291
|
+
},
|
|
292
|
+
networks: ["algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="],
|
|
293
|
+
policies: [preferTestnetPolicy],
|
|
294
|
+
});
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## Server Registration
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
import { x402ResourceServer } from "@x402-avm/core/server";
|
|
301
|
+
import { registerExactAvmScheme } from "@x402-avm/avm/exact/server";
|
|
302
|
+
|
|
303
|
+
const server = new x402ResourceServer(facilitatorClient);
|
|
304
|
+
|
|
305
|
+
// Wildcard (default -- all Algorand networks)
|
|
306
|
+
registerExactAvmScheme(server);
|
|
307
|
+
|
|
308
|
+
// Or specific networks
|
|
309
|
+
registerExactAvmScheme(server, {
|
|
310
|
+
networks: ["algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="],
|
|
311
|
+
});
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Facilitator Registration
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
import { x402Facilitator } from "@x402-avm/core/facilitator";
|
|
318
|
+
import { registerExactAvmScheme } from "@x402-avm/avm/exact/facilitator";
|
|
319
|
+
import { ALGORAND_TESTNET_CAIP2, ALGORAND_MAINNET_CAIP2 } from "@x402-avm/avm";
|
|
320
|
+
|
|
321
|
+
const facilitator = new x402Facilitator();
|
|
322
|
+
|
|
323
|
+
// Single network
|
|
324
|
+
registerExactAvmScheme(facilitator, {
|
|
325
|
+
signer: myFacilitatorSigner,
|
|
326
|
+
networks: ALGORAND_TESTNET_CAIP2,
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
// Multiple networks
|
|
330
|
+
registerExactAvmScheme(facilitator, {
|
|
331
|
+
signer: myFacilitatorSigner,
|
|
332
|
+
networks: [ALGORAND_TESTNET_CAIP2, ALGORAND_MAINNET_CAIP2],
|
|
333
|
+
});
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## Payment Policies
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
import { x402Client, PaymentPolicy } from "@x402-avm/core/client";
|
|
340
|
+
import { registerExactAvmScheme } from "@x402-avm/avm/exact/client";
|
|
341
|
+
import { ALGORAND_TESTNET_CAIP2 } from "@x402-avm/avm";
|
|
342
|
+
|
|
343
|
+
const preferTestnet: PaymentPolicy = (version, requirements) => {
|
|
344
|
+
return requirements.filter(r => r.network === ALGORAND_TESTNET_CAIP2);
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
const maxAmount: PaymentPolicy = (version, requirements) => {
|
|
348
|
+
const MAX_USDC = 5_000_000;
|
|
349
|
+
return requirements.filter(r => parseInt(r.maxAmountRequired, 10) <= MAX_USDC);
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
const preferAlgorand: PaymentPolicy = (version, requirements) => {
|
|
353
|
+
const algorandOptions = requirements.filter(r => r.network.startsWith("algorand:"));
|
|
354
|
+
return algorandOptions.length > 0 ? algorandOptions : requirements;
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
const client = new x402Client({ schemes: [] });
|
|
358
|
+
registerExactAvmScheme(client, {
|
|
359
|
+
signer,
|
|
360
|
+
policies: [preferTestnet, maxAmount],
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
client.registerPolicy(preferAlgorand);
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
## Constants
|
|
367
|
+
|
|
368
|
+
```typescript
|
|
369
|
+
import {
|
|
370
|
+
ALGORAND_MAINNET_CAIP2,
|
|
371
|
+
ALGORAND_TESTNET_CAIP2,
|
|
372
|
+
CAIP2_NETWORKS,
|
|
373
|
+
ALGORAND_MAINNET_GENESIS_HASH,
|
|
374
|
+
ALGORAND_TESTNET_GENESIS_HASH,
|
|
375
|
+
USDC_MAINNET_ASA_ID,
|
|
376
|
+
USDC_TESTNET_ASA_ID,
|
|
377
|
+
USDC_DECIMALS,
|
|
378
|
+
USDC_CONFIG,
|
|
379
|
+
DEFAULT_ALGOD_MAINNET,
|
|
380
|
+
DEFAULT_ALGOD_TESTNET,
|
|
381
|
+
MAX_ATOMIC_GROUP_SIZE,
|
|
382
|
+
MIN_TXN_FEE,
|
|
383
|
+
MAX_REASONABLE_FEE,
|
|
384
|
+
ALGORAND_ADDRESS_REGEX,
|
|
385
|
+
ALGORAND_ADDRESS_LENGTH,
|
|
386
|
+
} from "@x402-avm/avm";
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
## Utility Functions
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
import {
|
|
393
|
+
isValidAlgorandAddress,
|
|
394
|
+
convertToTokenAmount,
|
|
395
|
+
convertFromTokenAmount,
|
|
396
|
+
encodeTransaction,
|
|
397
|
+
decodeTransaction,
|
|
398
|
+
decodeSignedTransaction,
|
|
399
|
+
decodeUnsignedTransaction,
|
|
400
|
+
getNetworkFromCaip2,
|
|
401
|
+
isAlgorandNetwork,
|
|
402
|
+
isTestnetNetwork,
|
|
403
|
+
v1ToCaip2,
|
|
404
|
+
caip2ToV1,
|
|
405
|
+
createAlgodClient,
|
|
406
|
+
getSenderFromTransaction,
|
|
407
|
+
getTransactionId,
|
|
408
|
+
hasSignature,
|
|
409
|
+
validateGroupId,
|
|
410
|
+
assignGroupId,
|
|
411
|
+
} from "@x402-avm/avm";
|
|
412
|
+
|
|
413
|
+
// Address validation
|
|
414
|
+
isValidAlgorandAddress("AAAA...AAAA"); // => true/false
|
|
415
|
+
|
|
416
|
+
// Amount conversion
|
|
417
|
+
convertToTokenAmount("1.50", 6); // => "1500000"
|
|
418
|
+
convertFromTokenAmount("1500000", 6); // => "1.5"
|
|
419
|
+
|
|
420
|
+
// Network checks
|
|
421
|
+
isAlgorandNetwork("algorand:SGO1..."); // => true
|
|
422
|
+
isTestnetNetwork("algorand:SGO1..."); // => true
|
|
423
|
+
getNetworkFromCaip2("algorand:SGO1..."); // => "testnet"
|
|
424
|
+
|
|
425
|
+
// Algod client
|
|
426
|
+
const algod = createAlgodClient("algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=");
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
## HTTPFacilitatorClient
|
|
430
|
+
|
|
431
|
+
```typescript
|
|
432
|
+
import { HTTPFacilitatorClient } from "@x402-avm/core/server";
|
|
433
|
+
|
|
434
|
+
const facilitatorClient = new HTTPFacilitatorClient({
|
|
435
|
+
url: "https://facilitator.goplausible.xyz",
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
const authenticatedClient = new HTTPFacilitatorClient({
|
|
439
|
+
url: "https://facilitator.example.com",
|
|
440
|
+
headers: {
|
|
441
|
+
Authorization: `Bearer ${process.env.FACILITATOR_API_KEY}`,
|
|
442
|
+
},
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
const supported = await facilitatorClient.supported();
|
|
446
|
+
const verifyResult = await facilitatorClient.verify({ paymentPayload, paymentRequirements });
|
|
447
|
+
const settleResult = await facilitatorClient.settle({ paymentPayload, paymentRequirements });
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
## Type Guard
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
import { isAvmSignerWallet } from "@x402-avm/avm";
|
|
454
|
+
|
|
455
|
+
function checkWallet(wallet: unknown) {
|
|
456
|
+
if (isAvmSignerWallet(wallet)) {
|
|
457
|
+
console.log("Address:", wallet.address);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
## Transaction Group Creation (Simple Payment)
|
|
463
|
+
|
|
464
|
+
```typescript
|
|
465
|
+
import algosdk from "algosdk";
|
|
466
|
+
import { ALGORAND_TESTNET_CAIP2, USDC_TESTNET_ASA_ID, createAlgodClient } from "@x402-avm/avm";
|
|
467
|
+
|
|
468
|
+
async function createSimplePayment(senderAddress: string, receiverAddress: string, amount: number) {
|
|
469
|
+
const algod = createAlgodClient(ALGORAND_TESTNET_CAIP2);
|
|
470
|
+
const params = await algod.getTransactionParams().do();
|
|
471
|
+
|
|
472
|
+
const txn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({
|
|
473
|
+
from: senderAddress,
|
|
474
|
+
to: receiverAddress,
|
|
475
|
+
amount,
|
|
476
|
+
assetIndex: parseInt(USDC_TESTNET_ASA_ID, 10),
|
|
477
|
+
suggestedParams: params,
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
return [txn.toByte()];
|
|
481
|
+
}
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
## Fee-Abstracted Payment Group
|
|
485
|
+
|
|
486
|
+
```typescript
|
|
487
|
+
import algosdk from "algosdk";
|
|
488
|
+
import {
|
|
489
|
+
ALGORAND_TESTNET_CAIP2,
|
|
490
|
+
USDC_TESTNET_ASA_ID,
|
|
491
|
+
MIN_TXN_FEE,
|
|
492
|
+
createAlgodClient,
|
|
493
|
+
encodeTransaction,
|
|
494
|
+
} from "@x402-avm/avm";
|
|
495
|
+
|
|
496
|
+
async function createFeeAbstractedPayment(
|
|
497
|
+
senderAddress: string,
|
|
498
|
+
receiverAddress: string,
|
|
499
|
+
feePayerAddress: string,
|
|
500
|
+
amount: number,
|
|
501
|
+
) {
|
|
502
|
+
const algod = createAlgodClient(ALGORAND_TESTNET_CAIP2);
|
|
503
|
+
const params = await algod.getTransactionParams().do();
|
|
504
|
+
|
|
505
|
+
const paymentTxn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({
|
|
506
|
+
from: senderAddress,
|
|
507
|
+
to: receiverAddress,
|
|
508
|
+
amount,
|
|
509
|
+
assetIndex: parseInt(USDC_TESTNET_ASA_ID, 10),
|
|
510
|
+
suggestedParams: { ...params, fee: 0, flatFee: true },
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
const feePayerTxn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
|
|
514
|
+
from: feePayerAddress,
|
|
515
|
+
to: feePayerAddress,
|
|
516
|
+
amount: 0,
|
|
517
|
+
suggestedParams: { ...params, fee: MIN_TXN_FEE * 2, flatFee: true },
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
const grouped = algosdk.assignGroupID([paymentTxn, feePayerTxn]);
|
|
521
|
+
|
|
522
|
+
return {
|
|
523
|
+
paymentGroup: [
|
|
524
|
+
encodeTransaction(grouped[0].toByte()),
|
|
525
|
+
encodeTransaction(grouped[1].toByte()),
|
|
526
|
+
],
|
|
527
|
+
paymentIndex: 0,
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
## Complete End-to-End (Client + Server + Facilitator)
|
|
533
|
+
|
|
534
|
+
```typescript
|
|
535
|
+
// ---- shared/config.ts ----
|
|
536
|
+
import { ALGORAND_TESTNET_CAIP2, USDC_TESTNET_ASA_ID } from "@x402-avm/avm";
|
|
537
|
+
|
|
538
|
+
export const NETWORK = ALGORAND_TESTNET_CAIP2;
|
|
539
|
+
export const USDC_ASA = USDC_TESTNET_ASA_ID;
|
|
540
|
+
export const RESOURCE_WALLET = "RECEIVER_ALGORAND_ADDRESS_58_CHARS";
|
|
541
|
+
export const FACILITATOR_URL = "http://localhost:4020";
|
|
542
|
+
export const RESOURCE_SERVER_URL = "http://localhost:4021";
|
|
543
|
+
|
|
544
|
+
// ---- server/index.ts ----
|
|
545
|
+
import express from "express";
|
|
546
|
+
import { paymentMiddleware, x402ResourceServer } from "@x402-avm/express";
|
|
547
|
+
import { registerExactAvmScheme } from "@x402-avm/avm/exact/server";
|
|
548
|
+
import { HTTPFacilitatorClient } from "@x402-avm/core/server";
|
|
549
|
+
import { NETWORK, USDC_ASA, RESOURCE_WALLET, FACILITATOR_URL } from "../shared/config";
|
|
550
|
+
|
|
551
|
+
const facilitatorClient = new HTTPFacilitatorClient({ url: FACILITATOR_URL });
|
|
552
|
+
const server = new x402ResourceServer(facilitatorClient);
|
|
553
|
+
registerExactAvmScheme(server);
|
|
554
|
+
|
|
555
|
+
const routes = {
|
|
556
|
+
"GET /api/weather": {
|
|
557
|
+
accepts: {
|
|
558
|
+
scheme: "exact",
|
|
559
|
+
network: NETWORK,
|
|
560
|
+
payTo: RESOURCE_WALLET,
|
|
561
|
+
price: "$0.01",
|
|
562
|
+
},
|
|
563
|
+
description: "Weather data",
|
|
564
|
+
},
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
const app = express();
|
|
568
|
+
app.use(paymentMiddleware(routes, server));
|
|
569
|
+
app.get("/api/weather", (req, res) => res.json({ temperature: 72, condition: "Sunny" }));
|
|
570
|
+
app.listen(4021);
|
|
571
|
+
|
|
572
|
+
// ---- client/index.ts ----
|
|
573
|
+
import { x402Client } from "@x402-avm/core/client";
|
|
574
|
+
import { registerExactAvmScheme } from "@x402-avm/avm/exact/client";
|
|
575
|
+
import type { ClientAvmSigner } from "@x402-avm/avm";
|
|
576
|
+
import algosdk from "algosdk";
|
|
577
|
+
import { RESOURCE_SERVER_URL } from "../shared/config";
|
|
578
|
+
|
|
579
|
+
const secretKey = Buffer.from(process.env.AVM_PRIVATE_KEY!, "base64");
|
|
580
|
+
const clientSigner: ClientAvmSigner = {
|
|
581
|
+
address: algosdk.encodeAddress(secretKey.slice(32)),
|
|
582
|
+
signTransactions: async (txns, indexesToSign) => {
|
|
583
|
+
return txns.map((txn, i) => {
|
|
584
|
+
if (indexesToSign && !indexesToSign.includes(i)) return null;
|
|
585
|
+
return algosdk.signTransaction(algosdk.decodeUnsignedTransaction(txn), secretKey).blob;
|
|
586
|
+
});
|
|
587
|
+
},
|
|
588
|
+
};
|
|
589
|
+
|
|
590
|
+
const client = new x402Client({ schemes: [] });
|
|
591
|
+
registerExactAvmScheme(client, { signer: clientSigner });
|
|
592
|
+
|
|
593
|
+
const response = await client.fetch(`${RESOURCE_SERVER_URL}/api/weather`);
|
|
594
|
+
if (response.ok) {
|
|
595
|
+
console.log("Weather:", await response.json());
|
|
596
|
+
}
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
## Component Import Summary
|
|
600
|
+
|
|
601
|
+
```typescript
|
|
602
|
+
// Core
|
|
603
|
+
import { x402Client } from "@x402-avm/core/client";
|
|
604
|
+
import { x402ResourceServer, x402HTTPResourceServer, HTTPFacilitatorClient } from "@x402-avm/core/server";
|
|
605
|
+
import { x402Facilitator } from "@x402-avm/core/facilitator";
|
|
606
|
+
import type { PaymentRequirements, PaymentPayload, PaymentRequired, Network } from "@x402-avm/core/types";
|
|
607
|
+
|
|
608
|
+
// AVM Registration (different subpath per role)
|
|
609
|
+
import { registerExactAvmScheme } from "@x402-avm/avm/exact/client";
|
|
610
|
+
import { registerExactAvmScheme } from "@x402-avm/avm/exact/server";
|
|
611
|
+
import { registerExactAvmScheme } from "@x402-avm/avm/exact/facilitator";
|
|
612
|
+
|
|
613
|
+
// AVM Types and Constants
|
|
614
|
+
import type { ClientAvmSigner, FacilitatorAvmSigner } from "@x402-avm/avm";
|
|
615
|
+
import { ALGORAND_TESTNET_CAIP2, USDC_TESTNET_ASA_ID } from "@x402-avm/avm";
|
|
616
|
+
```
|