@4mica/x402 0.1.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/.eslintrc.cjs +29 -0
- package/.prettierignore +3 -0
- package/.prettierrc +6 -0
- package/CHANGELOG.md +8 -0
- package/LICENSE +21 -0
- package/README.md +389 -0
- package/demo/.env.example +8 -0
- package/demo/README.md +125 -0
- package/demo/package.json +26 -0
- package/demo/src/client.ts +54 -0
- package/demo/src/deposit.ts +39 -0
- package/demo/src/server.ts +74 -0
- package/demo/tsconfig.json +8 -0
- package/demo/yarn.lock +925 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.js +1 -0
- package/dist/client/scheme.d.ts +11 -0
- package/dist/client/scheme.js +65 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/server/express/adapter.d.ts +71 -0
- package/dist/server/express/adapter.js +90 -0
- package/dist/server/express/index.d.ts +122 -0
- package/dist/server/express/index.js +340 -0
- package/dist/server/facilitator.d.ts +35 -0
- package/dist/server/facilitator.js +52 -0
- package/dist/server/index.d.ts +6 -0
- package/dist/server/index.js +4 -0
- package/dist/server/scheme.d.ts +93 -0
- package/dist/server/scheme.js +179 -0
- package/eslint.config.mjs +22 -0
- package/package.json +79 -0
- package/src/client/index.ts +1 -0
- package/src/client/scheme.ts +95 -0
- package/src/index.ts +7 -0
- package/src/server/express/adapter.ts +100 -0
- package/src/server/express/index.ts +466 -0
- package/src/server/facilitator.ts +90 -0
- package/src/server/index.ts +10 -0
- package/src/server/scheme.ts +223 -0
- package/tsconfig.build.json +5 -0
- package/tsconfig.json +17 -0
- package/vitest.config.ts +12 -0
package/.eslintrc.cjs
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
root: true,
|
|
3
|
+
env: {
|
|
4
|
+
es2020: true,
|
|
5
|
+
node: true,
|
|
6
|
+
},
|
|
7
|
+
parser: "@typescript-eslint/parser",
|
|
8
|
+
parserOptions: {
|
|
9
|
+
sourceType: "module",
|
|
10
|
+
ecmaVersion: 2020,
|
|
11
|
+
project: "./tsconfig.json",
|
|
12
|
+
},
|
|
13
|
+
plugins: ["@typescript-eslint"],
|
|
14
|
+
extends: [
|
|
15
|
+
"eslint:recommended",
|
|
16
|
+
"plugin:@typescript-eslint/recommended",
|
|
17
|
+
"eslint-config-prettier",
|
|
18
|
+
],
|
|
19
|
+
rules: {
|
|
20
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
21
|
+
"@typescript-eslint/explicit-module-boundary-types": "off",
|
|
22
|
+
"@typescript-eslint/no-unused-vars": [
|
|
23
|
+
"error",
|
|
24
|
+
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
|
|
25
|
+
],
|
|
26
|
+
"@typescript-eslint/no-var-requires": "off",
|
|
27
|
+
},
|
|
28
|
+
ignorePatterns: ["dist", "node_modules"],
|
|
29
|
+
};
|
package/.prettierignore
ADDED
package/.prettierrc
ADDED
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.3.0
|
|
4
|
+
- Breaking: include `reqId` in `PaymentGuaranteeRequestClaims` and signing payloads (EIP-712/EIP-191).
|
|
5
|
+
- Breaking: X402 envelopes now emit `req_id` and `TabResponse` exposes `nextReqId` for claim building.
|
|
6
|
+
- Fix: `listRecipientTabs` query parameter uses `settlement_status` to match core API.
|
|
7
|
+
- Improve: RPC admin endpoints return typed `UserSuspensionStatus`/`AdminApiKey*` models and errors carry status metadata.
|
|
8
|
+
- Fix: contract gateway disambiguates overloaded withdrawal functions for ethers v6.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 4Mica
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
# @4mica/x402
|
|
2
|
+
|
|
3
|
+
Express middleware and client integration for the x402 Payment Protocol with 4mica credit flow support. This package provides batteries-included middleware for adding 4mica payment requirements to your Express.js applications, with automatic facilitator and scheme registration.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm install @4mica/x402
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start (Server)
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import express from "express";
|
|
15
|
+
import { paymentMiddlewareFromConfig } from "@4mica/x402/server/express";
|
|
16
|
+
|
|
17
|
+
const app = express();
|
|
18
|
+
app.use(express.json());
|
|
19
|
+
|
|
20
|
+
// Apply the payment middleware - facilitator and scheme are automatically configured
|
|
21
|
+
app.use(
|
|
22
|
+
paymentMiddlewareFromConfig(
|
|
23
|
+
{
|
|
24
|
+
"GET /premium-content": {
|
|
25
|
+
accepts: {
|
|
26
|
+
scheme: "4mica-credit",
|
|
27
|
+
price: "$0.10",
|
|
28
|
+
network: "eip155:11155111", // Ethereum Sepolia
|
|
29
|
+
payTo: "0xYourAddress",
|
|
30
|
+
},
|
|
31
|
+
description: "Access to premium content",
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
// Payment tab config
|
|
35
|
+
{
|
|
36
|
+
advertisedEndpoint: "https://api.example.com/tabs/open",
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
// Implement your protected route
|
|
42
|
+
app.get("/premium-content", (req, res) => {
|
|
43
|
+
res.json({ message: "This is premium content behind a paywall" });
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
app.listen(3000, () => {
|
|
47
|
+
console.log("Server running on http://localhost:3000");
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Quick Start (Client)
|
|
52
|
+
|
|
53
|
+
### Using with Fetch
|
|
54
|
+
|
|
55
|
+
Use with `@x402/fetch` for automatic payment handling:
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
|
|
59
|
+
import { FourMicaEvmScheme } from "@4mica/x402/client";
|
|
60
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
61
|
+
|
|
62
|
+
// Create an EVM account
|
|
63
|
+
const account = privateKeyToAccount("0xYourPrivateKey");
|
|
64
|
+
|
|
65
|
+
// Create the 4mica scheme client
|
|
66
|
+
const scheme = await FourMicaEvmScheme.create(account);
|
|
67
|
+
|
|
68
|
+
// Wrap fetch with payment handling
|
|
69
|
+
const fetchWithPayment = wrapFetchWithPaymentFromConfig(fetch, {
|
|
70
|
+
schemes: [
|
|
71
|
+
{
|
|
72
|
+
network: "eip155:11155111", // Ethereum Sepolia
|
|
73
|
+
client: scheme,
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Make requests - payments are handled automatically
|
|
79
|
+
const response = await fetchWithPayment("https://api.example.com/premium-content");
|
|
80
|
+
const data = await response.json();
|
|
81
|
+
console.log(data);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Using with Axios
|
|
85
|
+
|
|
86
|
+
Use with `@x402/axios` for Axios-based applications:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import axios from "axios";
|
|
90
|
+
import { wrapAxiosWithPaymentFromConfig } from "@x402/axios";
|
|
91
|
+
import { FourMicaEvmScheme } from "@4mica/x402/client";
|
|
92
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
93
|
+
|
|
94
|
+
// Create an EVM account
|
|
95
|
+
const account = privateKeyToAccount("0xYourPrivateKey");
|
|
96
|
+
|
|
97
|
+
// Create the 4mica scheme client
|
|
98
|
+
const scheme = await FourMicaEvmScheme.create(account);
|
|
99
|
+
|
|
100
|
+
// Wrap axios instance with payment handling
|
|
101
|
+
const api = wrapAxiosWithPaymentFromConfig(axios.create(), {
|
|
102
|
+
schemes: [
|
|
103
|
+
{
|
|
104
|
+
network: "eip155:11155111", // Ethereum Sepolia
|
|
105
|
+
client: scheme,
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Make requests - payments are handled automatically
|
|
111
|
+
const response = await api.get("https://api.example.com/premium-content");
|
|
112
|
+
const data = response.data;
|
|
113
|
+
console.log(data);
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Server Configuration
|
|
117
|
+
|
|
118
|
+
### `paymentMiddlewareFromConfig(routes, tabConfig, ...options)`
|
|
119
|
+
|
|
120
|
+
The recommended middleware factory for most use cases. Automatically configures the 4mica facilitator and registers the `FourMicaEvmScheme` for all supported networks.
|
|
121
|
+
|
|
122
|
+
#### Parameters
|
|
123
|
+
|
|
124
|
+
1. **`routes`** (required): Route configurations for protected endpoints
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
{
|
|
128
|
+
"GET /path": {
|
|
129
|
+
accepts: {
|
|
130
|
+
scheme: "4mica-credit",
|
|
131
|
+
price: "$0.10",
|
|
132
|
+
network: "eip155:11155111", // or "eip155:80002" for Polygon Amoy
|
|
133
|
+
payTo: "0xRecipientAddress",
|
|
134
|
+
},
|
|
135
|
+
description: "What the user is paying for",
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
2. **`tabConfig`** (required): Payment tab configuration
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
{
|
|
144
|
+
// Full URL endpoint for opening payment tabs
|
|
145
|
+
// This is injected into paymentRequirements.extra and clients use it to open tabs
|
|
146
|
+
advertisedEndpoint: "https://api.example.com/tabs/open",
|
|
147
|
+
|
|
148
|
+
// Lifetime of payment tabs in seconds
|
|
149
|
+
ttlSeconds: 3600, // optional, defaults to facilitator's default
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
3. **`facilitatorClients`** (optional): Additional facilitator client(s) for other payment schemes
|
|
154
|
+
4. **`schemes`** (optional): Additional scheme registrations for other networks/schemes
|
|
155
|
+
5. **`paywallConfig`** (optional): Configuration for the built-in paywall UI
|
|
156
|
+
6. **`paywall`** (optional): Custom paywall provider
|
|
157
|
+
7. **`syncFacilitatorOnStart`** (optional): Whether to sync with facilitator on startup (defaults to true)
|
|
158
|
+
|
|
159
|
+
#### Supported Networks
|
|
160
|
+
|
|
161
|
+
- `eip155:11155111` - Ethereum Sepolia
|
|
162
|
+
- `eip155:80002` - Polygon Amoy
|
|
163
|
+
|
|
164
|
+
### Advanced Server Usage
|
|
165
|
+
|
|
166
|
+
For advanced scenarios where you need additional payment schemes or custom configuration:
|
|
167
|
+
|
|
168
|
+
#### Using `paymentMiddleware` with Custom Server
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import { paymentMiddleware } from "@4mica/x402/server/express";
|
|
172
|
+
import {
|
|
173
|
+
x402ResourceServer,
|
|
174
|
+
FourMicaFacilitatorClient,
|
|
175
|
+
} from "@4mica/x402/server";
|
|
176
|
+
import { ExactEvmScheme } from "@x402/evm/exact/server";
|
|
177
|
+
import { HTTPFacilitatorClient } from "@x402/core/server";
|
|
178
|
+
|
|
179
|
+
// Create 4mica facilitator
|
|
180
|
+
const fourMicaFacilitator = new FourMicaFacilitatorClient();
|
|
181
|
+
|
|
182
|
+
// Optionally add other facilitators/schemes for additional payment methods
|
|
183
|
+
const otherFacilitator = new HTTPFacilitatorClient({
|
|
184
|
+
url: "https://other-facilitator.example.com"
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// Create resource server with facilitators and additional schemes
|
|
188
|
+
// The middleware will auto-register FourMicaEvmScheme
|
|
189
|
+
const resourceServer = new x402ResourceServer([
|
|
190
|
+
fourMicaFacilitator,
|
|
191
|
+
otherFacilitator,
|
|
192
|
+
])
|
|
193
|
+
.register("eip155:8453", new ExactEvmScheme()); // Add Base mainnet with exact scheme
|
|
194
|
+
|
|
195
|
+
app.use(
|
|
196
|
+
paymentMiddleware(
|
|
197
|
+
routes,
|
|
198
|
+
resourceServer,
|
|
199
|
+
{
|
|
200
|
+
advertisedEndpoint: "https://api.example.com/tabs/open",
|
|
201
|
+
ttlSeconds: 3600,
|
|
202
|
+
},
|
|
203
|
+
paywallConfig
|
|
204
|
+
)
|
|
205
|
+
);
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
#### Using `paymentMiddlewareFromHTTPServer` with HTTP Hooks
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
import { paymentMiddlewareFromHTTPServer } from "@4mica/x402/server/express";
|
|
212
|
+
import {
|
|
213
|
+
x402ResourceServer,
|
|
214
|
+
x402HTTPResourceServer,
|
|
215
|
+
FourMicaFacilitatorClient,
|
|
216
|
+
} from "@4mica/x402/server";
|
|
217
|
+
|
|
218
|
+
// Create 4mica facilitator
|
|
219
|
+
const fourMicaFacilitator = new FourMicaFacilitatorClient();
|
|
220
|
+
|
|
221
|
+
// The middleware will auto-register FourMicaEvmScheme
|
|
222
|
+
const resourceServer = new x402ResourceServer(fourMicaFacilitator);
|
|
223
|
+
|
|
224
|
+
const httpServer = new x402HTTPResourceServer(resourceServer, routes)
|
|
225
|
+
.onProtectedRequest((context) => {
|
|
226
|
+
console.log("Protected request:", context.path);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
app.use(
|
|
230
|
+
paymentMiddlewareFromHTTPServer(
|
|
231
|
+
httpServer,
|
|
232
|
+
{
|
|
233
|
+
advertisedEndpoint: "https://api.example.com/tabs/open",
|
|
234
|
+
ttlSeconds: 3600,
|
|
235
|
+
},
|
|
236
|
+
paywallConfig
|
|
237
|
+
)
|
|
238
|
+
);
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Client Configuration
|
|
242
|
+
|
|
243
|
+
### Multi-Network Client Setup
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
|
|
247
|
+
import { FourMicaEvmScheme } from "@4mica/x402/client";
|
|
248
|
+
|
|
249
|
+
const sepoliaScheme = await FourMicaEvmScheme.create(sepoliaAccount);
|
|
250
|
+
const amoyScheme = await FourMicaEvmScheme.create(amoyAccount);
|
|
251
|
+
|
|
252
|
+
const fetchWithPayment = wrapFetchWithPaymentFromConfig(fetch, {
|
|
253
|
+
schemes: [
|
|
254
|
+
{
|
|
255
|
+
network: "eip155:11155111", // Ethereum Sepolia
|
|
256
|
+
client: sepoliaScheme,
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
network: "eip155:80002", // Polygon Amoy
|
|
260
|
+
client: amoyScheme,
|
|
261
|
+
},
|
|
262
|
+
],
|
|
263
|
+
});
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Using Builder Pattern
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
import { wrapFetchWithPayment, x402Client } from "@x402/fetch";
|
|
270
|
+
import { FourMicaEvmScheme } from "@4mica/x402/client";
|
|
271
|
+
|
|
272
|
+
const scheme = await FourMicaEvmScheme.create(account);
|
|
273
|
+
|
|
274
|
+
const client = new x402Client()
|
|
275
|
+
.register("eip155:11155111", scheme);
|
|
276
|
+
|
|
277
|
+
const fetchWithPayment = wrapFetchWithPayment(fetch, client);
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Complete Example
|
|
281
|
+
|
|
282
|
+
### Server
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
import express from "express";
|
|
286
|
+
import { paymentMiddlewareFromConfig } from "@4mica/x402/server/express";
|
|
287
|
+
|
|
288
|
+
const app = express();
|
|
289
|
+
app.use(express.json());
|
|
290
|
+
|
|
291
|
+
app.use(
|
|
292
|
+
paymentMiddlewareFromConfig(
|
|
293
|
+
{
|
|
294
|
+
"GET /api/data": {
|
|
295
|
+
accepts: {
|
|
296
|
+
scheme: "4mica-credit",
|
|
297
|
+
price: "$0.05",
|
|
298
|
+
network: "eip155:11155111",
|
|
299
|
+
payTo: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
|
|
300
|
+
},
|
|
301
|
+
description: "API data access",
|
|
302
|
+
},
|
|
303
|
+
"POST /api/compute": {
|
|
304
|
+
accepts: {
|
|
305
|
+
scheme: "4mica-credit",
|
|
306
|
+
price: "$0.20",
|
|
307
|
+
network: "eip155:11155111",
|
|
308
|
+
payTo: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
|
|
309
|
+
},
|
|
310
|
+
description: "Computation service",
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
advertisedEndpoint: "https://api.example.com/tabs/open",
|
|
315
|
+
ttlSeconds: 7200, // 2 hours
|
|
316
|
+
}
|
|
317
|
+
)
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
app.get("/api/data", (req, res) => {
|
|
321
|
+
res.json({ data: "Premium data content" });
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
app.post("/api/compute", (req, res) => {
|
|
325
|
+
res.json({ result: "Computation complete" });
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
app.listen(3000);
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Client
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
|
|
335
|
+
import { FourMicaEvmScheme } from "@4mica/x402/client";
|
|
336
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
337
|
+
|
|
338
|
+
async function main() {
|
|
339
|
+
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
|
|
340
|
+
const scheme = await FourMicaEvmScheme.create(account);
|
|
341
|
+
|
|
342
|
+
const fetchWithPayment = wrapFetchWithPaymentFromConfig(fetch, {
|
|
343
|
+
schemes: [
|
|
344
|
+
{
|
|
345
|
+
network: "eip155:11155111",
|
|
346
|
+
client: scheme,
|
|
347
|
+
},
|
|
348
|
+
],
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
// Fetch premium data - payment handled automatically
|
|
352
|
+
const dataResponse = await fetchWithPayment("https://api.example.com/api/data");
|
|
353
|
+
const data = await dataResponse.json();
|
|
354
|
+
console.log("Data:", data);
|
|
355
|
+
|
|
356
|
+
// Make computation request - payment handled automatically
|
|
357
|
+
const computeResponse = await fetchWithPayment("https://api.example.com/api/compute", {
|
|
358
|
+
method: "POST",
|
|
359
|
+
headers: { "Content-Type": "application/json" },
|
|
360
|
+
body: JSON.stringify({ input: "some data" }),
|
|
361
|
+
});
|
|
362
|
+
const result = await computeResponse.json();
|
|
363
|
+
console.log("Result:", result);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
main();
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## How It Works
|
|
370
|
+
|
|
371
|
+
1. **Server Setup**: The middleware automatically registers the `FourMicaEvmScheme` and injects the 4mica facilitator client, so you don't need to configure them manually.
|
|
372
|
+
|
|
373
|
+
2. **Tab Management**: When a client requests a protected resource, the middleware handles the tab lifecycle:
|
|
374
|
+
- The `advertisedEndpoint` is injected into `paymentRequirements.extra.tabEndpoint`
|
|
375
|
+
- Clients use this endpoint to open payment tabs
|
|
376
|
+
- The middleware automatically processes tab opening requests when they arrive at the advertised endpoint
|
|
377
|
+
|
|
378
|
+
3. **Payment Flow**:
|
|
379
|
+
- Client makes initial request to protected resource
|
|
380
|
+
- Server responds with `402 Payment Required` including payment requirements
|
|
381
|
+
- Client requests a tab from the advertised endpoint
|
|
382
|
+
- Client signs a payment guarantee using the 4mica SDK
|
|
383
|
+
- Client retries the request with the payment payload
|
|
384
|
+
- Server verifies and settles the payment via the 4mica facilitator
|
|
385
|
+
- Server returns the protected resource
|
|
386
|
+
|
|
387
|
+
## License
|
|
388
|
+
|
|
389
|
+
MIT
|
package/demo/README.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# @4mica/x402 Demo
|
|
2
|
+
|
|
3
|
+
This demo shows how to use `@4mica/x402` to protect an API endpoint with 4mica payments.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
1. **Install dependencies**:
|
|
8
|
+
|
|
9
|
+
First, build the parent package:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
cd ..
|
|
13
|
+
yarn install
|
|
14
|
+
yarn build
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Then install demo dependencies:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
cd demo
|
|
21
|
+
yarn install
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
2. **Configure environment variables**:
|
|
25
|
+
|
|
26
|
+
Copy the example file and edit it:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
cp .env.example .env
|
|
30
|
+
# Edit .env with your private key and settings
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Required variables:
|
|
34
|
+
- `PRIVATE_KEY`: Your Ethereum private key (with 0x prefix) for Sepolia testnet
|
|
35
|
+
- `PAY_TO_ADDRESS`: Address that will receive payments (optional, defaults to a test address)
|
|
36
|
+
|
|
37
|
+
## Running the Demo
|
|
38
|
+
|
|
39
|
+
### Terminal 1: Start the server
|
|
40
|
+
|
|
41
|
+
From the demo directory:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
yarn server
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Or from the package root:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
yarn demo:server
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
You should see:
|
|
54
|
+
```
|
|
55
|
+
x402 Demo Server running on http://localhost:3000
|
|
56
|
+
Protected endpoint: http://localhost:3000/api/premium-data
|
|
57
|
+
Payment required: $0.05 (4mica credit on Sepolia)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Terminal 2: Run the client
|
|
61
|
+
|
|
62
|
+
The client will automatically load environment variables from `.env`:
|
|
63
|
+
|
|
64
|
+
From the demo directory:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
yarn client
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Or from the package root:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
yarn demo:client
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
You can also set PRIVATE_KEY inline:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
PRIVATE_KEY=0xYourPrivateKey yarn client
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## What Happens
|
|
83
|
+
|
|
84
|
+
1. **Server** starts with one protected endpoint: `GET /api/premium-data`
|
|
85
|
+
- Requires a payment of $0.05 in 4mica credits on Sepolia
|
|
86
|
+
- Uses x402 payment protocol
|
|
87
|
+
|
|
88
|
+
2. **Client** makes a request to the protected endpoint:
|
|
89
|
+
- First receives `402 Payment Required` response
|
|
90
|
+
- Automatically opens a payment tab via the 4mica facilitator
|
|
91
|
+
- Signs and submits the payment
|
|
92
|
+
- Retries the request with payment proof
|
|
93
|
+
- Receives the protected data
|
|
94
|
+
|
|
95
|
+
3. **Payment Flow**:
|
|
96
|
+
```
|
|
97
|
+
Client → GET /api/premium-data
|
|
98
|
+
← 402 Payment Required (with payment requirements)
|
|
99
|
+
|
|
100
|
+
Client → POST /payment/tab (open payment tab)
|
|
101
|
+
← 200 OK (tab details)
|
|
102
|
+
|
|
103
|
+
Client → Signs payment guarantee (via 4mica SDK)
|
|
104
|
+
|
|
105
|
+
Client → GET /api/premium-data (with payment proof)
|
|
106
|
+
← 200 OK (protected data)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Testing Without Running the Client
|
|
110
|
+
|
|
111
|
+
You can also test the server manually using curl:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# Check server status
|
|
115
|
+
curl http://localhost:3000/
|
|
116
|
+
|
|
117
|
+
# Try to access protected endpoint (will return 402)
|
|
118
|
+
curl -v http://localhost:3000/api/premium-data
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Notes
|
|
122
|
+
|
|
123
|
+
- Make sure your account has sufficient balance on Sepolia testnet
|
|
124
|
+
- The demo uses the default 4mica facilitator configuration
|
|
125
|
+
- Tab TTL is set to 1 hour (3600 seconds)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@4mica/x402-demo",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"server": "tsx src/server.ts",
|
|
8
|
+
"client": "tsx src/client.ts",
|
|
9
|
+
"deposit": "tsx src/deposit.ts",
|
|
10
|
+
"dev": "tsx watch src/server.ts"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@4mica/sdk": "file:../../../../../ts-sdk-4mica",
|
|
14
|
+
"@4mica/x402": "file:..",
|
|
15
|
+
"@x402/fetch": "^2.2.0",
|
|
16
|
+
"dotenv": "^16.4.7",
|
|
17
|
+
"express": "^5.2.1",
|
|
18
|
+
"viem": "^2.21.54"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/express": "^5.0.6",
|
|
22
|
+
"@types/node": "^25.0.7",
|
|
23
|
+
"tsx": "^4.19.2",
|
|
24
|
+
"typescript": "^5.3.3"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import 'dotenv/config'
|
|
2
|
+
import { wrapFetchWithPaymentFromConfig } from '@x402/fetch'
|
|
3
|
+
import { FourMicaEvmScheme } from '@4mica/x402/client'
|
|
4
|
+
import { privateKeyToAccount } from 'viem/accounts'
|
|
5
|
+
|
|
6
|
+
async function main() {
|
|
7
|
+
const privateKey = process.env.PRIVATE_KEY
|
|
8
|
+
if (!privateKey || !privateKey.startsWith('0x')) {
|
|
9
|
+
console.error('Error: PRIVATE_KEY environment variable must be set and start with 0x')
|
|
10
|
+
console.error('Example: PRIVATE_KEY=0x1234... yarn client')
|
|
11
|
+
process.exit(1)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const apiUrl = process.env.API_URL || 'http://localhost:3000'
|
|
15
|
+
const endpoint = `${apiUrl}/api/premium-data`
|
|
16
|
+
|
|
17
|
+
console.log('Initializing x402 client...')
|
|
18
|
+
console.log(`Target endpoint: ${endpoint}`)
|
|
19
|
+
|
|
20
|
+
const account = privateKeyToAccount(privateKey as `0x${string}`)
|
|
21
|
+
console.log(`Using account: ${account.address}`)
|
|
22
|
+
|
|
23
|
+
const scheme = await FourMicaEvmScheme.create(account)
|
|
24
|
+
|
|
25
|
+
const fetchWithPayment = wrapFetchWithPaymentFromConfig(fetch, {
|
|
26
|
+
schemes: [
|
|
27
|
+
{
|
|
28
|
+
network: 'eip155:11155111', // Ethereum Sepolia
|
|
29
|
+
client: scheme,
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
console.log('\nMaking request to protected endpoint...')
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const response = await fetchWithPayment(endpoint)
|
|
38
|
+
const data = await response.json()
|
|
39
|
+
|
|
40
|
+
console.log('Request successful!')
|
|
41
|
+
console.log('Response:', JSON.stringify(data, null, 2))
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error('Request failed:', error)
|
|
44
|
+
if (error instanceof Error) {
|
|
45
|
+
console.error('Message:', error.message)
|
|
46
|
+
}
|
|
47
|
+
process.exit(1)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
main().catch((error) => {
|
|
52
|
+
console.error('Unhandled error:', error)
|
|
53
|
+
process.exit(1)
|
|
54
|
+
})
|