@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
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
# x402-avm Server Reference
|
|
2
|
+
|
|
3
|
+
## @x402-avm/express Package
|
|
4
|
+
|
|
5
|
+
### Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @x402-avm/express @x402-avm/avm @x402-avm/core express
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
With paywall:
|
|
12
|
+
```bash
|
|
13
|
+
npm install @x402-avm/express @x402-avm/avm @x402-avm/core @x402-avm/paywall express
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### Middleware Functions
|
|
17
|
+
|
|
18
|
+
#### paymentMiddlewareFromConfig
|
|
19
|
+
|
|
20
|
+
The simplest middleware variant. Creates and configures the x402ResourceServer internally.
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
function paymentMiddlewareFromConfig(
|
|
24
|
+
routes: RoutesConfig | RouteConfig,
|
|
25
|
+
facilitatorClient: HTTPFacilitatorClient,
|
|
26
|
+
schemes?: SchemeConfig[],
|
|
27
|
+
paywallConfig?: PaywallConfig,
|
|
28
|
+
paywall?: PaywallProvider,
|
|
29
|
+
): RequestHandler
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
| Parameter | Type | Required | Description |
|
|
33
|
+
|-----------|------|----------|-------------|
|
|
34
|
+
| `routes` | `RoutesConfig \| RouteConfig` | Yes | Route payment configuration |
|
|
35
|
+
| `facilitatorClient` | `HTTPFacilitatorClient` | Yes | Client to communicate with facilitator |
|
|
36
|
+
| `schemes` | `SchemeConfig[]` | No | Scheme configurations for network matching |
|
|
37
|
+
| `paywallConfig` | `PaywallConfig` | No | Paywall UI configuration |
|
|
38
|
+
| `paywall` | `PaywallProvider` | No | Custom paywall provider |
|
|
39
|
+
|
|
40
|
+
#### paymentMiddleware
|
|
41
|
+
|
|
42
|
+
Uses a pre-configured x402ResourceServer instance. Choose this when you need to register multiple schemes or reuse the server.
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
function paymentMiddleware(
|
|
46
|
+
routes: RoutesConfig | RouteConfig,
|
|
47
|
+
server: x402ResourceServer,
|
|
48
|
+
paywallConfig?: PaywallConfig,
|
|
49
|
+
paywall?: PaywallProvider,
|
|
50
|
+
): RequestHandler
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
| Parameter | Type | Required | Description |
|
|
54
|
+
|-----------|------|----------|-------------|
|
|
55
|
+
| `routes` | `RoutesConfig \| RouteConfig` | Yes | Route payment configuration |
|
|
56
|
+
| `server` | `x402ResourceServer` | Yes | Pre-configured resource server |
|
|
57
|
+
| `paywallConfig` | `PaywallConfig` | No | Paywall UI configuration |
|
|
58
|
+
| `paywall` | `PaywallProvider` | No | Custom paywall provider |
|
|
59
|
+
|
|
60
|
+
#### paymentMiddlewareFromHTTPServer
|
|
61
|
+
|
|
62
|
+
The most advanced variant. Uses x402HTTPResourceServer with hooks for custom access control.
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
function paymentMiddlewareFromHTTPServer(
|
|
66
|
+
httpServer: x402HTTPResourceServer,
|
|
67
|
+
): RequestHandler
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
| Parameter | Type | Required | Description |
|
|
71
|
+
|-----------|------|----------|-------------|
|
|
72
|
+
| `httpServer` | `x402HTTPResourceServer` | Yes | HTTP server with hooks configured |
|
|
73
|
+
|
|
74
|
+
## @x402-avm/hono Package
|
|
75
|
+
|
|
76
|
+
### Installation
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
npm install @x402-avm/hono @x402-avm/avm @x402-avm/core hono
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Node.js server:
|
|
83
|
+
```bash
|
|
84
|
+
npm install @x402-avm/hono @x402-avm/avm @x402-avm/core hono @hono/node-server
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Middleware Functions
|
|
88
|
+
|
|
89
|
+
The Hono package exports the same three middleware variants as Express, returning Hono `MiddlewareHandler` instead of Express `RequestHandler`.
|
|
90
|
+
|
|
91
|
+
#### paymentMiddlewareFromConfig
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
function paymentMiddlewareFromConfig(
|
|
95
|
+
routes: RoutesConfig | RouteConfig,
|
|
96
|
+
facilitatorClient: HTTPFacilitatorClient,
|
|
97
|
+
schemes?: SchemeConfig[],
|
|
98
|
+
paywallConfig?: PaywallConfig,
|
|
99
|
+
paywall?: PaywallProvider,
|
|
100
|
+
syncFacilitatorOnStart?: boolean, // default: true; set false for serverless
|
|
101
|
+
): MiddlewareHandler
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The `syncFacilitatorOnStart` parameter is unique to Hono. Set it to `false` for Cloudflare Workers and other serverless environments to avoid cold-start delays.
|
|
105
|
+
|
|
106
|
+
#### paymentMiddleware
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
function paymentMiddleware(
|
|
110
|
+
routes: RoutesConfig | RouteConfig,
|
|
111
|
+
server: x402ResourceServer,
|
|
112
|
+
paywallConfig?: PaywallConfig,
|
|
113
|
+
paywall?: PaywallProvider,
|
|
114
|
+
): MiddlewareHandler
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### paymentMiddlewareFromHTTPServer
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
function paymentMiddlewareFromHTTPServer(
|
|
121
|
+
httpServer: x402HTTPResourceServer,
|
|
122
|
+
): MiddlewareHandler
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Route Configuration
|
|
126
|
+
|
|
127
|
+
### RoutesConfig Type
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
type RoutesConfig = Record<string, RouteConfig>;
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Keys are route patterns in the format `"METHOD /path"` or just `"/path"` (matches all methods).
|
|
134
|
+
|
|
135
|
+
**Pattern syntax:**
|
|
136
|
+
- `"GET /api/weather"` -- exact match, GET only
|
|
137
|
+
- `"POST /api/generate"` -- exact match, POST only
|
|
138
|
+
- `"GET /api/premium/*"` -- wildcard, matches all sub-paths
|
|
139
|
+
- `"/api/resource"` -- matches all HTTP methods
|
|
140
|
+
- `"GET /api/lookup/:id"` -- path parameters (Express/Hono style)
|
|
141
|
+
|
|
142
|
+
### RouteConfig Type
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
interface RouteConfig {
|
|
146
|
+
accepts: PaymentOption | PaymentOption[];
|
|
147
|
+
resource?: string;
|
|
148
|
+
description?: string;
|
|
149
|
+
mimeType?: string;
|
|
150
|
+
customPaywallHtml?: string;
|
|
151
|
+
unpaidResponseBody?: (context: RequestContext) => {
|
|
152
|
+
contentType: string;
|
|
153
|
+
body: any;
|
|
154
|
+
};
|
|
155
|
+
extensions?: Record<string, unknown>;
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
| Field | Type | Required | Description |
|
|
160
|
+
|-------|------|----------|-------------|
|
|
161
|
+
| `accepts` | `PaymentOption \| PaymentOption[]` | Yes | Payment configuration(s) |
|
|
162
|
+
| `resource` | `string` | No | Resource identifier URL |
|
|
163
|
+
| `description` | `string` | No | Human-readable description |
|
|
164
|
+
| `mimeType` | `string` | No | Response MIME type (use `"text/html"` for paywall) |
|
|
165
|
+
| `customPaywallHtml` | `string` | No | Custom HTML for browser paywall |
|
|
166
|
+
| `unpaidResponseBody` | `Function` | No | Preview content for unpaid API requests |
|
|
167
|
+
| `extensions` | `Record<string, unknown>` | No | Protocol extensions (e.g., bazaar) |
|
|
168
|
+
|
|
169
|
+
### PaymentOption Type
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
interface PaymentOption {
|
|
173
|
+
scheme: string;
|
|
174
|
+
payTo: string;
|
|
175
|
+
price: Price | DynamicPrice;
|
|
176
|
+
network: string;
|
|
177
|
+
maxTimeoutSeconds?: number;
|
|
178
|
+
extra?: Record<string, unknown>;
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
| Field | Type | Required | Description |
|
|
183
|
+
|-------|------|----------|-------------|
|
|
184
|
+
| `scheme` | `string` | Yes | Payment scheme (`"exact"`) |
|
|
185
|
+
| `payTo` | `string` | Yes | Algorand address to receive payment (58 chars) |
|
|
186
|
+
| `price` | `Price \| DynamicPrice` | Yes | USD price string (`"$0.01"`) or dynamic function |
|
|
187
|
+
| `network` | `string` | Yes | CAIP-2 network identifier |
|
|
188
|
+
| `maxTimeoutSeconds` | `number` | No | Payment validity window (default: 60) |
|
|
189
|
+
| `extra` | `Record<string, unknown>` | No | AVM-specific: `feePayer`, `asset`, `decimals` |
|
|
190
|
+
|
|
191
|
+
### DynamicPrice Type
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
type DynamicPrice = (context: RequestContext) => Price;
|
|
195
|
+
type Price = string; // e.g., "$0.01"
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Core Server Classes
|
|
199
|
+
|
|
200
|
+
### HTTPFacilitatorClient
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
import { HTTPFacilitatorClient } from "@x402-avm/core/server";
|
|
204
|
+
|
|
205
|
+
const client = new HTTPFacilitatorClient({
|
|
206
|
+
url?: string; // Facilitator URL (default: "https://x402.org/facilitator")
|
|
207
|
+
headers?: Record<string, string>; // Custom headers (e.g., auth)
|
|
208
|
+
});
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**Methods:**
|
|
212
|
+
|
|
213
|
+
| Method | Returns | Description |
|
|
214
|
+
|--------|---------|-------------|
|
|
215
|
+
| `supported()` | `Promise<SupportedResponse>` | Get supported networks and schemes |
|
|
216
|
+
| `verify({ paymentPayload, paymentRequirements })` | `Promise<VerifyResponse>` | Verify a payment |
|
|
217
|
+
| `settle({ paymentPayload, paymentRequirements })` | `Promise<SettleResponse>` | Settle a payment |
|
|
218
|
+
|
|
219
|
+
### x402ResourceServer
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
import { x402ResourceServer } from "@x402-avm/core/server";
|
|
223
|
+
|
|
224
|
+
const server = new x402ResourceServer(facilitatorClient);
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Must register AVM scheme after creation:
|
|
228
|
+
```typescript
|
|
229
|
+
import { registerExactAvmScheme } from "@x402-avm/avm/exact/server";
|
|
230
|
+
registerExactAvmScheme(server);
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### x402HTTPResourceServer
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
import { x402HTTPResourceServer } from "@x402-avm/core/server";
|
|
237
|
+
|
|
238
|
+
const httpServer = new x402HTTPResourceServer(resourceServer, routes);
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**Hooks:**
|
|
242
|
+
|
|
243
|
+
| Hook | Signature | Description |
|
|
244
|
+
|------|-----------|-------------|
|
|
245
|
+
| `onProtectedRequest` | `(context, routeConfig) => Promise<{ grantAccess: true } \| { abort: true, reason: string } \| undefined>` | Intercept before payment check |
|
|
246
|
+
|
|
247
|
+
Return `{ grantAccess: true }` to bypass payment (e.g., API key), `{ abort: true, reason }` to reject, or `undefined` to continue to payment flow.
|
|
248
|
+
|
|
249
|
+
## CAIP-2 Network Constants
|
|
250
|
+
|
|
251
|
+
| Constant | Value | Import |
|
|
252
|
+
|----------|-------|--------|
|
|
253
|
+
| `ALGORAND_TESTNET_CAIP2` | `"algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="` | `@x402-avm/avm` |
|
|
254
|
+
| `ALGORAND_MAINNET_CAIP2` | `"algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8="` | `@x402-avm/avm` |
|
|
255
|
+
|
|
256
|
+
## USDC ASA Constants
|
|
257
|
+
|
|
258
|
+
| Constant | Value | Import |
|
|
259
|
+
|----------|-------|--------|
|
|
260
|
+
| `USDC_TESTNET_ASA_ID` | `"10458941"` | `@x402-avm/avm` |
|
|
261
|
+
| `USDC_MAINNET_ASA_ID` | `"31566704"` | `@x402-avm/avm` |
|
|
262
|
+
| `USDC_DECIMALS` | `6` | `@x402-avm/avm` |
|
|
263
|
+
|
|
264
|
+
## Paywall Configuration
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
interface PaywallConfig {
|
|
268
|
+
title?: string;
|
|
269
|
+
description?: string;
|
|
270
|
+
logoUrl?: string;
|
|
271
|
+
theme?: {
|
|
272
|
+
primaryColor?: string;
|
|
273
|
+
backgroundColor?: string;
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Custom PaywallProvider
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
interface PaywallProvider {
|
|
282
|
+
generatePaywall(
|
|
283
|
+
paymentRequirements: PaymentRequirements,
|
|
284
|
+
routeConfig: RouteConfig,
|
|
285
|
+
paywallConfig?: PaywallConfig,
|
|
286
|
+
): string; // Returns HTML string
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Environment Variables
|
|
291
|
+
|
|
292
|
+
### Resource Server
|
|
293
|
+
|
|
294
|
+
| Variable | Required | Description | Default |
|
|
295
|
+
|----------|----------|-------------|---------|
|
|
296
|
+
| `AVM_ADDRESS` / `RESOURCE_PAY_TO` | Yes | Algorand address receiving payments | -- |
|
|
297
|
+
| `FACILITATOR_URL` | Yes | URL of facilitator server | -- |
|
|
298
|
+
| `PORT` | No | Server port | `4021` |
|
|
299
|
+
|
|
300
|
+
### Facilitator Server
|
|
301
|
+
|
|
302
|
+
| Variable | Required | Description | Default |
|
|
303
|
+
|----------|----------|-------------|---------|
|
|
304
|
+
| `AVM_PRIVATE_KEY` | Yes | Base64-encoded 64-byte key | -- |
|
|
305
|
+
| `ALGOD_SERVER` | No | Algorand node URL | `https://testnet-api.algonode.cloud` |
|
|
306
|
+
| `ALGOD_TOKEN` | No | Algorand node API token | `""` |
|
|
307
|
+
| `FACILITATOR_PORT` / `PORT` | No | Server port | `4020` |
|
|
308
|
+
|
|
309
|
+
## Facilitator HTTP Endpoints
|
|
310
|
+
|
|
311
|
+
A facilitator server exposes three endpoints:
|
|
312
|
+
|
|
313
|
+
| Endpoint | Method | Body | Response |
|
|
314
|
+
|----------|--------|------|----------|
|
|
315
|
+
| `/verify` | POST | `{ paymentPayload, paymentRequirements }` | `{ isValid, invalidReason? }` |
|
|
316
|
+
| `/settle` | POST | `{ paymentPayload, paymentRequirements }` | `{ success, transaction?, network?, error? }` |
|
|
317
|
+
| `/supported` | GET | -- | `{ networks, schemes }` |
|
|
318
|
+
|
|
319
|
+
## Fee Abstraction
|
|
320
|
+
|
|
321
|
+
Fee abstraction is configured through the `extra.feePayer` field in route configuration:
|
|
322
|
+
|
|
323
|
+
```typescript
|
|
324
|
+
extra: {
|
|
325
|
+
feePayer: "FACILITATOR_FEE_PAYER_ADDRESS",
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
When a client sees `feePayer` in the payment requirements, it creates a 2-transaction atomic group:
|
|
330
|
+
1. **Payment transaction** (signed by client): ASA transfer to `payTo`, fee=0
|
|
331
|
+
2. **Fee transaction** (unsigned, for facilitator): self-payment, fee covers both transactions
|
|
332
|
+
|
|
333
|
+
The facilitator signs the fee transaction during settlement.
|
|
334
|
+
|
|
335
|
+
## Deployment Patterns
|
|
336
|
+
|
|
337
|
+
### Express (Node.js)
|
|
338
|
+
|
|
339
|
+
Standard `app.listen()` on a port. Suitable for Docker, VMs, or managed Node.js hosting.
|
|
340
|
+
|
|
341
|
+
### Hono (Node.js)
|
|
342
|
+
|
|
343
|
+
Use `@hono/node-server` with `serve()`. Same deployment as Express.
|
|
344
|
+
|
|
345
|
+
### Hono (Cloudflare Workers)
|
|
346
|
+
|
|
347
|
+
Export the Hono app as default export. Set `syncFacilitatorOnStart: false` to avoid cold-start delays. Use `wrangler.toml` for environment variables.
|
|
348
|
+
|
|
349
|
+
### Hono (Bun)
|
|
350
|
+
|
|
351
|
+
Export `{ port, fetch: app.fetch }` as default export.
|
|
352
|
+
|
|
353
|
+
### Hono (Deno)
|
|
354
|
+
|
|
355
|
+
Use `Deno.serve({ port }, app.fetch)`.
|
|
356
|
+
|
|
357
|
+
## Testing
|
|
358
|
+
|
|
359
|
+
### Manual Test Flow
|
|
360
|
+
|
|
361
|
+
1. Start facilitator: `PORT=4020 AVM_PRIVATE_KEY=... ts-node facilitator.ts`
|
|
362
|
+
2. Start resource server: `PORT=4021 FACILITATOR_URL=http://localhost:4020 AVM_ADDRESS=... ts-node server.ts`
|
|
363
|
+
3. Test public route: `curl http://localhost:4021/api/health` (should return 200)
|
|
364
|
+
4. Test protected route: `curl http://localhost:4021/api/weather` (should return 402)
|
|
365
|
+
5. Run client: `AVM_PRIVATE_KEY=... RESOURCE_SERVER_URL=http://localhost:4021 ts-node client.ts`
|
|
366
|
+
|
|
367
|
+
### Using Online Facilitator
|
|
368
|
+
|
|
369
|
+
Set `FACILITATOR_URL=https://facilitator.goplausible.xyz` to skip running a local facilitator.
|
|
370
|
+
|
|
371
|
+
## External Resources
|
|
372
|
+
|
|
373
|
+
- [@x402-avm/express on npm](https://www.npmjs.com/package/@x402-avm/express)
|
|
374
|
+
- [@x402-avm/hono on npm](https://www.npmjs.com/package/@x402-avm/hono)
|
|
375
|
+
- [@x402-avm/core on npm](https://www.npmjs.com/package/@x402-avm/core)
|
|
376
|
+
- [@x402-avm/avm on npm](https://www.npmjs.com/package/@x402-avm/avm)
|
|
377
|
+
- [@x402-avm/paywall on npm](https://www.npmjs.com/package/@x402-avm/paywall)
|
|
378
|
+
- [GoPlausible x402-avm Examples](https://github.com/GoPlausible/x402-avm/tree/branch-v2-algorand-publish/examples/)
|
|
379
|
+
- [GoPlausible x402-avm Documentation](https://github.com/GoPlausible/.github/blob/main/profile/algorand-x402-documentation/)
|
|
380
|
+
- [Express.js Documentation](https://expressjs.com/)
|
|
381
|
+
- [Hono Documentation](https://hono.dev/)
|
|
382
|
+
- [Cloudflare Workers Documentation](https://developers.cloudflare.com/workers/)
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# Creating x402 Payment-Protected Servers
|
|
2
|
+
|
|
3
|
+
Build TypeScript servers that gate API endpoints behind Algorand (AVM) payments using Express.js or Hono middleware.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
Before creating a payment-protected server:
|
|
8
|
+
|
|
9
|
+
1. **Node.js 18+** installed
|
|
10
|
+
2. **An Algorand address** to receive payments (58-character address)
|
|
11
|
+
3. **A facilitator** -- either run your own or use `https://facilitator.goplausible.xyz`
|
|
12
|
+
4. **TypeScript project** initialized with `tsconfig.json`
|
|
13
|
+
|
|
14
|
+
## Core Workflow: Middleware-Based Payment Gating
|
|
15
|
+
|
|
16
|
+
The server middleware intercepts requests to protected routes, checks for a valid `PAYMENT-SIGNATURE` header, and either returns 402 (pay first) or passes through to the route handler (payment verified).
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
Request → Middleware checks PAYMENT-SIGNATURE header
|
|
20
|
+
├── No header → Return 402 with PaymentRequirements
|
|
21
|
+
├── Has header → Forward to facilitator
|
|
22
|
+
│ ├── verify() fails → Return 402
|
|
23
|
+
│ └── verify() passes → settle() → Pass to route handler
|
|
24
|
+
└── Route not protected → Pass through
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## How to Proceed
|
|
28
|
+
|
|
29
|
+
### Step 1: Install Dependencies
|
|
30
|
+
|
|
31
|
+
**Express.js:**
|
|
32
|
+
```bash
|
|
33
|
+
npm install @x402-avm/express @x402-avm/avm @x402-avm/core express
|
|
34
|
+
npm install -D @types/express typescript
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Hono:**
|
|
38
|
+
```bash
|
|
39
|
+
npm install @x402-avm/hono @x402-avm/avm @x402-avm/core hono
|
|
40
|
+
npm install -D typescript
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Hono with Node.js server:**
|
|
44
|
+
```bash
|
|
45
|
+
npm install @x402-avm/hono @x402-avm/avm @x402-avm/core hono @hono/node-server
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**With paywall UI (optional):**
|
|
49
|
+
```bash
|
|
50
|
+
npm install @x402-avm/paywall
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Step 2: Choose a Middleware Variant
|
|
54
|
+
|
|
55
|
+
There are three middleware variants, from simplest to most configurable:
|
|
56
|
+
|
|
57
|
+
| Variant | Use Case | What It Creates |
|
|
58
|
+
|---------|----------|-----------------|
|
|
59
|
+
| `paymentMiddlewareFromConfig` | Quick start, simple apps | Creates x402ResourceServer internally |
|
|
60
|
+
| `paymentMiddleware` | Need custom server config | Uses your x402ResourceServer instance |
|
|
61
|
+
| `paymentMiddlewareFromHTTPServer` | Need hooks (API key bypass, logging) | Uses x402HTTPResourceServer with hooks |
|
|
62
|
+
|
|
63
|
+
### Step 3: Define Routes
|
|
64
|
+
|
|
65
|
+
Routes map HTTP method + path patterns to payment configuration:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { ALGORAND_TESTNET_CAIP2 } from "@x402-avm/avm";
|
|
69
|
+
|
|
70
|
+
const routes = {
|
|
71
|
+
"GET /api/weather": {
|
|
72
|
+
accepts: {
|
|
73
|
+
scheme: "exact",
|
|
74
|
+
network: ALGORAND_TESTNET_CAIP2,
|
|
75
|
+
payTo: "YOUR_ALGORAND_ADDRESS",
|
|
76
|
+
price: "$0.01",
|
|
77
|
+
},
|
|
78
|
+
description: "Weather data",
|
|
79
|
+
},
|
|
80
|
+
"GET /api/premium/*": {
|
|
81
|
+
accepts: {
|
|
82
|
+
scheme: "exact",
|
|
83
|
+
network: ALGORAND_TESTNET_CAIP2,
|
|
84
|
+
payTo: "YOUR_ALGORAND_ADDRESS",
|
|
85
|
+
price: "$0.10",
|
|
86
|
+
},
|
|
87
|
+
description: "Premium API endpoints",
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Step 4: Apply Middleware (Express)
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import express from "express";
|
|
96
|
+
import { paymentMiddleware, x402ResourceServer } from "@x402-avm/express";
|
|
97
|
+
import { registerExactAvmScheme } from "@x402-avm/avm/exact/server";
|
|
98
|
+
import { HTTPFacilitatorClient } from "@x402-avm/core/server";
|
|
99
|
+
|
|
100
|
+
const app = express();
|
|
101
|
+
|
|
102
|
+
const facilitatorClient = new HTTPFacilitatorClient({
|
|
103
|
+
url: process.env.FACILITATOR_URL || "https://facilitator.goplausible.xyz",
|
|
104
|
+
});
|
|
105
|
+
const server = new x402ResourceServer(facilitatorClient);
|
|
106
|
+
registerExactAvmScheme(server);
|
|
107
|
+
|
|
108
|
+
app.use(paymentMiddleware(routes, server));
|
|
109
|
+
|
|
110
|
+
app.get("/api/weather", (req, res) => {
|
|
111
|
+
res.json({ temperature: 72, condition: "sunny" });
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
app.listen(4021);
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Step 4 (Alternative): Apply Middleware (Hono)
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import { Hono } from "hono";
|
|
121
|
+
import { paymentMiddleware, x402ResourceServer } from "@x402-avm/hono";
|
|
122
|
+
import { registerExactAvmScheme } from "@x402-avm/avm/exact/server";
|
|
123
|
+
import { HTTPFacilitatorClient } from "@x402-avm/core/server";
|
|
124
|
+
|
|
125
|
+
const app = new Hono();
|
|
126
|
+
|
|
127
|
+
const facilitatorClient = new HTTPFacilitatorClient({
|
|
128
|
+
url: process.env.FACILITATOR_URL || "https://facilitator.goplausible.xyz",
|
|
129
|
+
});
|
|
130
|
+
const server = new x402ResourceServer(facilitatorClient);
|
|
131
|
+
registerExactAvmScheme(server);
|
|
132
|
+
|
|
133
|
+
app.use(paymentMiddleware(routes, server));
|
|
134
|
+
|
|
135
|
+
app.get("/api/weather", (c) => {
|
|
136
|
+
return c.json({ temperature: 72, condition: "sunny" });
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
export default app;
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Step 5: Add a Facilitator Server (Optional)
|
|
143
|
+
|
|
144
|
+
If you need your own facilitator instead of the public one:
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
import express from "express";
|
|
148
|
+
import { x402Facilitator } from "@x402-avm/core/facilitator";
|
|
149
|
+
import { registerExactAvmScheme } from "@x402-avm/avm/exact/facilitator";
|
|
150
|
+
import { ALGORAND_TESTNET_CAIP2 } from "@x402-avm/avm";
|
|
151
|
+
import algosdk from "algosdk";
|
|
152
|
+
|
|
153
|
+
const secretKey = Buffer.from(process.env.AVM_PRIVATE_KEY!, "base64");
|
|
154
|
+
const address = algosdk.encodeAddress(secretKey.slice(32));
|
|
155
|
+
const algodClient = new algosdk.Algodv2("", "https://testnet-api.algonode.cloud", "");
|
|
156
|
+
|
|
157
|
+
// Create signer implementing FacilitatorAvmSigner interface
|
|
158
|
+
const signer = { /* ... see EXAMPLES.md for full implementation ... */ };
|
|
159
|
+
|
|
160
|
+
const facilitator = new x402Facilitator();
|
|
161
|
+
registerExactAvmScheme(facilitator, { signer, networks: ALGORAND_TESTNET_CAIP2 });
|
|
162
|
+
|
|
163
|
+
const app = express();
|
|
164
|
+
app.use(express.json());
|
|
165
|
+
app.post("/verify", async (req, res) => { /* ... */ });
|
|
166
|
+
app.post("/settle", async (req, res) => { /* ... */ });
|
|
167
|
+
app.get("/supported", (req, res) => { /* ... */ });
|
|
168
|
+
app.listen(4020);
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Step 6: Set Environment Variables
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
# Resource Server
|
|
175
|
+
AVM_ADDRESS=YOUR_ALGORAND_ADDRESS_HERE
|
|
176
|
+
FACILITATOR_URL=https://facilitator.goplausible.xyz
|
|
177
|
+
PORT=4021
|
|
178
|
+
|
|
179
|
+
# Facilitator (if running your own)
|
|
180
|
+
AVM_PRIVATE_KEY=<base64-encoded-64-byte-key>
|
|
181
|
+
ALGOD_SERVER=https://testnet-api.algonode.cloud
|
|
182
|
+
ALGOD_TOKEN=
|
|
183
|
+
FACILITATOR_PORT=4020
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Important Rules / Guidelines
|
|
187
|
+
|
|
188
|
+
1. **Register AVM scheme unconditionally** -- always call `registerExactAvmScheme(server)` without environment variable guards
|
|
189
|
+
2. **Public routes are unaffected** -- only routes listed in the `routes` config object are protected
|
|
190
|
+
3. **Route patterns support wildcards** -- `"GET /api/premium/*"` matches all sub-paths
|
|
191
|
+
4. **Method prefix is optional** -- `"/api/resource"` matches all HTTP methods
|
|
192
|
+
5. **Multi-network routes use arrays** -- pass an array to `accepts` for cross-chain support
|
|
193
|
+
6. **Facilitator URL is required** -- the resource server must be able to reach a facilitator
|
|
194
|
+
7. **Price strings use USD notation** -- `"$0.01"` is resolved to the appropriate asset amount
|
|
195
|
+
|
|
196
|
+
## Common Errors / Troubleshooting
|
|
197
|
+
|
|
198
|
+
| Error | Cause | Solution |
|
|
199
|
+
|-------|-------|----------|
|
|
200
|
+
| All routes return 402 | Route patterns too broad | Check route patterns match intended paths |
|
|
201
|
+
| 402 but no `accepts` array | AVM scheme not registered on server | Call `registerExactAvmScheme(server)` |
|
|
202
|
+
| Facilitator unreachable | Wrong URL or facilitator not running | Check `FACILITATOR_URL` and facilitator status |
|
|
203
|
+
| `paymentMiddleware is not a function` | Wrong import | Import from `@x402-avm/express` or `@x402-avm/hono` |
|
|
204
|
+
| CORS errors in browser | Missing CORS middleware | Add `cors()` middleware before payment middleware |
|
|
205
|
+
| Paywall not showing | Missing `mimeType: "text/html"` | Set `mimeType` in route config for browser routes |
|
|
206
|
+
| Dynamic price error | Price function throws | Ensure price function handles all edge cases |
|
|
207
|
+
| 500 on verify/settle | Facilitator signer error | Check facilitator logs, verify private key |
|
|
208
|
+
|
|
209
|
+
## References / Further Reading
|
|
210
|
+
|
|
211
|
+
- [create-typescript-x402-server-reference.md](./create-typescript-x402-server-reference.md) - Detailed middleware API reference
|
|
212
|
+
- [create-typescript-x402-server-examples.md](./create-typescript-x402-server-examples.md) - Complete server code examples
|
|
213
|
+
- [@x402-avm/express on npm](https://www.npmjs.com/package/@x402-avm/express)
|
|
214
|
+
- [@x402-avm/hono on npm](https://www.npmjs.com/package/@x402-avm/hono)
|
|
215
|
+
- [GoPlausible x402-avm Examples](https://github.com/GoPlausible/x402-avm/tree/branch-v2-algorand-publish/examples/)
|
|
216
|
+
- [GoPlausible x402-avm Documentation](https://github.com/GoPlausible/.github/blob/main/profile/algorand-x402-documentation/)
|