@dcentralab/d402-client 0.2.7 โ 0.3.2
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 +22 -0
- package/README.md +58 -553
- package/dist/index.d.mts +474 -283
- package/dist/index.d.ts +474 -283
- package/dist/index.js +112 -100
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +102 -98
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -10
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Traia
|
|
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.
|
|
22
|
+
|
package/README.md
CHANGED
|
@@ -4,517 +4,80 @@
|
|
|
4
4
|
|
|
5
5
|
Implementation of the D402 payment protocol for HTTP 402 (Payment Required) responses. Works in any JavaScript environment (React, Next.js, Vue, Node.js, etc.) with automatic payment signing and retry.
|
|
6
6
|
|
|
7
|
-
Part of the iatp-js monorepo.
|
|
7
|
+
Part of the iatp-js monorepo. Built by Dcentralab.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## ๐ Quick Start
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
### Installation
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
npm install @dcentralab/d402-client viem wagmi
|
|
15
|
-
|
|
16
|
-
# or
|
|
17
|
-
pnpm add @dcentralab/d402-client viem wagmi
|
|
18
|
-
|
|
19
|
-
# or
|
|
20
|
-
yarn add @dcentralab/d402-client viem wagmi
|
|
21
|
-
|
|
22
15
|
```
|
|
23
16
|
|
|
24
|
-
**Requirements:**
|
|
25
|
-
- React/Next.js app
|
|
26
|
-
- viem ^2.21.0
|
|
27
|
-
- wagmi (for wallet connection)
|
|
28
|
-
- User with Web3 wallet (MetaMask, WalletConnect, etc.)
|
|
29
|
-
|
|
30
|
-
## ๐ Quick Start (React/Next.js)
|
|
31
|
-
|
|
32
|
-
## ๐ก Complete React Example (Recommended Pattern)
|
|
17
|
+
**Requirements:** React/Next.js app with viem ^2.21.0 and wagmi for wallet connection.
|
|
33
18
|
|
|
34
|
-
###
|
|
19
|
+
### Your First Payment
|
|
35
20
|
|
|
36
21
|
```typescript
|
|
37
|
-
'
|
|
38
|
-
|
|
39
|
-
import { useMutation } from '@tanstack/react-query'
|
|
22
|
+
import { D402Client, createIATPWallet, getWalletsByOwner } from '@dcentralab/d402-client'
|
|
40
23
|
import { useWalletClient } from 'wagmi'
|
|
41
|
-
import {
|
|
42
|
-
createIATPWallet,
|
|
43
|
-
D402Client,
|
|
44
|
-
getWalletsByOwner
|
|
45
|
-
} from '@dcentralab/d402-client'
|
|
46
|
-
|
|
47
|
-
interface PaymentParams {
|
|
48
|
-
endpoint: string
|
|
49
|
-
payload: Record<string, unknown>
|
|
50
|
-
maxValue: bigint
|
|
51
|
-
network?: 'sepolia'
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function useD402Payment() {
|
|
55
|
-
const { data: walletClient } = useWalletClient()
|
|
56
|
-
|
|
57
|
-
const mutation = useMutation({
|
|
58
|
-
mutationFn: async ({
|
|
59
|
-
endpoint,
|
|
60
|
-
payload,
|
|
61
|
-
maxValue,
|
|
62
|
-
network = 'sepolia'
|
|
63
|
-
}: PaymentParams) => {
|
|
64
|
-
if (!walletClient) {
|
|
65
|
-
throw new Error('Please connect your wallet first')
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Check if user already has IATP wallet
|
|
69
|
-
const existingWallets = await getWalletsByOwner({
|
|
70
|
-
ownerAddress: walletClient.account.address,
|
|
71
|
-
network
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
// Get or create wallet
|
|
75
|
-
let iatpWalletAddress: `0x${string}`
|
|
76
|
-
|
|
77
|
-
if (existingWallets.length === 0) {
|
|
78
|
-
// Create new wallet (one-time)
|
|
79
|
-
const newWallet = await createIATPWallet({
|
|
80
|
-
ownerAccount: walletClient.account,
|
|
81
|
-
network
|
|
82
|
-
})
|
|
83
|
-
iatpWalletAddress = newWallet.walletAddress
|
|
84
|
-
} else {
|
|
85
|
-
// Use existing wallet
|
|
86
|
-
iatpWalletAddress = existingWallets[0]
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Create D402 client
|
|
90
|
-
const client = new D402Client({
|
|
91
|
-
operatorAccount: walletClient.account,
|
|
92
|
-
iatpWalletAddress,
|
|
93
|
-
maxValue
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
// Call 402-protected API
|
|
97
|
-
const response = await client.fetch(endpoint, {
|
|
98
|
-
method: 'POST',
|
|
99
|
-
headers: { 'Content-Type': 'application/json' },
|
|
100
|
-
body: JSON.stringify(payload)
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
return await response.json()
|
|
104
|
-
}
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
return {
|
|
108
|
-
execute: mutation.mutateAsync,
|
|
109
|
-
isLoading: mutation.isPending,
|
|
110
|
-
result: mutation.data,
|
|
111
|
-
error: mutation.error,
|
|
112
|
-
isWalletConnected: !!walletClient
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### Use in Component
|
|
118
|
-
|
|
119
|
-
```typescript
|
|
120
|
-
'use client'
|
|
121
|
-
|
|
122
|
-
import { useD402Payment } from '@/hooks/useD402Payment'
|
|
123
|
-
|
|
124
|
-
export default function AnalyzeButton() {
|
|
125
|
-
const { execute, isLoading, result, error, isWalletConnected } = useD402Payment()
|
|
126
|
-
|
|
127
|
-
async function handleAnalyze() {
|
|
128
|
-
await execute({
|
|
129
|
-
endpoint: 'https://sentiment-api.com/analyze',
|
|
130
|
-
payload: { text: 'Bitcoin looks bullish today' },
|
|
131
|
-
maxValue: 1000000n // 1 USDC max
|
|
132
|
-
})
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (!isWalletConnected) {
|
|
136
|
-
return <button disabled>Connect Wallet First</button>
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return (
|
|
140
|
-
<div>
|
|
141
|
-
<button onClick={handleAnalyze} disabled={isLoading}>
|
|
142
|
-
{isLoading ? 'Processing...' : 'Analyze Sentiment (โ0.01 USDC)'}
|
|
143
|
-
</button>
|
|
144
|
-
|
|
145
|
-
{error && (
|
|
146
|
-
<div className="error">
|
|
147
|
-
Error: {error.message}
|
|
148
|
-
</div>
|
|
149
|
-
)}
|
|
150
|
-
|
|
151
|
-
{result && (
|
|
152
|
-
<div className="success">
|
|
153
|
-
<pre>{JSON.stringify(result, null, 2)}</pre>
|
|
154
|
-
</div>
|
|
155
|
-
)}
|
|
156
|
-
</div>
|
|
157
|
-
)
|
|
158
|
-
}
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
**This pattern:**
|
|
162
|
-
- โ
Automatically checks for existing wallet
|
|
163
|
-
- โ
Creates wallet only if needed (one-time)
|
|
164
|
-
- โ
Reuses wallet for future calls
|
|
165
|
-
- โ
Handles loading and error states
|
|
166
|
-
- โ
Works with React Query for caching
|
|
167
|
-
|
|
168
|
-
---
|
|
169
|
-
|
|
170
|
-
## ๐๏ธ Features
|
|
171
|
-
|
|
172
|
-
### 1. IATPWallet Creation
|
|
173
|
-
|
|
174
|
-
Create on-chain wallet with owner/operator separation:
|
|
175
|
-
|
|
176
|
-
```typescript
|
|
177
|
-
import { createIATPWallet } from '@dcentralab/d402-client'
|
|
178
|
-
import { privateKeyToAccount } from 'viem/accounts'
|
|
179
24
|
|
|
180
|
-
//
|
|
181
|
-
const
|
|
25
|
+
// In your React component
|
|
26
|
+
const { data: walletClient } = useWalletClient()
|
|
182
27
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
28
|
+
// 1. Check if user has an IATP wallet
|
|
29
|
+
const existingWallets = await getWalletsByOwner({
|
|
30
|
+
ownerAddress: walletClient.account.address,
|
|
31
|
+
network: 'sepolia'
|
|
187
32
|
})
|
|
188
33
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
**Returns:**
|
|
194
|
-
- `walletAddress` - IATPWallet contract address
|
|
195
|
-
- `ownerAddress` - Owner's address (also the operator)
|
|
196
|
-
- `transactionHash` - Creation transaction
|
|
197
|
-
- `blockNumber` - Block where wallet was created
|
|
198
|
-
- `network` - Network where deployed
|
|
199
|
-
- `chainId` - Chain ID
|
|
200
|
-
|
|
201
|
-
### 2. Automatic 402 Payment Handling
|
|
202
|
-
|
|
203
|
-
```typescript
|
|
204
|
-
import { D402Client } from '@dcentralab/d402-client'
|
|
34
|
+
// 2. Create wallet if needed (one-time)
|
|
35
|
+
const walletAddress = existingWallets.length === 0
|
|
36
|
+
? (await createIATPWallet({ ownerAccount: walletClient.account })).walletAddress
|
|
37
|
+
: existingWallets[0]
|
|
205
38
|
|
|
39
|
+
// 3. Create D402 client
|
|
206
40
|
const client = new D402Client({
|
|
207
|
-
operatorAccount,
|
|
208
|
-
iatpWalletAddress:
|
|
209
|
-
maxValue: 1000000n
|
|
210
|
-
networkFilter: 'sepolia', // Only Sepolia network
|
|
211
|
-
schemeFilter: 'exact' // Only exact payments
|
|
41
|
+
operatorAccount: walletClient.account,
|
|
42
|
+
iatpWalletAddress: walletAddress,
|
|
43
|
+
maxValue: 1000000n // 1 USDC max
|
|
212
44
|
})
|
|
213
45
|
|
|
214
|
-
//
|
|
215
|
-
|
|
216
|
-
// 2. Parses payment requirements
|
|
217
|
-
// 3. Signs with EIP-712
|
|
218
|
-
// 4. Retries with payment
|
|
219
|
-
const response = await client.fetch('https://paid-api.com/endpoint')
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
### 3. Manual Payment Flow (Low-Level)
|
|
223
|
-
|
|
224
|
-
```typescript
|
|
225
|
-
import {
|
|
226
|
-
parsePaymentRequirement,
|
|
227
|
-
signD402Payment,
|
|
228
|
-
encodePayment
|
|
229
|
-
} from '@dcentralab/d402-client'
|
|
230
|
-
|
|
231
|
-
// 1. Make request
|
|
232
|
-
const response = await fetch('https://api.example.com')
|
|
233
|
-
|
|
234
|
-
if (response.status === 402) {
|
|
235
|
-
// 2. Parse payment requirement
|
|
236
|
-
const requirement = await parsePaymentRequirement(response)
|
|
237
|
-
|
|
238
|
-
// 3. Sign payment
|
|
239
|
-
const signedPayment = await signD402Payment({
|
|
240
|
-
operatorAccount,
|
|
241
|
-
paymentRequirement: requirement,
|
|
242
|
-
iatpWalletAddress: '0xYourWallet...'
|
|
243
|
-
})
|
|
244
|
-
|
|
245
|
-
// 4. Encode for header
|
|
246
|
-
const paymentHeader = encodePayment(signedPayment)
|
|
247
|
-
|
|
248
|
-
// 5. Retry with payment
|
|
249
|
-
const paidResponse = await fetch('https://api.example.com', {
|
|
250
|
-
headers: { 'X-Payment': paymentHeader }
|
|
251
|
-
})
|
|
252
|
-
}
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
## ๐ง API Reference
|
|
256
|
-
|
|
257
|
-
### D402Client
|
|
258
|
-
|
|
259
|
-
Main class for automatic 402 payment handling.
|
|
260
|
-
|
|
261
|
-
#### Constructor
|
|
262
|
-
|
|
263
|
-
```typescript
|
|
264
|
-
new D402Client(config: D402ClientConfig)
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
**Config Options:**
|
|
268
|
-
|
|
269
|
-
| Option | Type | Required | Description |
|
|
270
|
-
|--------|------|----------|-------------|
|
|
271
|
-
| `operatorAccount` | `Account` | โ
| Viem account for signing payments (EOA) |
|
|
272
|
-
| `iatpWalletAddress` | `0x${string}` | โ | IATPWallet contract address (uses operator address if not provided) |
|
|
273
|
-
| `maxValue` | `bigint` | โ | Max payment in base units (wei). Safety limit to prevent overpaying. |
|
|
274
|
-
| `networkFilter` | `string` | โ | Only select requirements matching this network |
|
|
275
|
-
| `schemeFilter` | `string` | โ | Payment scheme filter (default: "exact") |
|
|
276
|
-
| `paymentRequirementsSelector` | `PaymentSelector` | โ | Custom payment selection logic |
|
|
277
|
-
|
|
278
|
-
#### Methods
|
|
279
|
-
|
|
280
|
-
**`fetch(url, init?): Promise<Response>`**
|
|
281
|
-
|
|
282
|
-
Fetch with automatic 402 payment handling. Same API as native fetch.
|
|
283
|
-
|
|
284
|
-
```typescript
|
|
285
|
-
const response = await client.fetch(url, {
|
|
46
|
+
// 4. Call 402-protected API (automatic payment handling!)
|
|
47
|
+
const response = await client.fetch('https://paid-api.com/analyze', {
|
|
286
48
|
method: 'POST',
|
|
287
|
-
|
|
288
|
-
body: JSON.stringify(data)
|
|
49
|
+
body: JSON.stringify({ text: 'Bitcoin looks bullish' })
|
|
289
50
|
})
|
|
290
51
|
```
|
|
291
52
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
Select payment requirement from list based on filters.
|
|
295
|
-
|
|
296
|
-
**`getWalletAddress(): 0x${string}`**
|
|
297
|
-
|
|
298
|
-
Get configured wallet address.
|
|
299
|
-
|
|
300
|
-
**`getOperatorAccount(): Account`**
|
|
301
|
-
|
|
302
|
-
Get operator account.
|
|
303
|
-
|
|
304
|
-
**`getMaxValue(): bigint | undefined`**
|
|
305
|
-
|
|
306
|
-
Get maximum payment limit.
|
|
307
|
-
|
|
308
|
-
### Functions
|
|
309
|
-
|
|
310
|
-
**`createIATPWallet(params): Promise<WalletCreationResult>`**
|
|
311
|
-
|
|
312
|
-
Create new IATPWallet contract on-chain.
|
|
313
|
-
|
|
314
|
-
**Parameters:**
|
|
315
|
-
- `ownerAccount: Account` - Owner's viem account (will also be the operator)
|
|
316
|
-
- `network?: 'sepolia'` - Network (default: sepolia)
|
|
317
|
-
- `rpcUrl?: string` - Custom RPC URL
|
|
318
|
-
|
|
319
|
-
**`parsePaymentRequirement(response): Promise<PaymentRequirement>`**
|
|
320
|
-
|
|
321
|
-
Parse first payment requirement from 402 response.
|
|
322
|
-
|
|
323
|
-
**`parseAllPaymentRequirements(response): Promise<PaymentRequirement[]>`**
|
|
324
|
-
|
|
325
|
-
Parse all payment requirements from 402 response.
|
|
326
|
-
|
|
327
|
-
**`signD402Payment(params): Promise<SignedPayment>`**
|
|
328
|
-
|
|
329
|
-
Sign payment with EIP-712.
|
|
330
|
-
|
|
331
|
-
**`encodePayment(payment): string`**
|
|
332
|
-
|
|
333
|
-
Encode signed payment to base64 for X-Payment header.
|
|
334
|
-
|
|
335
|
-
**`decodePayment(encoded): SignedPayment`**
|
|
336
|
-
|
|
337
|
-
Decode base64 payment header.
|
|
338
|
-
|
|
339
|
-
### Contract Functions
|
|
340
|
-
|
|
341
|
-
**`getContractAddress(name, network): string | null`**
|
|
342
|
-
|
|
343
|
-
Get contract address for network.
|
|
344
|
-
|
|
345
|
-
**`getContractAbi(name, network): any[] | null`**
|
|
346
|
-
|
|
347
|
-
Get contract ABI for network.
|
|
348
|
-
|
|
349
|
-
**`getContractConfig(name, network): { address, abi } | null`**
|
|
350
|
-
|
|
351
|
-
Get both address and ABI.
|
|
352
|
-
|
|
353
|
-
### Utility Functions
|
|
354
|
-
|
|
355
|
-
**`parseMoney(amount, decimals): bigint`**
|
|
53
|
+
That's it! The client automatically handles 402 responses, payment signing, and retry.
|
|
356
54
|
|
|
357
|
-
|
|
55
|
+
## ๐ Documentation
|
|
358
56
|
|
|
359
|
-
|
|
57
|
+
- **[Getting Started Guide](./docs/getting-started.md)** - Installation, setup, and first payment
|
|
58
|
+
- **[API Reference](./docs/api-reference.md)** - Complete API documentation
|
|
59
|
+
- **[Wallet Management](./docs/wallet-management.md)** - Creating and managing IATP wallets
|
|
60
|
+
- **[Usage Patterns](./docs/usage-patterns.md)** - Frontend vs backend patterns
|
|
61
|
+
- **[Examples](./docs/examples.md)** - Complete code examples
|
|
62
|
+
- **[Security Guide](./docs/security.md)** - Best practices and security considerations
|
|
360
63
|
|
|
361
|
-
|
|
64
|
+
## ๐๏ธ Key Features
|
|
362
65
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
Get chain ID for network name.
|
|
370
|
-
|
|
371
|
-
## ๐ก Usage Patterns
|
|
372
|
-
|
|
373
|
-
### Pattern 1: Frontend Direct (Recommended for Web3 Apps)
|
|
374
|
-
|
|
375
|
-
**React component calls 402 API directly:**
|
|
376
|
-
|
|
377
|
-
```typescript
|
|
378
|
-
'use client'
|
|
379
|
-
|
|
380
|
-
import { D402Client } from '@dcentralab/d402-client'
|
|
381
|
-
import { useWalletClient } from 'wagmi'
|
|
382
|
-
|
|
383
|
-
export default function PaymentComponent() {
|
|
384
|
-
const { data: walletClient } = useWalletClient()
|
|
385
|
-
|
|
386
|
-
async function callPaidAPI() {
|
|
387
|
-
if (!walletClient) return
|
|
388
|
-
|
|
389
|
-
// User's wallet signs payments
|
|
390
|
-
const client = new D402Client({
|
|
391
|
-
operatorAccount: walletClient.account,
|
|
392
|
-
iatpWalletAddress: '0xUserIATPWallet...',
|
|
393
|
-
maxValue: 1000000n
|
|
394
|
-
})
|
|
395
|
-
|
|
396
|
-
// Calls external 402 API directly
|
|
397
|
-
const response = await client.fetch('https://sentiment-api.com/analyze', {
|
|
398
|
-
method: 'POST',
|
|
399
|
-
body: JSON.stringify({ text: 'Bitcoin sentiment' })
|
|
400
|
-
})
|
|
401
|
-
|
|
402
|
-
return await response.json()
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
```
|
|
406
|
-
|
|
407
|
-
**Flow:** Browser โ D402Client โ External 402 API
|
|
408
|
-
|
|
409
|
-
**Pros:**
|
|
410
|
-
- โ
User pays from their wallet
|
|
411
|
-
- โ
Fully decentralized
|
|
412
|
-
- โ
No backend needed
|
|
413
|
-
|
|
414
|
-
**Cons:**
|
|
415
|
-
- โ ๏ธ Requires wallet connection
|
|
416
|
-
- โ ๏ธ User approves each payment
|
|
417
|
-
|
|
418
|
-
### Pattern 2: Backend Proxy (Alternative)
|
|
419
|
-
|
|
420
|
-
**Backend handles 402 calls, frontend just calls your API:**
|
|
421
|
-
|
|
422
|
-
**Backend (Node.js):**
|
|
423
|
-
```typescript
|
|
424
|
-
import { D402Client } from '@dcentralab/d402-client'
|
|
425
|
-
import { privateKeyToAccount } from 'viem/accounts'
|
|
426
|
-
|
|
427
|
-
const operatorAccount = privateKeyToAccount(process.env.OPERATOR_KEY!)
|
|
428
|
-
|
|
429
|
-
app.post('/api/analyze', async (req, res) => {
|
|
430
|
-
const client = new D402Client({
|
|
431
|
-
operatorAccount,
|
|
432
|
-
iatpWalletAddress: req.user.iatpWallet,
|
|
433
|
-
maxValue: 1000000n
|
|
434
|
-
})
|
|
435
|
-
|
|
436
|
-
const response = await client.fetch('https://sentiment-api.com/analyze', {
|
|
437
|
-
method: 'POST',
|
|
438
|
-
body: JSON.stringify(req.body)
|
|
439
|
-
})
|
|
440
|
-
|
|
441
|
-
res.json(await response.json())
|
|
442
|
-
})
|
|
443
|
-
```
|
|
444
|
-
|
|
445
|
-
**Frontend (simpler):**
|
|
446
|
-
```typescript
|
|
447
|
-
// Just call YOUR backend
|
|
448
|
-
const response = await fetch('/api/analyze', {
|
|
449
|
-
method: 'POST',
|
|
450
|
-
body: JSON.stringify({ text: 'Analyze this' })
|
|
451
|
-
})
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
**Cons:**
|
|
455
|
-
- โ ๏ธ Backend controls payments
|
|
456
|
-
- โ ๏ธ More centralized
|
|
66
|
+
- โ
**Automatic 402 handling** - Detects, signs, and retries with payment
|
|
67
|
+
- โ
**EIP-712 signatures** - Secure, typed message signing
|
|
68
|
+
- โ
**Universal** - Works in browsers and Node.js
|
|
69
|
+
- โ
**Type-safe** - Full TypeScript support
|
|
70
|
+
- โ
**Well-tested** - 166 tests covering all functionality
|
|
457
71
|
|
|
458
72
|
## ๐ Supported Networks
|
|
459
73
|
|
|
460
74
|
IATP contracts are currently deployed on:
|
|
461
75
|
|
|
462
|
-
| Network |
|
|
463
|
-
|
|
464
|
-
| **Sepolia Testnet** |
|
|
465
|
-
|
|
466
|
-
> **Note:** Additional networks (mainnet, Base, Polygon, etc.) will be supported once IATP contracts are deployed on those chains.
|
|
467
|
-
|
|
468
|
-
## ๐ฆ Package Exports
|
|
469
|
-
|
|
470
|
-
```typescript
|
|
471
|
-
// Main client
|
|
472
|
-
export { D402Client } from '@dcentralab/d402-client'
|
|
76
|
+
| Network | Chain ID | USDC Address |
|
|
77
|
+
|----------------------|------------|----------------------------------------------|
|
|
78
|
+
| **Sepolia Testnet** | `11155111` | `0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238` |
|
|
473
79
|
|
|
474
|
-
|
|
475
|
-
export { createIATPWallet } from '@dcentralab/d402-client'
|
|
476
|
-
|
|
477
|
-
// Payment functions
|
|
478
|
-
export {
|
|
479
|
-
parsePaymentRequirement,
|
|
480
|
-
parseAllPaymentRequirements,
|
|
481
|
-
signD402Payment,
|
|
482
|
-
encodePayment,
|
|
483
|
-
decodePayment
|
|
484
|
-
} from '@dcentralab/d402-client'
|
|
485
|
-
|
|
486
|
-
// Contract access
|
|
487
|
-
export {
|
|
488
|
-
ContractName,
|
|
489
|
-
getContractAddress,
|
|
490
|
-
getContractAbi,
|
|
491
|
-
getContractConfig
|
|
492
|
-
} from '@dcentralab/d402-client'
|
|
493
|
-
|
|
494
|
-
// Utilities
|
|
495
|
-
export {
|
|
496
|
-
parseMoney,
|
|
497
|
-
usdToUsdc,
|
|
498
|
-
generateNonce,
|
|
499
|
-
getChainId
|
|
500
|
-
} from '@dcentralab/d402-client'
|
|
501
|
-
|
|
502
|
-
// Error classes
|
|
503
|
-
export {
|
|
504
|
-
PaymentError,
|
|
505
|
-
PaymentAmountExceededError,
|
|
506
|
-
UnsupportedSchemeError,
|
|
507
|
-
Invalid402ResponseError
|
|
508
|
-
} from '@dcentralab/d402-client'
|
|
509
|
-
|
|
510
|
-
// Types
|
|
511
|
-
export type {
|
|
512
|
-
D402ClientConfig,
|
|
513
|
-
PaymentRequirement,
|
|
514
|
-
SignedPayment,
|
|
515
|
-
WalletCreationResult
|
|
516
|
-
} from '@dcentralab/d402-client'
|
|
517
|
-
```
|
|
80
|
+
> Additional networks (mainnet, Base, Polygon, etc.) will be supported once IATP contracts are deployed.
|
|
518
81
|
|
|
519
82
|
## ๐งช Testing
|
|
520
83
|
|
|
@@ -522,102 +85,44 @@ export type {
|
|
|
522
85
|
# Run all tests
|
|
523
86
|
pnpm test
|
|
524
87
|
|
|
525
|
-
# Run specific test file
|
|
526
|
-
pnpm test client.test.ts
|
|
527
|
-
|
|
528
88
|
# Run with coverage
|
|
529
89
|
pnpm test --coverage
|
|
530
90
|
|
|
531
|
-
#
|
|
532
|
-
pnpm
|
|
91
|
+
# Type check
|
|
92
|
+
pnpm typecheck
|
|
533
93
|
```
|
|
534
94
|
|
|
535
|
-
**Test Coverage:**
|
|
536
|
-
- โ
17 encoder/decoder tests
|
|
537
|
-
- โ
19 parser tests
|
|
538
|
-
- โ
29 contracts tests
|
|
539
|
-
- โ
24 signer tests
|
|
540
|
-
- โ
14 wallet tests
|
|
541
|
-
- โ
19 client constructor tests
|
|
542
|
-
- โ
22 integration tests
|
|
543
|
-
|
|
544
|
-
**Total: 144 tests**
|
|
545
|
-
|
|
546
|
-
## ๐ Security
|
|
95
|
+
**Test Coverage:** 166 tests covering client, wallet, payment, settlement, and integration scenarios.
|
|
547
96
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
**โ
Safe (Backend):**
|
|
551
|
-
```typescript
|
|
552
|
-
// Store operator key in environment variable
|
|
553
|
-
const operatorAccount = privateKeyToAccount(process.env.OPERATOR_KEY!)
|
|
554
|
-
```
|
|
555
|
-
|
|
556
|
-
**โ Unsafe (Frontend):**
|
|
557
|
-
```typescript
|
|
558
|
-
// Never hardcode private keys in frontend code
|
|
559
|
-
const account = privateKeyToAccount('0xHARDCODED') // DON'T DO THIS!
|
|
560
|
-
```
|
|
97
|
+
## ๐ฆ Package Exports
|
|
561
98
|
|
|
562
|
-
**โ
Safe (Frontend with Wallet):**
|
|
563
99
|
```typescript
|
|
564
|
-
//
|
|
565
|
-
|
|
566
|
-
const client = new D402Client({
|
|
567
|
-
operatorAccount: walletClient.account
|
|
568
|
-
})
|
|
569
|
-
```
|
|
570
|
-
|
|
571
|
-
### Payment Security
|
|
572
|
-
|
|
573
|
-
- โ
EIP-712 typed signatures prevent tampering
|
|
574
|
-
- โ
Nonce prevents replay attacks
|
|
575
|
-
- โ
Timestamp bounds (validAfter/validBefore)
|
|
576
|
-
- โ
Amount verification
|
|
577
|
-
- โ
Destination address verification
|
|
578
|
-
- โ
maxValue safety limit
|
|
579
|
-
|
|
580
|
-
## ๐ ๏ธ Development
|
|
581
|
-
|
|
582
|
-
### Build
|
|
583
|
-
|
|
584
|
-
```bash
|
|
585
|
-
pnpm build
|
|
586
|
-
```
|
|
100
|
+
// Main client
|
|
101
|
+
import { D402Client } from '@dcentralab/d402-client'
|
|
587
102
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
- `dist/index.mjs` - ES Module
|
|
591
|
-
- `dist/index.d.ts` - TypeScript types
|
|
103
|
+
// Wallet management
|
|
104
|
+
import { createIATPWallet, getWalletsByOwner, getAvailableBalance } from '@dcentralab/d402-client'
|
|
592
105
|
|
|
593
|
-
|
|
106
|
+
// Payment functions
|
|
107
|
+
import { signD402Payment, encodePayment, parsePaymentRequirement } from '@dcentralab/d402-client'
|
|
594
108
|
|
|
595
|
-
|
|
596
|
-
pnpm typecheck
|
|
109
|
+
// All exports documented in API Reference
|
|
597
110
|
```
|
|
598
111
|
|
|
599
|
-
##
|
|
600
|
-
|
|
601
|
-
Part of the IATP-JS monorepo:
|
|
602
|
-
- `@dcentralab/d402-client` - D402 payment protocol (this package)
|
|
603
|
-
- `@dcentralab/mcp-client` - MCP integration (planned)
|
|
604
|
-
- `@dcentralab/a2a-client` - A2A protocol (planned)
|
|
112
|
+
## ๐ค Contributing
|
|
605
113
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
- [Viem](https://viem.sh) - TypeScript Web3 library
|
|
609
|
-
- [D402 Protocol](https://docs.cdp.coinbase.com/x402) - HTTP 402 specification
|
|
114
|
+
We welcome contributions! See the [main Contributing Guide](../../docs/CONTRIBUTING.md).
|
|
610
115
|
|
|
611
116
|
## ๐ License
|
|
612
117
|
|
|
613
|
-
MIT
|
|
118
|
+
MIT License - see [LICENSE](../../LICENSE) file.
|
|
614
119
|
|
|
615
120
|
## ๐ฌ Support
|
|
616
121
|
|
|
617
|
-
-
|
|
618
|
-
-
|
|
122
|
+
- ๐ง Email: dev.support@d402.net
|
|
123
|
+
- ๐ Issues: [GitHub Issues](https://github.com/DcentraLab/iatp-js/issues)
|
|
124
|
+
- ๐ Docs: [Complete Documentation](./docs/)
|
|
619
125
|
|
|
620
126
|
---
|
|
621
127
|
|
|
622
128
|
**Made with โค๏ธ by the DcentraLab Team**
|
|
623
|
-
|