@payroute/x402-sdk 1.0.0 → 1.0.1

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 CHANGED
@@ -6,16 +6,16 @@ This SDK abstracts the complexity of **HTTP 402 Pay-Per-Hit** workflows, enablin
6
6
 
7
7
  ## Features
8
8
 
9
- - 🚀 **Full x402 Abstraction**: Automates the HTTP 402 -> Payment -> Retry loop.
10
- - 💸 **Mantle Network Support**: Built for Mantle Mainnet and Sepolia Testnet.
11
- - 🤖 **AI Agent Ready**: Dedicated methods for interacting with Payroute-enabled AI Agents.
12
- - 📦 **Token Management**: Automatically handles ERC20 (MUSD) approvals and transfers.
13
- - 🛡️ **Type-Safe**: Written in TypeScript with full type definitions.
9
+ - **Full x402 Abstraction**: Automates the HTTP 402 -> Payment -> Retry loop.
10
+ - **Mantle Network Support**: Built for Mantle Mainnet and Sepolia Testnet.
11
+ - **AI Agent Ready**: Dedicated methods for interacting with Payroute-enabled AI Agents.
12
+ - **Token Management**: Automatically handles ERC20 (MUSD) approvals and transfers.
13
+ - **Type-Safe**: Written in TypeScript with full type definitions.
14
14
 
15
15
  ## Installation
16
16
 
17
17
  ```bash
18
- npm install payroute-x402-sdk ethers
18
+ npm install @payroute/x402-sdk ethers
19
19
  ```
20
20
 
21
21
  _Note: `ethers` peer dependency (v6) is required._
@@ -25,7 +25,7 @@ _Note: `ethers` peer dependency (v6) is required._
25
25
  ### 1. Initialize the Service
26
26
 
27
27
  ```typescript
28
- import { PaymentService } from "payroute-x402-sdk";
28
+ import { PaymentService } from "@payroute/x402-sdk";
29
29
 
30
30
  const service = new PaymentService({
31
31
  privateKey: process.env.WALLET_PRIVATE_KEY, // Your EVM private key
@@ -37,31 +37,61 @@ const service = new PaymentService({
37
37
 
38
38
  Access premium content served behind a Payroute gateway.
39
39
 
40
+ #### Direct Payment (Non-Escrow)
41
+
42
+ Use this method for direct peer-to-peer payments to a receiver.
43
+
40
44
  ```typescript
41
45
  try {
42
- const content = await service.getProxyEndpoint("my-premium-blog-post");
46
+ const content = await service.getProxyEndpoint("test09");
43
47
  console.log("Accessed Content:", content);
44
48
  } catch (error) {
45
49
  console.error("Payment or Fetch Failed:", error);
46
50
  }
47
51
  ```
48
52
 
53
+ #### Escrow Payment
54
+
55
+ Use this method when the gateway requires payment via an escrow smart contract.
56
+
57
+ ```typescript
58
+ try {
59
+ const contentStart = await service.getProxyEndpointEscrow("test09");
60
+ console.log("Accessed Escrow Content:", contentStart);
61
+ } catch (error) {
62
+ console.error("Payment or Fetch Failed:", error);
63
+ }
64
+ ```
65
+
49
66
  ### 3. Interact with a Paid AI Agent
50
67
 
51
68
  Send messages to an AI agent that requires per-message payments.
52
69
 
70
+ #### Direct Payment (Non-Escrow)
71
+
53
72
  ```typescript
54
73
  try {
55
- const response = await service.generateAIResponse(
56
- "finance-advisor-agent",
57
- "What is the outlook for MNT?"
58
- );
74
+ const response = await service.generateAIResponse("agentTest1", "Hello");
59
75
  console.log("AI Response:", response);
60
76
  } catch (error) {
61
77
  console.error("Agent Interaction Failed:", error);
62
78
  }
63
79
  ```
64
80
 
81
+ #### Escrow Payment
82
+
83
+ ```typescript
84
+ try {
85
+ const responseEscrow = await service.generateAIResponseEscrow(
86
+ "agentTest1",
87
+ "Hello"
88
+ );
89
+ console.log("AI Response Escrow:", responseEscrow);
90
+ } catch (error) {
91
+ console.error("Agent Interaction Failed:", error);
92
+ }
93
+ ```
94
+
65
95
  ## Advanced Usage
66
96
 
67
97
  ### Custom RPC Provider
@@ -75,32 +105,16 @@ const service = new PaymentService({
75
105
  });
76
106
  ```
77
107
 
78
- ### Generic Pay-And-Retry
79
-
80
- If you are building a custom integration that follows the x402 generic pattern but doesn't fit the standard gateway/agent flow, you can use the low-level `payAndRetry` method.
81
-
82
- ```typescript
83
- const response = await service.payAndRetry({
84
- paymentData: {
85
- amount: "1000000000000000000", // 1 ETH/MNT in wei
86
- recipient: "0x123...",
87
- },
88
- retryRequest: async (headers) => {
89
- // Perform your custom retry logic here using the provided headers
90
- // headers['X-Payment-Tx'] will contain the transaction hash
91
- return fetch("https://api.custom.com/resource", { headers });
92
- },
93
- });
94
- ```
95
-
96
108
  ## Architecture
97
109
 
98
110
  The SDK implements the **Payroute x402 Protocol**:
99
111
 
100
112
  1. **Request**: SDK attempts to access a resource.
101
- 2. **Challenge (402)**: Server responds with `402 Payment Required` and payment details (Escrow contract, Amount, Transaction ID).
102
- 3. **Approval**: SDK approves the required token (MUSD) for the escrow contract.
103
- 4. **Payment**: SDK calls the Escrow contract's `createTx` function.
113
+ 2. **Challenge (402)**: Server responds with `402 Payment Required` and payment details (Receiver Address, Amount, Transaction ID, and optionally Escrow Address).
114
+ 3. **Approval (If needed)**: SDK approves the required token (MUSD) for the escrow contract or spends directly.
115
+ 4. **Payment**:
116
+ - **Direct**: Transfers MUSD directly to the receiver.
117
+ - **Escrow**: Calls the Escrow contract's `createTx` function.
104
118
  5. **Confirmation**: SDK waits for blockchain confirmation.
105
119
  6. **Retry**: SDK retries the original request with the transaction hash in the `x-payment-tx` header.
106
120
  7. **Response**: Server validates the transaction and returns the content.
package/dist/index.d.mts CHANGED
@@ -29,10 +29,6 @@ declare class PaymentService {
29
29
  * @param params.retryRequest - A callback that performs the HTTP request. Must accept headers.
30
30
  * @returns The response from the retried request.
31
31
  */
32
- payAndRetry<T>(params: {
33
- paymentData: PaymentData;
34
- retryRequest: (headers: Record<string, string>) => Promise<T>;
35
- }): Promise<T>;
36
32
  /**
37
33
  * Get AI response
38
34
  *
@@ -40,6 +36,13 @@ declare class PaymentService {
40
36
  * @returns
41
37
  */
42
38
  generateAIResponse<T = any>(agentSlug: string, message: string): Promise<T>;
39
+ /**
40
+ * Get AI response
41
+ *
42
+ * @param agentSlug
43
+ * @returns
44
+ */
45
+ generateAIResponseEscrow<T = any>(agentSlug: string, message: string): Promise<T>;
43
46
  /**
44
47
  * Get proxy endpoint
45
48
  *
@@ -47,6 +50,13 @@ declare class PaymentService {
47
50
  * @returns
48
51
  */
49
52
  getProxyEndpoint<T = any>(gatewaySlug: string): Promise<T>;
53
+ /**
54
+ * Get proxy endpoint escrow
55
+ *
56
+ * @param gatewaySlug
57
+ * @returns
58
+ */
59
+ getProxyEndpointEscrow<T = any>(gatewaySlug: string): Promise<T>;
50
60
  /**
51
61
  * Helper to get the current wallet address
52
62
  */
package/dist/index.d.ts CHANGED
@@ -29,10 +29,6 @@ declare class PaymentService {
29
29
  * @param params.retryRequest - A callback that performs the HTTP request. Must accept headers.
30
30
  * @returns The response from the retried request.
31
31
  */
32
- payAndRetry<T>(params: {
33
- paymentData: PaymentData;
34
- retryRequest: (headers: Record<string, string>) => Promise<T>;
35
- }): Promise<T>;
36
32
  /**
37
33
  * Get AI response
38
34
  *
@@ -40,6 +36,13 @@ declare class PaymentService {
40
36
  * @returns
41
37
  */
42
38
  generateAIResponse<T = any>(agentSlug: string, message: string): Promise<T>;
39
+ /**
40
+ * Get AI response
41
+ *
42
+ * @param agentSlug
43
+ * @returns
44
+ */
45
+ generateAIResponseEscrow<T = any>(agentSlug: string, message: string): Promise<T>;
43
46
  /**
44
47
  * Get proxy endpoint
45
48
  *
@@ -47,6 +50,13 @@ declare class PaymentService {
47
50
  * @returns
48
51
  */
49
52
  getProxyEndpoint<T = any>(gatewaySlug: string): Promise<T>;
53
+ /**
54
+ * Get proxy endpoint escrow
55
+ *
56
+ * @param gatewaySlug
57
+ * @returns
58
+ */
59
+ getProxyEndpointEscrow<T = any>(gatewaySlug: string): Promise<T>;
50
60
  /**
51
61
  * Helper to get the current wallet address
52
62
  */
package/dist/index.js CHANGED
@@ -43,13 +43,14 @@ var NETWORKS = {
43
43
  chainId: 31337
44
44
  }
45
45
  };
46
- var BASE_ENDPOINT = "https://x402-services.vercel.app";
46
+ var BASE_ENDPOINT = "http://localhost:3000";
47
47
  var ESCROW_ABI = [
48
- "function createTx(string txId, address creator, uint256 amount) external payable"
48
+ "function createTx(bytes32 txId, address creator, uint256 amount)"
49
49
  ];
50
50
  var MUSD_ADDRESS = "0x4dABf45C8cF333Ef1e874c3FDFC3C86799af80c8";
51
51
  var ERC20_ABI = [
52
- "function approve(address spender, uint256 amount) external returns (bool)"
52
+ "function approve(address spender, uint256 amount) external returns (bool)",
53
+ "function transfer(address to, uint256 amount) external returns (bool)"
53
54
  ];
54
55
  var PaymentService = class {
55
56
  wallet;
@@ -75,43 +76,120 @@ var PaymentService = class {
75
76
  * @param params.retryRequest - A callback that performs the HTTP request. Must accept headers.
76
77
  * @returns The response from the retried request.
77
78
  */
78
- async payAndRetry(params) {
79
- const { paymentData, retryRequest } = params;
79
+ // async payAndRetry<T>(params: {
80
+ // paymentData: PaymentData;
81
+ // retryRequest: (headers: Record<string, string>) => Promise<T>;
82
+ // }): Promise<T> {
83
+ // const { paymentData, retryRequest } = params;
84
+ // try {
85
+ // // 1. Validate Payment Data
86
+ // if (!ethers.isAddress(paymentData.recipient)) {
87
+ // throw new Error(`Invalid recipient address: ${paymentData.recipient}`);
88
+ // }
89
+ // // 2. Build Transaction
90
+ // const txRequest = {
91
+ // to: paymentData.recipient,
92
+ // value: BigInt(paymentData.amount),
93
+ // // Gas limit/price will be estimated by provider/wallet
94
+ // };
95
+ // // 3. Sign & Send Transaction
96
+ // // console.log(`Sending payment of ${paymentData.amount} wei to ${paymentData.recipient}...`);
97
+ // const txResponse = await this.wallet.sendTransaction(txRequest);
98
+ // // 4. Wait for confirmation
99
+ // // console.log(`Transaction sent: ${txResponse.hash}. Waiting for confirmation...`);
100
+ // const receipt = await txResponse.wait(1); // Wait for 1 confirmation
101
+ // if (!receipt || receipt.status !== 1) {
102
+ // throw new Error('Transaction failed or was reverted on-chain.');
103
+ // }
104
+ // // 5. Retry original request with header X-Payment-Tx
105
+ // const txHash = receipt.hash;
106
+ // const headers = {
107
+ // 'X-Payment-Tx': txHash,
108
+ // 'Content-Type': 'application/json', // Default content type, extendable if needed
109
+ // };
110
+ // // 6. Return final HTTP response
111
+ // return await retryRequest(headers);
112
+ // } catch (error: any) {
113
+ // // 7. Throw clear errors on failure
114
+ // const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred during payment flow';
115
+ // // console.error('PaymentService Error:', errorMessage);
116
+ // throw new Error(`PaymentService Failed: ${errorMessage}`);
117
+ // }
118
+ // }
119
+ /**
120
+ * Get AI response
121
+ *
122
+ * @param agentSlug
123
+ * @returns
124
+ */
125
+ async generateAIResponse(agentSlug, message) {
80
126
  try {
81
- if (!import_ethers.ethers.isAddress(paymentData.recipient)) {
82
- throw new Error(`Invalid recipient address: ${paymentData.recipient}`);
127
+ const initialResponse = await fetch(`${BASE_ENDPOINT}/agent/${agentSlug}/chat`, {
128
+ method: "POST",
129
+ headers: {
130
+ "Content-Type": "application/json"
131
+ },
132
+ body: JSON.stringify({
133
+ message
134
+ })
135
+ });
136
+ if (!initialResponse.ok && initialResponse.status !== 402) {
137
+ throw new Error(`Unexpected status code: ${initialResponse.status}`);
83
138
  }
84
- const txRequest = {
85
- to: paymentData.recipient,
86
- value: BigInt(paymentData.amount)
87
- // Gas limit/price will be estimated by provider/wallet
88
- };
89
- const txResponse = await this.wallet.sendTransaction(txRequest);
139
+ const paymentDetail = await initialResponse.json();
140
+ if (!paymentDetail) {
141
+ throw new Error("Payment detail not found in response.");
142
+ }
143
+ const txId = paymentDetail.transactionId;
144
+ const amountPayment = paymentDetail.amount;
145
+ const receiverAddress = paymentDetail.receiverAddress;
146
+ const amount = import_ethers.ethers.parseUnits(amountPayment.toString(), 6);
147
+ if (!receiverAddress) {
148
+ throw new Error("Receiver address not found in payment details.");
149
+ }
150
+ const musdContract = new import_ethers.ethers.Contract(MUSD_ADDRESS, ERC20_ABI, this.wallet);
151
+ console.log(`Approving MUSD spending for ${receiverAddress}...`);
152
+ const approveTx = await musdContract.approve(receiverAddress, amount);
153
+ await approveTx.wait(1);
154
+ console.log(`Initiating Expect Payment to creator ${receiverAddress} (${amount} wei)`);
155
+ const txResponse = await musdContract.transfer(receiverAddress, amount);
156
+ console.log(`Payment sent: ${txResponse.hash}. Waiting for confirmation...`);
90
157
  const receipt = await txResponse.wait(1);
91
158
  if (!receipt || receipt.status !== 1) {
92
- throw new Error("Transaction failed or was reverted on-chain.");
159
+ throw new Error("Payment transaction failed.");
93
160
  }
94
- const txHash = receipt.hash;
161
+ const finalTxHash = receipt.hash;
95
162
  const headers = {
96
- "X-Payment-Tx": txHash,
97
- "Content-Type": "application/json"
98
- // Default content type, extendable if needed
163
+ "Content-Type": "application/json",
164
+ "x-payment-tx": finalTxHash
99
165
  };
100
- return await retryRequest(headers);
166
+ console.log(`Retry with txHash: ${finalTxHash}`);
167
+ const retryResponse = await fetch(`${BASE_ENDPOINT}/agent/${agentSlug}/chat`, {
168
+ method: "POST",
169
+ headers,
170
+ body: JSON.stringify({
171
+ message
172
+ })
173
+ });
174
+ if (!retryResponse.ok) {
175
+ const errorText = await retryResponse.text();
176
+ throw new Error(`Retry failed: ${retryResponse.status} - ${errorText}`);
177
+ }
178
+ return await retryResponse.json();
101
179
  } catch (error) {
102
180
  const errorMessage = error instanceof Error ? error.message : "Unknown error occurred during payment flow";
103
181
  throw new Error(`PaymentService Failed: ${errorMessage}`);
104
182
  }
105
183
  }
106
184
  /**
107
- * Get AI response
108
- *
109
- * @param agentSlug
110
- * @returns
111
- */
112
- async generateAIResponse(agentSlug, message) {
185
+ * Get AI response
186
+ *
187
+ * @param agentSlug
188
+ * @returns
189
+ */
190
+ async generateAIResponseEscrow(agentSlug, message) {
113
191
  try {
114
- const initialResponse = await fetch(`${BASE_ENDPOINT}/agent/${agentSlug}/chat`, {
192
+ const initialResponse = await fetch(`${BASE_ENDPOINT}/agent/escrow/${agentSlug}/chat`, {
115
193
  method: "POST",
116
194
  headers: {
117
195
  "Content-Type": "application/json"
@@ -124,32 +202,41 @@ var PaymentService = class {
124
202
  throw new Error(`Unexpected status code: ${initialResponse.status}`);
125
203
  }
126
204
  const paymentDetail = await initialResponse.json();
205
+ if (!paymentDetail) {
206
+ throw new Error("Payment detail not found in response.");
207
+ }
127
208
  const txId = paymentDetail.transactionId;
128
209
  const escrowAddress = paymentDetail.escrowAddress;
129
- const amountPayment = paymentDetail.amountPayment;
130
- const contractAddress = paymentDetail.contractAddress;
131
- if (!contractAddress) {
132
- throw new Error("Contract address not found in payment details.");
210
+ const amountPayment = paymentDetail.amount;
211
+ const receiverAddress = paymentDetail.receiverAddress;
212
+ const amount = import_ethers.ethers.parseUnits(amountPayment.toString(), 6);
213
+ if (!receiverAddress) {
214
+ throw new Error("Receiver address not found in payment details.");
133
215
  }
134
216
  const musdContract = new import_ethers.ethers.Contract(MUSD_ADDRESS, ERC20_ABI, this.wallet);
135
- const approveTx = await musdContract.approve(contractAddress, amountPayment);
217
+ console.log(`Approving MUSD spending for ${escrowAddress}...`);
218
+ const approveTx = await musdContract.approve(escrowAddress, amount);
136
219
  await approveTx.wait(1);
137
- const contract = new import_ethers.ethers.Contract(contractAddress, ESCROW_ABI, this.wallet);
220
+ console.log(`Initiating Expect Payment to ${escrowAddress} for creator ${receiverAddress} (${amount} wei)`);
221
+ const contract = new import_ethers.ethers.Contract(escrowAddress, ESCROW_ABI, this.wallet);
138
222
  const txResponse = await contract.createTx(
139
223
  txId,
140
- escrowAddress,
141
- amountPayment
224
+ receiverAddress,
225
+ amount
142
226
  );
227
+ console.log(`Escrow payment sent: ${txResponse.hash}. Waiting for confirmation...`);
143
228
  const receipt = await txResponse.wait(1);
144
229
  if (!receipt || receipt.status !== 1) {
145
230
  throw new Error("Escrow transaction failed.");
146
231
  }
147
232
  const finalTxHash = receipt.hash;
148
233
  const headers = {
149
- "x-payment-tx": finalTxHash,
150
- "Content-Type": "application/json"
234
+ "Content-Type": "application/json",
235
+ "Accept": "application/json",
236
+ "x-payment-tx": finalTxHash
151
237
  };
152
- const retryResponse = await fetch(`${BASE_ENDPOINT}/agent/${agentSlug}/chat`, {
238
+ console.log(`Retry with txHash: ${finalTxHash}`);
239
+ const retryResponse = await fetch(`${BASE_ENDPOINT}/agent/escrow/${agentSlug}/chat`, {
153
240
  method: "POST",
154
241
  headers,
155
242
  body: JSON.stringify({
@@ -174,7 +261,12 @@ var PaymentService = class {
174
261
  */
175
262
  async getProxyEndpoint(gatewaySlug) {
176
263
  try {
177
- const initialResponse = await fetch(`${BASE_ENDPOINT}/escrow/${gatewaySlug}`);
264
+ let initialResponse;
265
+ try {
266
+ initialResponse = await fetch(`${BASE_ENDPOINT}/${gatewaySlug}`);
267
+ } catch (e) {
268
+ throw new Error(`Initial Endpoint Failed: ${e}`);
269
+ }
178
270
  if (initialResponse.ok) {
179
271
  return await initialResponse.json();
180
272
  }
@@ -182,32 +274,98 @@ var PaymentService = class {
182
274
  throw new Error(`Unexpected status code: ${initialResponse.status}`);
183
275
  }
184
276
  const paymentDetail = await initialResponse.json();
277
+ if (!paymentDetail) {
278
+ throw new Error("Payment Detail not found.");
279
+ }
280
+ console.log("Payment Detail:", paymentDetail);
281
+ const amountPayment = paymentDetail.amount;
282
+ const receiverAddress = paymentDetail.receiverAddress;
283
+ const amount = import_ethers.ethers.parseUnits(amountPayment.toString(), 6);
284
+ if (!receiverAddress) {
285
+ throw new Error("Receiver address not found in payment details.");
286
+ }
287
+ const musdContract = new import_ethers.ethers.Contract(MUSD_ADDRESS, ERC20_ABI, this.wallet);
288
+ console.log(`Initiating Expect Payment to ${receiverAddress} (${amount} wei)`);
289
+ const txResponse = await musdContract.transfer(receiverAddress, amount);
290
+ console.log(`Payment sent: ${txResponse.hash}. Waiting for confirmation...`);
291
+ const receipt = await txResponse.wait(1);
292
+ if (!receipt || receipt.status !== 1) {
293
+ throw new Error("Payment transaction failed.");
294
+ }
295
+ const finalTxHash = receipt.hash;
296
+ const headers = {
297
+ "x-payment-tx": finalTxHash
298
+ };
299
+ console.log("view header: ", headers);
300
+ const retryResponse = await fetch(`${BASE_ENDPOINT}/${gatewaySlug}`, {
301
+ method: "GET",
302
+ headers
303
+ });
304
+ if (!retryResponse.ok) {
305
+ const errorText = await retryResponse.text();
306
+ throw new Error(`Retry failed: ${retryResponse.status} - ${errorText}`);
307
+ }
308
+ return await retryResponse.json();
309
+ } catch (error) {
310
+ const errorMessage = error instanceof Error ? error : "Unknown error in getProxyEndpoint";
311
+ throw new Error(`Proxy Endpoint Failed: ${errorMessage}`);
312
+ }
313
+ }
314
+ /**
315
+ * Get proxy endpoint escrow
316
+ *
317
+ * @param gatewaySlug
318
+ * @returns
319
+ */
320
+ async getProxyEndpointEscrow(gatewaySlug) {
321
+ try {
322
+ let initialResponse;
323
+ try {
324
+ initialResponse = await fetch(`${BASE_ENDPOINT}/escrow/${gatewaySlug}`);
325
+ } catch (e) {
326
+ throw new Error(`Initial Endpoint Failed: ${e}`);
327
+ }
328
+ if (initialResponse.ok) {
329
+ return await initialResponse.json();
330
+ }
331
+ if (initialResponse.status !== 402) {
332
+ throw new Error(`Unexpected status code: ${initialResponse.status}`);
333
+ }
334
+ const paymentDetail = await initialResponse.json();
335
+ if (!paymentDetail) {
336
+ throw new Error("Payment Detail not found.");
337
+ }
338
+ console.log("Payment Detail:", paymentDetail);
185
339
  const txId = paymentDetail.transactionId;
186
340
  const escrowAddress = paymentDetail.escrowAddress;
187
- const amountPayment = paymentDetail.amountPayment;
188
- const contractAddress = paymentDetail.contractAddress;
189
- if (!contractAddress) {
190
- throw new Error("Contract address not found in payment details.");
341
+ const amountPayment = paymentDetail.amount;
342
+ const receiverAddress = paymentDetail.receiverAddress;
343
+ const amount = import_ethers.ethers.parseUnits(amountPayment.toString(), 6);
344
+ if (!receiverAddress) {
345
+ throw new Error("Receiver address not found in payment details.");
191
346
  }
192
347
  const musdContract = new import_ethers.ethers.Contract(MUSD_ADDRESS, ERC20_ABI, this.wallet);
193
- const approveTx = await musdContract.approve(contractAddress, amountPayment);
348
+ console.log(`Approving MUSD spending for ${escrowAddress}`);
349
+ const approveTx = await musdContract.approve(escrowAddress, amount);
194
350
  await approveTx.wait(1);
195
- const contract = new import_ethers.ethers.Contract(contractAddress, ESCROW_ABI, this.wallet);
351
+ console.log(`Initiating Expect Payment to ${escrowAddress} for creator ${receiverAddress} (${amount} wei)`);
352
+ const contract = new import_ethers.ethers.Contract(escrowAddress, ESCROW_ABI, this.wallet);
196
353
  const txResponse = await contract.createTx(
197
354
  txId,
198
- escrowAddress,
199
- amountPayment
355
+ receiverAddress,
356
+ amount
200
357
  );
358
+ console.log(`Escrow payment sent: ${txResponse.hash}. Waiting for confirmation...`);
201
359
  const receipt = await txResponse.wait(1);
202
360
  if (!receipt || receipt.status !== 1) {
203
361
  throw new Error("Escrow transaction failed.");
204
362
  }
205
363
  const finalTxHash = receipt.hash;
206
364
  const headers = {
207
- "x-payment-tx": finalTxHash,
208
- "Content-Type": "application/json"
365
+ "x-payment-tx": finalTxHash
209
366
  };
210
- const retryResponse = await fetch(`${BASE_ENDPOINT}/${gatewaySlug}`, {
367
+ console.log("view header: ", headers);
368
+ const retryResponse = await fetch(`${BASE_ENDPOINT}/escrow/${gatewaySlug}`, {
211
369
  method: "GET",
212
370
  headers
213
371
  });
@@ -217,7 +375,7 @@ var PaymentService = class {
217
375
  }
218
376
  return await retryResponse.json();
219
377
  } catch (error) {
220
- const errorMessage = error instanceof Error ? error.message : "Unknown error in getProxyEndpoint";
378
+ const errorMessage = error instanceof Error ? error : "Unknown error in getProxyEndpoint";
221
379
  throw new Error(`Proxy Endpoint Failed: ${errorMessage}`);
222
380
  }
223
381
  }
package/dist/index.mjs CHANGED
@@ -17,13 +17,14 @@ var NETWORKS = {
17
17
  chainId: 31337
18
18
  }
19
19
  };
20
- var BASE_ENDPOINT = "https://x402-services.vercel.app";
20
+ var BASE_ENDPOINT = "http://localhost:3000";
21
21
  var ESCROW_ABI = [
22
- "function createTx(string txId, address creator, uint256 amount) external payable"
22
+ "function createTx(bytes32 txId, address creator, uint256 amount)"
23
23
  ];
24
24
  var MUSD_ADDRESS = "0x4dABf45C8cF333Ef1e874c3FDFC3C86799af80c8";
25
25
  var ERC20_ABI = [
26
- "function approve(address spender, uint256 amount) external returns (bool)"
26
+ "function approve(address spender, uint256 amount) external returns (bool)",
27
+ "function transfer(address to, uint256 amount) external returns (bool)"
27
28
  ];
28
29
  var PaymentService = class {
29
30
  wallet;
@@ -49,43 +50,120 @@ var PaymentService = class {
49
50
  * @param params.retryRequest - A callback that performs the HTTP request. Must accept headers.
50
51
  * @returns The response from the retried request.
51
52
  */
52
- async payAndRetry(params) {
53
- const { paymentData, retryRequest } = params;
53
+ // async payAndRetry<T>(params: {
54
+ // paymentData: PaymentData;
55
+ // retryRequest: (headers: Record<string, string>) => Promise<T>;
56
+ // }): Promise<T> {
57
+ // const { paymentData, retryRequest } = params;
58
+ // try {
59
+ // // 1. Validate Payment Data
60
+ // if (!ethers.isAddress(paymentData.recipient)) {
61
+ // throw new Error(`Invalid recipient address: ${paymentData.recipient}`);
62
+ // }
63
+ // // 2. Build Transaction
64
+ // const txRequest = {
65
+ // to: paymentData.recipient,
66
+ // value: BigInt(paymentData.amount),
67
+ // // Gas limit/price will be estimated by provider/wallet
68
+ // };
69
+ // // 3. Sign & Send Transaction
70
+ // // console.log(`Sending payment of ${paymentData.amount} wei to ${paymentData.recipient}...`);
71
+ // const txResponse = await this.wallet.sendTransaction(txRequest);
72
+ // // 4. Wait for confirmation
73
+ // // console.log(`Transaction sent: ${txResponse.hash}. Waiting for confirmation...`);
74
+ // const receipt = await txResponse.wait(1); // Wait for 1 confirmation
75
+ // if (!receipt || receipt.status !== 1) {
76
+ // throw new Error('Transaction failed or was reverted on-chain.');
77
+ // }
78
+ // // 5. Retry original request with header X-Payment-Tx
79
+ // const txHash = receipt.hash;
80
+ // const headers = {
81
+ // 'X-Payment-Tx': txHash,
82
+ // 'Content-Type': 'application/json', // Default content type, extendable if needed
83
+ // };
84
+ // // 6. Return final HTTP response
85
+ // return await retryRequest(headers);
86
+ // } catch (error: any) {
87
+ // // 7. Throw clear errors on failure
88
+ // const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred during payment flow';
89
+ // // console.error('PaymentService Error:', errorMessage);
90
+ // throw new Error(`PaymentService Failed: ${errorMessage}`);
91
+ // }
92
+ // }
93
+ /**
94
+ * Get AI response
95
+ *
96
+ * @param agentSlug
97
+ * @returns
98
+ */
99
+ async generateAIResponse(agentSlug, message) {
54
100
  try {
55
- if (!ethers.isAddress(paymentData.recipient)) {
56
- throw new Error(`Invalid recipient address: ${paymentData.recipient}`);
101
+ const initialResponse = await fetch(`${BASE_ENDPOINT}/agent/${agentSlug}/chat`, {
102
+ method: "POST",
103
+ headers: {
104
+ "Content-Type": "application/json"
105
+ },
106
+ body: JSON.stringify({
107
+ message
108
+ })
109
+ });
110
+ if (!initialResponse.ok && initialResponse.status !== 402) {
111
+ throw new Error(`Unexpected status code: ${initialResponse.status}`);
57
112
  }
58
- const txRequest = {
59
- to: paymentData.recipient,
60
- value: BigInt(paymentData.amount)
61
- // Gas limit/price will be estimated by provider/wallet
62
- };
63
- const txResponse = await this.wallet.sendTransaction(txRequest);
113
+ const paymentDetail = await initialResponse.json();
114
+ if (!paymentDetail) {
115
+ throw new Error("Payment detail not found in response.");
116
+ }
117
+ const txId = paymentDetail.transactionId;
118
+ const amountPayment = paymentDetail.amount;
119
+ const receiverAddress = paymentDetail.receiverAddress;
120
+ const amount = ethers.parseUnits(amountPayment.toString(), 6);
121
+ if (!receiverAddress) {
122
+ throw new Error("Receiver address not found in payment details.");
123
+ }
124
+ const musdContract = new ethers.Contract(MUSD_ADDRESS, ERC20_ABI, this.wallet);
125
+ console.log(`Approving MUSD spending for ${receiverAddress}...`);
126
+ const approveTx = await musdContract.approve(receiverAddress, amount);
127
+ await approveTx.wait(1);
128
+ console.log(`Initiating Expect Payment to creator ${receiverAddress} (${amount} wei)`);
129
+ const txResponse = await musdContract.transfer(receiverAddress, amount);
130
+ console.log(`Payment sent: ${txResponse.hash}. Waiting for confirmation...`);
64
131
  const receipt = await txResponse.wait(1);
65
132
  if (!receipt || receipt.status !== 1) {
66
- throw new Error("Transaction failed or was reverted on-chain.");
133
+ throw new Error("Payment transaction failed.");
67
134
  }
68
- const txHash = receipt.hash;
135
+ const finalTxHash = receipt.hash;
69
136
  const headers = {
70
- "X-Payment-Tx": txHash,
71
- "Content-Type": "application/json"
72
- // Default content type, extendable if needed
137
+ "Content-Type": "application/json",
138
+ "x-payment-tx": finalTxHash
73
139
  };
74
- return await retryRequest(headers);
140
+ console.log(`Retry with txHash: ${finalTxHash}`);
141
+ const retryResponse = await fetch(`${BASE_ENDPOINT}/agent/${agentSlug}/chat`, {
142
+ method: "POST",
143
+ headers,
144
+ body: JSON.stringify({
145
+ message
146
+ })
147
+ });
148
+ if (!retryResponse.ok) {
149
+ const errorText = await retryResponse.text();
150
+ throw new Error(`Retry failed: ${retryResponse.status} - ${errorText}`);
151
+ }
152
+ return await retryResponse.json();
75
153
  } catch (error) {
76
154
  const errorMessage = error instanceof Error ? error.message : "Unknown error occurred during payment flow";
77
155
  throw new Error(`PaymentService Failed: ${errorMessage}`);
78
156
  }
79
157
  }
80
158
  /**
81
- * Get AI response
82
- *
83
- * @param agentSlug
84
- * @returns
85
- */
86
- async generateAIResponse(agentSlug, message) {
159
+ * Get AI response
160
+ *
161
+ * @param agentSlug
162
+ * @returns
163
+ */
164
+ async generateAIResponseEscrow(agentSlug, message) {
87
165
  try {
88
- const initialResponse = await fetch(`${BASE_ENDPOINT}/agent/${agentSlug}/chat`, {
166
+ const initialResponse = await fetch(`${BASE_ENDPOINT}/agent/escrow/${agentSlug}/chat`, {
89
167
  method: "POST",
90
168
  headers: {
91
169
  "Content-Type": "application/json"
@@ -98,32 +176,41 @@ var PaymentService = class {
98
176
  throw new Error(`Unexpected status code: ${initialResponse.status}`);
99
177
  }
100
178
  const paymentDetail = await initialResponse.json();
179
+ if (!paymentDetail) {
180
+ throw new Error("Payment detail not found in response.");
181
+ }
101
182
  const txId = paymentDetail.transactionId;
102
183
  const escrowAddress = paymentDetail.escrowAddress;
103
- const amountPayment = paymentDetail.amountPayment;
104
- const contractAddress = paymentDetail.contractAddress;
105
- if (!contractAddress) {
106
- throw new Error("Contract address not found in payment details.");
184
+ const amountPayment = paymentDetail.amount;
185
+ const receiverAddress = paymentDetail.receiverAddress;
186
+ const amount = ethers.parseUnits(amountPayment.toString(), 6);
187
+ if (!receiverAddress) {
188
+ throw new Error("Receiver address not found in payment details.");
107
189
  }
108
190
  const musdContract = new ethers.Contract(MUSD_ADDRESS, ERC20_ABI, this.wallet);
109
- const approveTx = await musdContract.approve(contractAddress, amountPayment);
191
+ console.log(`Approving MUSD spending for ${escrowAddress}...`);
192
+ const approveTx = await musdContract.approve(escrowAddress, amount);
110
193
  await approveTx.wait(1);
111
- const contract = new ethers.Contract(contractAddress, ESCROW_ABI, this.wallet);
194
+ console.log(`Initiating Expect Payment to ${escrowAddress} for creator ${receiverAddress} (${amount} wei)`);
195
+ const contract = new ethers.Contract(escrowAddress, ESCROW_ABI, this.wallet);
112
196
  const txResponse = await contract.createTx(
113
197
  txId,
114
- escrowAddress,
115
- amountPayment
198
+ receiverAddress,
199
+ amount
116
200
  );
201
+ console.log(`Escrow payment sent: ${txResponse.hash}. Waiting for confirmation...`);
117
202
  const receipt = await txResponse.wait(1);
118
203
  if (!receipt || receipt.status !== 1) {
119
204
  throw new Error("Escrow transaction failed.");
120
205
  }
121
206
  const finalTxHash = receipt.hash;
122
207
  const headers = {
123
- "x-payment-tx": finalTxHash,
124
- "Content-Type": "application/json"
208
+ "Content-Type": "application/json",
209
+ "Accept": "application/json",
210
+ "x-payment-tx": finalTxHash
125
211
  };
126
- const retryResponse = await fetch(`${BASE_ENDPOINT}/agent/${agentSlug}/chat`, {
212
+ console.log(`Retry with txHash: ${finalTxHash}`);
213
+ const retryResponse = await fetch(`${BASE_ENDPOINT}/agent/escrow/${agentSlug}/chat`, {
127
214
  method: "POST",
128
215
  headers,
129
216
  body: JSON.stringify({
@@ -148,7 +235,12 @@ var PaymentService = class {
148
235
  */
149
236
  async getProxyEndpoint(gatewaySlug) {
150
237
  try {
151
- const initialResponse = await fetch(`${BASE_ENDPOINT}/escrow/${gatewaySlug}`);
238
+ let initialResponse;
239
+ try {
240
+ initialResponse = await fetch(`${BASE_ENDPOINT}/${gatewaySlug}`);
241
+ } catch (e) {
242
+ throw new Error(`Initial Endpoint Failed: ${e}`);
243
+ }
152
244
  if (initialResponse.ok) {
153
245
  return await initialResponse.json();
154
246
  }
@@ -156,32 +248,98 @@ var PaymentService = class {
156
248
  throw new Error(`Unexpected status code: ${initialResponse.status}`);
157
249
  }
158
250
  const paymentDetail = await initialResponse.json();
251
+ if (!paymentDetail) {
252
+ throw new Error("Payment Detail not found.");
253
+ }
254
+ console.log("Payment Detail:", paymentDetail);
255
+ const amountPayment = paymentDetail.amount;
256
+ const receiverAddress = paymentDetail.receiverAddress;
257
+ const amount = ethers.parseUnits(amountPayment.toString(), 6);
258
+ if (!receiverAddress) {
259
+ throw new Error("Receiver address not found in payment details.");
260
+ }
261
+ const musdContract = new ethers.Contract(MUSD_ADDRESS, ERC20_ABI, this.wallet);
262
+ console.log(`Initiating Expect Payment to ${receiverAddress} (${amount} wei)`);
263
+ const txResponse = await musdContract.transfer(receiverAddress, amount);
264
+ console.log(`Payment sent: ${txResponse.hash}. Waiting for confirmation...`);
265
+ const receipt = await txResponse.wait(1);
266
+ if (!receipt || receipt.status !== 1) {
267
+ throw new Error("Payment transaction failed.");
268
+ }
269
+ const finalTxHash = receipt.hash;
270
+ const headers = {
271
+ "x-payment-tx": finalTxHash
272
+ };
273
+ console.log("view header: ", headers);
274
+ const retryResponse = await fetch(`${BASE_ENDPOINT}/${gatewaySlug}`, {
275
+ method: "GET",
276
+ headers
277
+ });
278
+ if (!retryResponse.ok) {
279
+ const errorText = await retryResponse.text();
280
+ throw new Error(`Retry failed: ${retryResponse.status} - ${errorText}`);
281
+ }
282
+ return await retryResponse.json();
283
+ } catch (error) {
284
+ const errorMessage = error instanceof Error ? error : "Unknown error in getProxyEndpoint";
285
+ throw new Error(`Proxy Endpoint Failed: ${errorMessage}`);
286
+ }
287
+ }
288
+ /**
289
+ * Get proxy endpoint escrow
290
+ *
291
+ * @param gatewaySlug
292
+ * @returns
293
+ */
294
+ async getProxyEndpointEscrow(gatewaySlug) {
295
+ try {
296
+ let initialResponse;
297
+ try {
298
+ initialResponse = await fetch(`${BASE_ENDPOINT}/escrow/${gatewaySlug}`);
299
+ } catch (e) {
300
+ throw new Error(`Initial Endpoint Failed: ${e}`);
301
+ }
302
+ if (initialResponse.ok) {
303
+ return await initialResponse.json();
304
+ }
305
+ if (initialResponse.status !== 402) {
306
+ throw new Error(`Unexpected status code: ${initialResponse.status}`);
307
+ }
308
+ const paymentDetail = await initialResponse.json();
309
+ if (!paymentDetail) {
310
+ throw new Error("Payment Detail not found.");
311
+ }
312
+ console.log("Payment Detail:", paymentDetail);
159
313
  const txId = paymentDetail.transactionId;
160
314
  const escrowAddress = paymentDetail.escrowAddress;
161
- const amountPayment = paymentDetail.amountPayment;
162
- const contractAddress = paymentDetail.contractAddress;
163
- if (!contractAddress) {
164
- throw new Error("Contract address not found in payment details.");
315
+ const amountPayment = paymentDetail.amount;
316
+ const receiverAddress = paymentDetail.receiverAddress;
317
+ const amount = ethers.parseUnits(amountPayment.toString(), 6);
318
+ if (!receiverAddress) {
319
+ throw new Error("Receiver address not found in payment details.");
165
320
  }
166
321
  const musdContract = new ethers.Contract(MUSD_ADDRESS, ERC20_ABI, this.wallet);
167
- const approveTx = await musdContract.approve(contractAddress, amountPayment);
322
+ console.log(`Approving MUSD spending for ${escrowAddress}`);
323
+ const approveTx = await musdContract.approve(escrowAddress, amount);
168
324
  await approveTx.wait(1);
169
- const contract = new ethers.Contract(contractAddress, ESCROW_ABI, this.wallet);
325
+ console.log(`Initiating Expect Payment to ${escrowAddress} for creator ${receiverAddress} (${amount} wei)`);
326
+ const contract = new ethers.Contract(escrowAddress, ESCROW_ABI, this.wallet);
170
327
  const txResponse = await contract.createTx(
171
328
  txId,
172
- escrowAddress,
173
- amountPayment
329
+ receiverAddress,
330
+ amount
174
331
  );
332
+ console.log(`Escrow payment sent: ${txResponse.hash}. Waiting for confirmation...`);
175
333
  const receipt = await txResponse.wait(1);
176
334
  if (!receipt || receipt.status !== 1) {
177
335
  throw new Error("Escrow transaction failed.");
178
336
  }
179
337
  const finalTxHash = receipt.hash;
180
338
  const headers = {
181
- "x-payment-tx": finalTxHash,
182
- "Content-Type": "application/json"
339
+ "x-payment-tx": finalTxHash
183
340
  };
184
- const retryResponse = await fetch(`${BASE_ENDPOINT}/${gatewaySlug}`, {
341
+ console.log("view header: ", headers);
342
+ const retryResponse = await fetch(`${BASE_ENDPOINT}/escrow/${gatewaySlug}`, {
185
343
  method: "GET",
186
344
  headers
187
345
  });
@@ -191,7 +349,7 @@ var PaymentService = class {
191
349
  }
192
350
  return await retryResponse.json();
193
351
  } catch (error) {
194
- const errorMessage = error instanceof Error ? error.message : "Unknown error in getProxyEndpoint";
352
+ const errorMessage = error instanceof Error ? error : "Unknown error in getProxyEndpoint";
195
353
  throw new Error(`Proxy Endpoint Failed: ${errorMessage}`);
196
354
  }
197
355
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payroute/x402-sdk",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "SDK for automation payment gateway with x402",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",