@dcentralab/d402-client 0.2.1 → 0.2.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/README.md +128 -68
- package/dist/index.d.mts +92 -94
- package/dist/index.d.ts +92 -94
- package/dist/index.js +23 -4149
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +24 -4150
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
**D402 Payment Protocol Client** for TypeScript/JavaScript
|
|
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
|
-
|
|
7
|
+
Part of the iatp-js monorepo. Future packages will add MCP and A2A protocol support.
|
|
8
|
+
|
|
9
|
+
Built by Dcentralab.
|
|
8
10
|
|
|
9
11
|
## 🚀 Installation
|
|
10
12
|
|
|
@@ -27,76 +29,143 @@ yarn add @dcentralab/d402-client viem wagmi
|
|
|
27
29
|
|
|
28
30
|
## 📖 Quick Start (React/Next.js)
|
|
29
31
|
|
|
30
|
-
|
|
32
|
+
## 💡 Complete React Example (Recommended Pattern)
|
|
31
33
|
|
|
32
|
-
|
|
34
|
+
### Custom Hook with Automatic Wallet Management
|
|
33
35
|
|
|
34
36
|
```typescript
|
|
35
37
|
'use client'
|
|
36
38
|
|
|
37
|
-
import {
|
|
39
|
+
import { useMutation } from '@tanstack/react-query'
|
|
38
40
|
import { useWalletClient } from 'wagmi'
|
|
39
|
-
import {
|
|
41
|
+
import {
|
|
42
|
+
createIATPWallet,
|
|
43
|
+
D402Client,
|
|
44
|
+
getWalletsByOwner
|
|
45
|
+
} from '@dcentralab/d402-client'
|
|
40
46
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
interface PaymentParams {
|
|
48
|
+
endpoint: string
|
|
49
|
+
payload: Record<string, unknown>
|
|
50
|
+
maxValue: bigint
|
|
51
|
+
network?: 'sepolia'
|
|
52
|
+
}
|
|
45
53
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
alert('Connect your wallet first!')
|
|
49
|
-
return
|
|
50
|
-
}
|
|
54
|
+
export function useD402Payment() {
|
|
55
|
+
const { data: walletClient } = useWalletClient()
|
|
51
56
|
|
|
52
|
-
|
|
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
|
+
})
|
|
53
73
|
|
|
54
|
-
|
|
55
|
-
|
|
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
|
|
56
90
|
const client = new D402Client({
|
|
57
91
|
operatorAccount: walletClient.account,
|
|
58
|
-
iatpWalletAddress
|
|
59
|
-
maxValue
|
|
92
|
+
iatpWalletAddress,
|
|
93
|
+
maxValue
|
|
60
94
|
})
|
|
61
95
|
|
|
62
|
-
// Call 402-protected API
|
|
63
|
-
const response = await client.fetch(
|
|
96
|
+
// Call 402-protected API
|
|
97
|
+
const response = await client.fetch(endpoint, {
|
|
64
98
|
method: 'POST',
|
|
65
99
|
headers: { 'Content-Type': 'application/json' },
|
|
66
|
-
body: JSON.stringify(
|
|
100
|
+
body: JSON.stringify(payload)
|
|
67
101
|
})
|
|
68
102
|
|
|
69
|
-
|
|
70
|
-
setResult(data)
|
|
71
|
-
|
|
72
|
-
} catch (error) {
|
|
73
|
-
console.error('Payment failed:', error)
|
|
74
|
-
} finally {
|
|
75
|
-
setLoading(false)
|
|
103
|
+
return await response.json()
|
|
76
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>
|
|
77
137
|
}
|
|
78
138
|
|
|
79
139
|
return (
|
|
80
140
|
<div>
|
|
81
|
-
<button onClick={
|
|
82
|
-
{
|
|
141
|
+
<button onClick={handleAnalyze} disabled={isLoading}>
|
|
142
|
+
{isLoading ? 'Processing...' : 'Analyze Sentiment (≈0.01 USDC)'}
|
|
83
143
|
</button>
|
|
84
|
-
|
|
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
|
+
)}
|
|
85
156
|
</div>
|
|
86
157
|
)
|
|
87
158
|
}
|
|
88
159
|
```
|
|
89
160
|
|
|
90
|
-
**
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
6. API returns data
|
|
97
|
-
7. User sees result
|
|
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
|
|
98
167
|
|
|
99
|
-
|
|
168
|
+
---
|
|
100
169
|
|
|
101
170
|
## 🏗️ Features
|
|
102
171
|
|
|
@@ -117,16 +186,17 @@ const result = await createIATPWallet({
|
|
|
117
186
|
rpcUrl: 'https://ethereum-sepolia-rpc.publicnode.com'
|
|
118
187
|
})
|
|
119
188
|
|
|
120
|
-
console.log('Wallet:', result.
|
|
121
|
-
console.log('
|
|
189
|
+
console.log('Wallet:', result.walletAddress)
|
|
190
|
+
console.log('Owner:', result.ownerAddress)
|
|
122
191
|
```
|
|
123
192
|
|
|
124
193
|
**Returns:**
|
|
125
|
-
- `
|
|
126
|
-
- `
|
|
127
|
-
- `operatorPrivateKey` - Operator's private key (store securely!)
|
|
194
|
+
- `walletAddress` - IATPWallet contract address
|
|
195
|
+
- `ownerAddress` - Owner's address (also the operator)
|
|
128
196
|
- `transactionHash` - Creation transaction
|
|
129
197
|
- `blockNumber` - Block where wallet was created
|
|
198
|
+
- `network` - Network where deployed
|
|
199
|
+
- `chainId` - Chain ID
|
|
130
200
|
|
|
131
201
|
### 2. Automatic 402 Payment Handling
|
|
132
202
|
|
|
@@ -137,8 +207,8 @@ const client = new D402Client({
|
|
|
137
207
|
operatorAccount,
|
|
138
208
|
iatpWalletAddress: '0xYourWallet...',
|
|
139
209
|
maxValue: 1000000n,
|
|
140
|
-
networkFilter: '
|
|
141
|
-
schemeFilter: 'exact'
|
|
210
|
+
networkFilter: 'sepolia', // Only Sepolia network
|
|
211
|
+
schemeFilter: 'exact' // Only exact payments
|
|
142
212
|
})
|
|
143
213
|
|
|
144
214
|
// Client automatically:
|
|
@@ -242,10 +312,9 @@ Get maximum payment limit.
|
|
|
242
312
|
Create new IATPWallet contract on-chain.
|
|
243
313
|
|
|
244
314
|
**Parameters:**
|
|
245
|
-
- `ownerAccount: Account` - Owner's viem account
|
|
246
|
-
- `network?: 'sepolia'
|
|
315
|
+
- `ownerAccount: Account` - Owner's viem account (will also be the operator)
|
|
316
|
+
- `network?: 'sepolia'` - Network (default: sepolia)
|
|
247
317
|
- `rpcUrl?: string` - Custom RPC URL
|
|
248
|
-
- `operatorPrivateKey?: 0x${string}` - Use specific operator key
|
|
249
318
|
|
|
250
319
|
**`parsePaymentRequirement(response): Promise<PaymentRequirement>`**
|
|
251
320
|
|
|
@@ -382,27 +451,19 @@ const response = await fetch('/api/analyze', {
|
|
|
382
451
|
})
|
|
383
452
|
```
|
|
384
453
|
|
|
385
|
-
**Flow:** Browser → Your Backend → D402Client → External 402 API
|
|
386
|
-
|
|
387
|
-
**Pros:**
|
|
388
|
-
- ✅ Simpler frontend (no wallet needed)
|
|
389
|
-
- ✅ Smooth UX (no wallet popups)
|
|
390
|
-
|
|
391
454
|
**Cons:**
|
|
392
455
|
- ⚠️ Backend controls payments
|
|
393
456
|
- ⚠️ More centralized
|
|
394
457
|
|
|
395
458
|
## 🌐 Supported Networks
|
|
396
459
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
|
400
|
-
|
|
401
|
-
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
| Arbitrum One | 42161 | `0xaf88d065e77c8cC2239327C5EDb3A432268e5831` |
|
|
405
|
-
| Arbitrum Sepolia | 421614 | `0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d` |
|
|
460
|
+
IATP contracts are currently deployed on:
|
|
461
|
+
|
|
462
|
+
| Network | Type | Chain ID | USDC Address | RPC URL |
|
|
463
|
+
|----------------------|---------|------------|----------------------------------------------|---------------------------------------------------|
|
|
464
|
+
| **Sepolia Testnet** | Testnet | `11155111` | `0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238` | [Chainlist](https://chainlist.org/chain/11155111) |
|
|
465
|
+
|
|
466
|
+
> **Note:** Additional networks (mainnet, Base, Polygon, etc.) will be supported once IATP contracts are deployed on those chains.
|
|
406
467
|
|
|
407
468
|
## 📦 Package Exports
|
|
408
469
|
|
|
@@ -544,7 +605,6 @@ Part of the IATP-JS monorepo:
|
|
|
544
605
|
|
|
545
606
|
## 🔗 Related Projects
|
|
546
607
|
|
|
547
|
-
- [IATP Python](https://github.com/Traia-IO/IATP) - Python implementation
|
|
548
608
|
- [Viem](https://viem.sh) - TypeScript Web3 library
|
|
549
609
|
- [D402 Protocol](https://docs.cdp.coinbase.com/x402) - HTTP 402 specification
|
|
550
610
|
|