@payroute/x402-sdk 1.0.0 → 1.0.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 CHANGED
@@ -6,26 +6,24 @@ 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
19
19
  ```
20
20
 
21
- _Note: `ethers` peer dependency (v6) is required._
22
-
23
21
  ## Quick Start
24
22
 
25
23
  ### 1. Initialize the Service
26
24
 
27
25
  ```typescript
28
- import { PaymentService } from "payroute-x402-sdk";
26
+ import { PaymentService } from "@payroute/x402-sdk";
29
27
 
30
28
  const service = new PaymentService({
31
29
  privateKey: process.env.WALLET_PRIVATE_KEY, // Your EVM private key
@@ -37,24 +35,43 @@ const service = new PaymentService({
37
35
 
38
36
  Access premium content served behind a Payroute gateway.
39
37
 
38
+ #### Direct Payment (Non-Escrow)
39
+
40
+ Use this method for direct peer-to-peer payments to a receiver.
41
+
40
42
  ```typescript
41
43
  try {
42
- const content = await service.getProxyEndpoint("my-premium-blog-post");
44
+ const content = await service.getProxyEndpoint("MantleDocs");
43
45
  console.log("Accessed Content:", content);
44
46
  } catch (error) {
45
47
  console.error("Payment or Fetch Failed:", error);
46
48
  }
47
49
  ```
48
50
 
51
+ #### Escrow Payment
52
+
53
+ Use this method when the gateway requires payment via an escrow smart contract.
54
+
55
+ ```typescript
56
+ try {
57
+ const contentStart = await service.getProxyEndpointEscrow("BitcoinOutlook");
58
+ console.log("Accessed Escrow Content:", contentStart);
59
+ } catch (error) {
60
+ console.error("Payment or Fetch Failed:", error);
61
+ }
62
+ ```
63
+
49
64
  ### 3. Interact with a Paid AI Agent
50
65
 
51
66
  Send messages to an AI agent that requires per-message payments.
52
67
 
68
+ #### Direct Payment (Non-Escrow)
69
+
53
70
  ```typescript
54
71
  try {
55
72
  const response = await service.generateAIResponse(
56
- "finance-advisor-agent",
57
- "What is the outlook for MNT?"
73
+ "mantleAgent",
74
+ "How to build smart contract on Mantle Network?"
58
75
  );
59
76
  console.log("AI Response:", response);
60
77
  } catch (error) {
@@ -62,6 +79,20 @@ try {
62
79
  }
63
80
  ```
64
81
 
82
+ #### Escrow Payment
83
+
84
+ ```typescript
85
+ try {
86
+ const responseEscrow = await service.generateAIResponseEscrow(
87
+ "mantleAgent",
88
+ "How to build AVS on EigenLayer?"
89
+ );
90
+ console.log("AI Response Escrow:", responseEscrow);
91
+ } catch (error) {
92
+ console.error("Agent Interaction Failed:", error);
93
+ }
94
+ ```
95
+
65
96
  ## Advanced Usage
66
97
 
67
98
  ### Custom RPC Provider
@@ -75,22 +106,73 @@ const service = new PaymentService({
75
106
  });
76
107
  ```
77
108
 
78
- ### Generic Pay-And-Retry
109
+ ## Integration with AI Agents & LLMs
110
+
111
+ One of the most powerful use cases for `@payroute/x402-sdk` is enabling **Autonomous Economic Agents**. Because the SDK handles the entire payment lifecycle programmatically, LLMs can "pay" for their own resources without user intervention.
112
+
113
+ ### Example: Autonomous Research Agent
79
114
 
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.
115
+ Imagine an AI agent tasked with gathering premium market data. It can use this SDK to automatically pay for each data point it accesses using its own wallet.
81
116
 
82
117
  ```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
- },
118
+ import { PaymentService } from "@payroute/x402-sdk";
119
+ import { openai } from "./my-llm-setup"; // Hypothetical LLM client
120
+
121
+ // 1. Give the Agent a Wallet
122
+ const agentWalletKey = process.env.AGENT_PRIVATE_KEY;
123
+ const payroute = new PaymentService({
124
+ privateKey: agentWalletKey,
125
+ network: "mantle",
93
126
  });
127
+
128
+ async function autonomousResearchTask(topic: string) {
129
+ console.log(`Agent starting research on: ${topic}...`);
130
+
131
+ // 2. Agent decides it needs premium data (e.g., from 'HighValueData' endpoint)
132
+ // The SDK handles the 402 challenge, approves tokens, pays, and returns the data.
133
+ console.log("Accessing premium data source...");
134
+
135
+ // THIS SINGLE LINE handles the entire negotiation and payment
136
+ const premiumData = await payroute.getProxyEndpointEscrow("HighValueData");
137
+
138
+ // 3. Agent processes the purchased data
139
+ console.log("Data acquired. Analyzing...");
140
+ const analysis = await openai.chat.completions.create({
141
+ model: "gpt-4",
142
+ messages: [
143
+ {
144
+ role: "user",
145
+ content: `Analyze this data: ${JSON.stringify(premiumData)}`,
146
+ },
147
+ ],
148
+ });
149
+
150
+ return analysis.choices[0].message.content;
151
+ }
152
+ ```
153
+
154
+ This pattern transforms **passive tools** into **economically active agents** capable of trading value for information or services on the open market.
155
+
156
+ ### Example: Agent-to-Agent Consultation
157
+
158
+ Your agent can also pay to converse with other specialized AI agents (e.g., a "Legal Expert" or "Medical Advisor").
159
+
160
+ ```typescript
161
+ async function consultExpertAgent(problem: string) {
162
+ // Agent identifies it needs help from a specific expert agent slug
163
+ const expertAgentSlug = "legal-expert-v1";
164
+
165
+ console.log(`Consulting ${expertAgentSlug}...`);
166
+
167
+ // The SDK handles payment for the conversation turn
168
+ const expertAdvice = await payroute.generateAIResponseEscrow(
169
+ expertAgentSlug,
170
+ `I have a user asking about: ${problem}. What are the compliance risks?`
171
+ );
172
+
173
+ // Initial Agent integrates the paid advice into its final response
174
+ return expertAdvice.response;
175
+ }
94
176
  ```
95
177
 
96
178
  ## Architecture
@@ -98,9 +180,11 @@ const response = await service.payAndRetry({
98
180
  The SDK implements the **Payroute x402 Protocol**:
99
181
 
100
182
  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.
183
+ 2. **Challenge (402)**: Server responds with `402 Payment Required` and payment details (Receiver Address, Amount, Transaction ID, and optionally Escrow Address).
184
+ 3. **Approval (If needed)**: SDK approves the required token (MUSD) for the escrow contract or spends directly.
185
+ 4. **Payment**:
186
+ - **Direct**: Transfers MUSD directly to the receiver.
187
+ - **Escrow**: Calls the Escrow contract's `createTx` function.
104
188
  5. **Confirmation**: SDK waits for blockchain confirmation.
105
189
  6. **Retry**: SDK retries the original request with the transaction hash in the `x-payment-tx` header.
106
190
  7. **Response**: Server validates the transaction and returns the content.
package/dist/index.d.mts CHANGED
@@ -13,6 +13,7 @@ interface PaymentServiceConfig {
13
13
  privateKey: string;
14
14
  network?: 'mantle' | 'mantleTestnet' | 'localhost';
15
15
  rpcUrl?: string;
16
+ apiBaseUrl?: string;
16
17
  }
17
18
  /**
18
19
  * PaymentService class
@@ -21,6 +22,7 @@ interface PaymentServiceConfig {
21
22
  declare class PaymentService {
22
23
  private wallet;
23
24
  private provider;
25
+ private apiBaseUrl;
24
26
  constructor(config: PaymentServiceConfig);
25
27
  /**
26
28
  * Performs a payment on-chain and retries the original request with proof of payment.
@@ -29,10 +31,6 @@ declare class PaymentService {
29
31
  * @param params.retryRequest - A callback that performs the HTTP request. Must accept headers.
30
32
  * @returns The response from the retried request.
31
33
  */
32
- payAndRetry<T>(params: {
33
- paymentData: PaymentData;
34
- retryRequest: (headers: Record<string, string>) => Promise<T>;
35
- }): Promise<T>;
36
34
  /**
37
35
  * Get AI response
38
36
  *
@@ -40,6 +38,13 @@ declare class PaymentService {
40
38
  * @returns
41
39
  */
42
40
  generateAIResponse<T = any>(agentSlug: string, message: string): Promise<T>;
41
+ /**
42
+ * Get AI response
43
+ *
44
+ * @param agentSlug
45
+ * @returns
46
+ */
47
+ generateAIResponseEscrow<T = any>(agentSlug: string, message: string): Promise<T>;
43
48
  /**
44
49
  * Get proxy endpoint
45
50
  *
@@ -47,6 +52,13 @@ declare class PaymentService {
47
52
  * @returns
48
53
  */
49
54
  getProxyEndpoint<T = any>(gatewaySlug: string): Promise<T>;
55
+ /**
56
+ * Get proxy endpoint escrow
57
+ *
58
+ * @param gatewaySlug
59
+ * @returns
60
+ */
61
+ getProxyEndpointEscrow<T = any>(gatewaySlug: string): Promise<T>;
50
62
  /**
51
63
  * Helper to get the current wallet address
52
64
  */
package/dist/index.d.ts CHANGED
@@ -13,6 +13,7 @@ interface PaymentServiceConfig {
13
13
  privateKey: string;
14
14
  network?: 'mantle' | 'mantleTestnet' | 'localhost';
15
15
  rpcUrl?: string;
16
+ apiBaseUrl?: string;
16
17
  }
17
18
  /**
18
19
  * PaymentService class
@@ -21,6 +22,7 @@ interface PaymentServiceConfig {
21
22
  declare class PaymentService {
22
23
  private wallet;
23
24
  private provider;
25
+ private apiBaseUrl;
24
26
  constructor(config: PaymentServiceConfig);
25
27
  /**
26
28
  * Performs a payment on-chain and retries the original request with proof of payment.
@@ -29,10 +31,6 @@ declare class PaymentService {
29
31
  * @param params.retryRequest - A callback that performs the HTTP request. Must accept headers.
30
32
  * @returns The response from the retried request.
31
33
  */
32
- payAndRetry<T>(params: {
33
- paymentData: PaymentData;
34
- retryRequest: (headers: Record<string, string>) => Promise<T>;
35
- }): Promise<T>;
36
34
  /**
37
35
  * Get AI response
38
36
  *
@@ -40,6 +38,13 @@ declare class PaymentService {
40
38
  * @returns
41
39
  */
42
40
  generateAIResponse<T = any>(agentSlug: string, message: string): Promise<T>;
41
+ /**
42
+ * Get AI response
43
+ *
44
+ * @param agentSlug
45
+ * @returns
46
+ */
47
+ generateAIResponseEscrow<T = any>(agentSlug: string, message: string): Promise<T>;
43
48
  /**
44
49
  * Get proxy endpoint
45
50
  *
@@ -47,6 +52,13 @@ declare class PaymentService {
47
52
  * @returns
48
53
  */
49
54
  getProxyEndpoint<T = any>(gatewaySlug: string): Promise<T>;
55
+ /**
56
+ * Get proxy endpoint escrow
57
+ *
58
+ * @param gatewaySlug
59
+ * @returns
60
+ */
61
+ getProxyEndpointEscrow<T = any>(gatewaySlug: string): Promise<T>;
50
62
  /**
51
63
  * Helper to get the current wallet address
52
64
  */
package/dist/index.js CHANGED
@@ -43,17 +43,18 @@ var NETWORKS = {
43
43
  chainId: 31337
44
44
  }
45
45
  };
46
- var BASE_ENDPOINT = "https://x402-services.vercel.app";
47
46
  var ESCROW_ABI = [
48
- "function createTx(string txId, address creator, uint256 amount) external payable"
47
+ "function createTx(bytes32 txId, address creator, uint256 amount)"
49
48
  ];
50
49
  var MUSD_ADDRESS = "0x4dABf45C8cF333Ef1e874c3FDFC3C86799af80c8";
51
50
  var ERC20_ABI = [
52
- "function approve(address spender, uint256 amount) external returns (bool)"
51
+ "function approve(address spender, uint256 amount) external returns (bool)",
52
+ "function transfer(address to, uint256 amount) external returns (bool)"
53
53
  ];
54
54
  var PaymentService = class {
55
55
  wallet;
56
56
  provider;
57
+ apiBaseUrl;
57
58
  constructor(config) {
58
59
  const networkKey = config.network || "mantle";
59
60
  const networkConfig = NETWORKS[networkKey];
@@ -67,6 +68,7 @@ var PaymentService = class {
67
68
  } catch (error) {
68
69
  throw new Error("Invalid private key provided.");
69
70
  }
71
+ this.apiBaseUrl = config.apiBaseUrl || "https://x402-services.vercel.app";
70
72
  }
71
73
  /**
72
74
  * Performs a payment on-chain and retries the original request with proof of payment.
@@ -75,43 +77,120 @@ var PaymentService = class {
75
77
  * @param params.retryRequest - A callback that performs the HTTP request. Must accept headers.
76
78
  * @returns The response from the retried request.
77
79
  */
78
- async payAndRetry(params) {
79
- const { paymentData, retryRequest } = params;
80
+ // async payAndRetry<T>(params: {
81
+ // paymentData: PaymentData;
82
+ // retryRequest: (headers: Record<string, string>) => Promise<T>;
83
+ // }): Promise<T> {
84
+ // const { paymentData, retryRequest } = params;
85
+ // try {
86
+ // // 1. Validate Payment Data
87
+ // if (!ethers.isAddress(paymentData.recipient)) {
88
+ // throw new Error(`Invalid recipient address: ${paymentData.recipient}`);
89
+ // }
90
+ // // 2. Build Transaction
91
+ // const txRequest = {
92
+ // to: paymentData.recipient,
93
+ // value: BigInt(paymentData.amount),
94
+ // // Gas limit/price will be estimated by provider/wallet
95
+ // };
96
+ // // 3. Sign & Send Transaction
97
+ // // console.log(`Sending payment of ${paymentData.amount} wei to ${paymentData.recipient}...`);
98
+ // const txResponse = await this.wallet.sendTransaction(txRequest);
99
+ // // 4. Wait for confirmation
100
+ // // console.log(`Transaction sent: ${txResponse.hash}. Waiting for confirmation...`);
101
+ // const receipt = await txResponse.wait(1); // Wait for 1 confirmation
102
+ // if (!receipt || receipt.status !== 1) {
103
+ // throw new Error('Transaction failed or was reverted on-chain.');
104
+ // }
105
+ // // 5. Retry original request with header X-Payment-Tx
106
+ // const txHash = receipt.hash;
107
+ // const headers = {
108
+ // 'X-Payment-Tx': txHash,
109
+ // 'Content-Type': 'application/json', // Default content type, extendable if needed
110
+ // };
111
+ // // 6. Return final HTTP response
112
+ // return await retryRequest(headers);
113
+ // } catch (error: any) {
114
+ // // 7. Throw clear errors on failure
115
+ // const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred during payment flow';
116
+ // // console.error('PaymentService Error:', errorMessage);
117
+ // throw new Error(`PaymentService Failed: ${errorMessage}`);
118
+ // }
119
+ // }
120
+ /**
121
+ * Get AI response
122
+ *
123
+ * @param agentSlug
124
+ * @returns
125
+ */
126
+ async generateAIResponse(agentSlug, message) {
80
127
  try {
81
- if (!import_ethers.ethers.isAddress(paymentData.recipient)) {
82
- throw new Error(`Invalid recipient address: ${paymentData.recipient}`);
128
+ const initialResponse = await fetch(`${this.apiBaseUrl}/agent/${agentSlug}/chat`, {
129
+ method: "POST",
130
+ headers: {
131
+ "Content-Type": "application/json"
132
+ },
133
+ body: JSON.stringify({
134
+ message
135
+ })
136
+ });
137
+ if (!initialResponse.ok && initialResponse.status !== 402) {
138
+ throw new Error(`Unexpected status code: ${initialResponse.status}`);
83
139
  }
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);
140
+ const paymentDetail = await initialResponse.json();
141
+ if (!paymentDetail) {
142
+ throw new Error("Payment detail not found in response.");
143
+ }
144
+ const txId = paymentDetail.transactionId;
145
+ const amountPayment = paymentDetail.amount;
146
+ const receiverAddress = paymentDetail.receiverAddress;
147
+ const amount = import_ethers.ethers.parseUnits(amountPayment.toString(), 6);
148
+ if (!receiverAddress) {
149
+ throw new Error("Receiver address not found in payment details.");
150
+ }
151
+ const musdContract = new import_ethers.ethers.Contract(MUSD_ADDRESS, ERC20_ABI, this.wallet);
152
+ console.log(`Approving MUSD spending for ${receiverAddress}...`);
153
+ const approveTx = await musdContract.approve(receiverAddress, amount);
154
+ await approveTx.wait(1);
155
+ console.log(`Initiating Expect Payment to creator ${receiverAddress} (${amount} wei)`);
156
+ const txResponse = await musdContract.transfer(receiverAddress, amount);
157
+ console.log(`Payment sent: ${txResponse.hash}. Waiting for confirmation...`);
90
158
  const receipt = await txResponse.wait(1);
91
159
  if (!receipt || receipt.status !== 1) {
92
- throw new Error("Transaction failed or was reverted on-chain.");
160
+ throw new Error("Payment transaction failed.");
93
161
  }
94
- const txHash = receipt.hash;
162
+ const finalTxHash = receipt.hash;
95
163
  const headers = {
96
- "X-Payment-Tx": txHash,
97
- "Content-Type": "application/json"
98
- // Default content type, extendable if needed
164
+ "Content-Type": "application/json",
165
+ "x-payment-tx": finalTxHash
99
166
  };
100
- return await retryRequest(headers);
167
+ console.log(`Retry with txHash: ${finalTxHash}`);
168
+ const retryResponse = await fetch(`${this.apiBaseUrl}/agent/${agentSlug}/chat`, {
169
+ method: "POST",
170
+ headers,
171
+ body: JSON.stringify({
172
+ message
173
+ })
174
+ });
175
+ if (!retryResponse.ok) {
176
+ const errorText = await retryResponse.text();
177
+ throw new Error(`Retry failed: ${retryResponse.status} - ${errorText}`);
178
+ }
179
+ return await retryResponse.json();
101
180
  } catch (error) {
102
181
  const errorMessage = error instanceof Error ? error.message : "Unknown error occurred during payment flow";
103
182
  throw new Error(`PaymentService Failed: ${errorMessage}`);
104
183
  }
105
184
  }
106
185
  /**
107
- * Get AI response
108
- *
109
- * @param agentSlug
110
- * @returns
111
- */
112
- async generateAIResponse(agentSlug, message) {
186
+ * Get AI response
187
+ *
188
+ * @param agentSlug
189
+ * @returns
190
+ */
191
+ async generateAIResponseEscrow(agentSlug, message) {
113
192
  try {
114
- const initialResponse = await fetch(`${BASE_ENDPOINT}/agent/${agentSlug}/chat`, {
193
+ const initialResponse = await fetch(`${this.apiBaseUrl}/agent/escrow/${agentSlug}/chat`, {
115
194
  method: "POST",
116
195
  headers: {
117
196
  "Content-Type": "application/json"
@@ -124,32 +203,41 @@ var PaymentService = class {
124
203
  throw new Error(`Unexpected status code: ${initialResponse.status}`);
125
204
  }
126
205
  const paymentDetail = await initialResponse.json();
206
+ if (!paymentDetail) {
207
+ throw new Error("Payment detail not found in response.");
208
+ }
127
209
  const txId = paymentDetail.transactionId;
128
210
  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.");
211
+ const amountPayment = paymentDetail.amount;
212
+ const receiverAddress = paymentDetail.receiverAddress;
213
+ const amount = import_ethers.ethers.parseUnits(amountPayment.toString(), 6);
214
+ if (!receiverAddress) {
215
+ throw new Error("Receiver address not found in payment details.");
133
216
  }
134
217
  const musdContract = new import_ethers.ethers.Contract(MUSD_ADDRESS, ERC20_ABI, this.wallet);
135
- const approveTx = await musdContract.approve(contractAddress, amountPayment);
218
+ console.log(`Approving MUSD spending for ${escrowAddress}...`);
219
+ const approveTx = await musdContract.approve(escrowAddress, amount);
136
220
  await approveTx.wait(1);
137
- const contract = new import_ethers.ethers.Contract(contractAddress, ESCROW_ABI, this.wallet);
221
+ console.log(`Initiating Expect Payment to ${escrowAddress} for creator ${receiverAddress} (${amount} wei)`);
222
+ const contract = new import_ethers.ethers.Contract(escrowAddress, ESCROW_ABI, this.wallet);
138
223
  const txResponse = await contract.createTx(
139
224
  txId,
140
- escrowAddress,
141
- amountPayment
225
+ receiverAddress,
226
+ amount
142
227
  );
228
+ console.log(`Escrow payment sent: ${txResponse.hash}. Waiting for confirmation...`);
143
229
  const receipt = await txResponse.wait(1);
144
230
  if (!receipt || receipt.status !== 1) {
145
231
  throw new Error("Escrow transaction failed.");
146
232
  }
147
233
  const finalTxHash = receipt.hash;
148
234
  const headers = {
149
- "x-payment-tx": finalTxHash,
150
- "Content-Type": "application/json"
235
+ "Content-Type": "application/json",
236
+ "Accept": "application/json",
237
+ "x-payment-tx": finalTxHash
151
238
  };
152
- const retryResponse = await fetch(`${BASE_ENDPOINT}/agent/${agentSlug}/chat`, {
239
+ console.log(`Retry with txHash: ${finalTxHash}`);
240
+ const retryResponse = await fetch(`${this.apiBaseUrl}/agent/escrow/${agentSlug}/chat`, {
153
241
  method: "POST",
154
242
  headers,
155
243
  body: JSON.stringify({
@@ -174,7 +262,70 @@ var PaymentService = class {
174
262
  */
175
263
  async getProxyEndpoint(gatewaySlug) {
176
264
  try {
177
- const initialResponse = await fetch(`${BASE_ENDPOINT}/escrow/${gatewaySlug}`);
265
+ let initialResponse;
266
+ try {
267
+ initialResponse = await fetch(`${this.apiBaseUrl}/${gatewaySlug}`);
268
+ } catch (e) {
269
+ throw new Error(`Initial Endpoint Failed: ${e}`);
270
+ }
271
+ if (initialResponse.ok) {
272
+ return await initialResponse.json();
273
+ }
274
+ if (initialResponse.status !== 402) {
275
+ throw new Error(`Unexpected status code: ${initialResponse.status}`);
276
+ }
277
+ const paymentDetail = await initialResponse.json();
278
+ if (!paymentDetail) {
279
+ throw new Error("Payment Detail not found.");
280
+ }
281
+ console.log("Payment Detail:", paymentDetail);
282
+ const amountPayment = paymentDetail.amount;
283
+ const receiverAddress = paymentDetail.receiverAddress;
284
+ const amount = import_ethers.ethers.parseUnits(amountPayment.toString(), 6);
285
+ if (!receiverAddress) {
286
+ throw new Error("Receiver address not found in payment details.");
287
+ }
288
+ const musdContract = new import_ethers.ethers.Contract(MUSD_ADDRESS, ERC20_ABI, this.wallet);
289
+ console.log(`Initiating Expect Payment to ${receiverAddress} (${amount} wei)`);
290
+ const txResponse = await musdContract.transfer(receiverAddress, amount);
291
+ console.log(`Payment sent: ${txResponse.hash}. Waiting for confirmation...`);
292
+ const receipt = await txResponse.wait(1);
293
+ if (!receipt || receipt.status !== 1) {
294
+ throw new Error("Payment transaction failed.");
295
+ }
296
+ const finalTxHash = receipt.hash;
297
+ const headers = {
298
+ "x-payment-tx": finalTxHash
299
+ };
300
+ console.log("view header: ", headers);
301
+ const retryResponse = await fetch(`${this.apiBaseUrl}/${gatewaySlug}`, {
302
+ method: "GET",
303
+ headers
304
+ });
305
+ if (!retryResponse.ok) {
306
+ const errorText = await retryResponse.text();
307
+ throw new Error(`Retry failed: ${retryResponse.status} - ${errorText}`);
308
+ }
309
+ return await retryResponse.json();
310
+ } catch (error) {
311
+ const errorMessage = error instanceof Error ? error : "Unknown error in getProxyEndpoint";
312
+ throw new Error(`Proxy Endpoint Failed: ${errorMessage}`);
313
+ }
314
+ }
315
+ /**
316
+ * Get proxy endpoint escrow
317
+ *
318
+ * @param gatewaySlug
319
+ * @returns
320
+ */
321
+ async getProxyEndpointEscrow(gatewaySlug) {
322
+ try {
323
+ let initialResponse;
324
+ try {
325
+ initialResponse = await fetch(`${this.apiBaseUrl}/escrow/${gatewaySlug}`);
326
+ } catch (e) {
327
+ throw new Error(`Initial Endpoint Failed: ${e}`);
328
+ }
178
329
  if (initialResponse.ok) {
179
330
  return await initialResponse.json();
180
331
  }
@@ -182,32 +333,40 @@ var PaymentService = class {
182
333
  throw new Error(`Unexpected status code: ${initialResponse.status}`);
183
334
  }
184
335
  const paymentDetail = await initialResponse.json();
336
+ if (!paymentDetail) {
337
+ throw new Error("Payment Detail not found.");
338
+ }
339
+ console.log("Payment Detail:", paymentDetail);
185
340
  const txId = paymentDetail.transactionId;
186
341
  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.");
342
+ const amountPayment = paymentDetail.amount;
343
+ const receiverAddress = paymentDetail.receiverAddress;
344
+ const amount = import_ethers.ethers.parseUnits(amountPayment.toString(), 6);
345
+ if (!receiverAddress) {
346
+ throw new Error("Receiver address not found in payment details.");
191
347
  }
192
348
  const musdContract = new import_ethers.ethers.Contract(MUSD_ADDRESS, ERC20_ABI, this.wallet);
193
- const approveTx = await musdContract.approve(contractAddress, amountPayment);
349
+ console.log(`Approving MUSD spending for ${escrowAddress}`);
350
+ const approveTx = await musdContract.approve(escrowAddress, amount);
194
351
  await approveTx.wait(1);
195
- const contract = new import_ethers.ethers.Contract(contractAddress, ESCROW_ABI, this.wallet);
352
+ console.log(`Initiating Expect Payment to ${escrowAddress} for creator ${receiverAddress} (${amount} wei)`);
353
+ const contract = new import_ethers.ethers.Contract(escrowAddress, ESCROW_ABI, this.wallet);
196
354
  const txResponse = await contract.createTx(
197
355
  txId,
198
- escrowAddress,
199
- amountPayment
356
+ receiverAddress,
357
+ amount
200
358
  );
359
+ console.log(`Escrow payment sent: ${txResponse.hash}. Waiting for confirmation...`);
201
360
  const receipt = await txResponse.wait(1);
202
361
  if (!receipt || receipt.status !== 1) {
203
362
  throw new Error("Escrow transaction failed.");
204
363
  }
205
364
  const finalTxHash = receipt.hash;
206
365
  const headers = {
207
- "x-payment-tx": finalTxHash,
208
- "Content-Type": "application/json"
366
+ "x-payment-tx": finalTxHash
209
367
  };
210
- const retryResponse = await fetch(`${BASE_ENDPOINT}/${gatewaySlug}`, {
368
+ console.log("view header: ", headers);
369
+ const retryResponse = await fetch(`${this.apiBaseUrl}/escrow/${gatewaySlug}`, {
211
370
  method: "GET",
212
371
  headers
213
372
  });
@@ -217,7 +376,7 @@ var PaymentService = class {
217
376
  }
218
377
  return await retryResponse.json();
219
378
  } catch (error) {
220
- const errorMessage = error instanceof Error ? error.message : "Unknown error in getProxyEndpoint";
379
+ const errorMessage = error instanceof Error ? error : "Unknown error in getProxyEndpoint";
221
380
  throw new Error(`Proxy Endpoint Failed: ${errorMessage}`);
222
381
  }
223
382
  }
package/dist/index.mjs CHANGED
@@ -17,17 +17,18 @@ var NETWORKS = {
17
17
  chainId: 31337
18
18
  }
19
19
  };
20
- var BASE_ENDPOINT = "https://x402-services.vercel.app";
21
20
  var ESCROW_ABI = [
22
- "function createTx(string txId, address creator, uint256 amount) external payable"
21
+ "function createTx(bytes32 txId, address creator, uint256 amount)"
23
22
  ];
24
23
  var MUSD_ADDRESS = "0x4dABf45C8cF333Ef1e874c3FDFC3C86799af80c8";
25
24
  var ERC20_ABI = [
26
- "function approve(address spender, uint256 amount) external returns (bool)"
25
+ "function approve(address spender, uint256 amount) external returns (bool)",
26
+ "function transfer(address to, uint256 amount) external returns (bool)"
27
27
  ];
28
28
  var PaymentService = class {
29
29
  wallet;
30
30
  provider;
31
+ apiBaseUrl;
31
32
  constructor(config) {
32
33
  const networkKey = config.network || "mantle";
33
34
  const networkConfig = NETWORKS[networkKey];
@@ -41,6 +42,7 @@ var PaymentService = class {
41
42
  } catch (error) {
42
43
  throw new Error("Invalid private key provided.");
43
44
  }
45
+ this.apiBaseUrl = config.apiBaseUrl || "https://x402-services.vercel.app";
44
46
  }
45
47
  /**
46
48
  * Performs a payment on-chain and retries the original request with proof of payment.
@@ -49,43 +51,120 @@ var PaymentService = class {
49
51
  * @param params.retryRequest - A callback that performs the HTTP request. Must accept headers.
50
52
  * @returns The response from the retried request.
51
53
  */
52
- async payAndRetry(params) {
53
- const { paymentData, retryRequest } = params;
54
+ // async payAndRetry<T>(params: {
55
+ // paymentData: PaymentData;
56
+ // retryRequest: (headers: Record<string, string>) => Promise<T>;
57
+ // }): Promise<T> {
58
+ // const { paymentData, retryRequest } = params;
59
+ // try {
60
+ // // 1. Validate Payment Data
61
+ // if (!ethers.isAddress(paymentData.recipient)) {
62
+ // throw new Error(`Invalid recipient address: ${paymentData.recipient}`);
63
+ // }
64
+ // // 2. Build Transaction
65
+ // const txRequest = {
66
+ // to: paymentData.recipient,
67
+ // value: BigInt(paymentData.amount),
68
+ // // Gas limit/price will be estimated by provider/wallet
69
+ // };
70
+ // // 3. Sign & Send Transaction
71
+ // // console.log(`Sending payment of ${paymentData.amount} wei to ${paymentData.recipient}...`);
72
+ // const txResponse = await this.wallet.sendTransaction(txRequest);
73
+ // // 4. Wait for confirmation
74
+ // // console.log(`Transaction sent: ${txResponse.hash}. Waiting for confirmation...`);
75
+ // const receipt = await txResponse.wait(1); // Wait for 1 confirmation
76
+ // if (!receipt || receipt.status !== 1) {
77
+ // throw new Error('Transaction failed or was reverted on-chain.');
78
+ // }
79
+ // // 5. Retry original request with header X-Payment-Tx
80
+ // const txHash = receipt.hash;
81
+ // const headers = {
82
+ // 'X-Payment-Tx': txHash,
83
+ // 'Content-Type': 'application/json', // Default content type, extendable if needed
84
+ // };
85
+ // // 6. Return final HTTP response
86
+ // return await retryRequest(headers);
87
+ // } catch (error: any) {
88
+ // // 7. Throw clear errors on failure
89
+ // const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred during payment flow';
90
+ // // console.error('PaymentService Error:', errorMessage);
91
+ // throw new Error(`PaymentService Failed: ${errorMessage}`);
92
+ // }
93
+ // }
94
+ /**
95
+ * Get AI response
96
+ *
97
+ * @param agentSlug
98
+ * @returns
99
+ */
100
+ async generateAIResponse(agentSlug, message) {
54
101
  try {
55
- if (!ethers.isAddress(paymentData.recipient)) {
56
- throw new Error(`Invalid recipient address: ${paymentData.recipient}`);
102
+ const initialResponse = await fetch(`${this.apiBaseUrl}/agent/${agentSlug}/chat`, {
103
+ method: "POST",
104
+ headers: {
105
+ "Content-Type": "application/json"
106
+ },
107
+ body: JSON.stringify({
108
+ message
109
+ })
110
+ });
111
+ if (!initialResponse.ok && initialResponse.status !== 402) {
112
+ throw new Error(`Unexpected status code: ${initialResponse.status}`);
57
113
  }
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);
114
+ const paymentDetail = await initialResponse.json();
115
+ if (!paymentDetail) {
116
+ throw new Error("Payment detail not found in response.");
117
+ }
118
+ const txId = paymentDetail.transactionId;
119
+ const amountPayment = paymentDetail.amount;
120
+ const receiverAddress = paymentDetail.receiverAddress;
121
+ const amount = ethers.parseUnits(amountPayment.toString(), 6);
122
+ if (!receiverAddress) {
123
+ throw new Error("Receiver address not found in payment details.");
124
+ }
125
+ const musdContract = new ethers.Contract(MUSD_ADDRESS, ERC20_ABI, this.wallet);
126
+ console.log(`Approving MUSD spending for ${receiverAddress}...`);
127
+ const approveTx = await musdContract.approve(receiverAddress, amount);
128
+ await approveTx.wait(1);
129
+ console.log(`Initiating Expect Payment to creator ${receiverAddress} (${amount} wei)`);
130
+ const txResponse = await musdContract.transfer(receiverAddress, amount);
131
+ console.log(`Payment sent: ${txResponse.hash}. Waiting for confirmation...`);
64
132
  const receipt = await txResponse.wait(1);
65
133
  if (!receipt || receipt.status !== 1) {
66
- throw new Error("Transaction failed or was reverted on-chain.");
134
+ throw new Error("Payment transaction failed.");
67
135
  }
68
- const txHash = receipt.hash;
136
+ const finalTxHash = receipt.hash;
69
137
  const headers = {
70
- "X-Payment-Tx": txHash,
71
- "Content-Type": "application/json"
72
- // Default content type, extendable if needed
138
+ "Content-Type": "application/json",
139
+ "x-payment-tx": finalTxHash
73
140
  };
74
- return await retryRequest(headers);
141
+ console.log(`Retry with txHash: ${finalTxHash}`);
142
+ const retryResponse = await fetch(`${this.apiBaseUrl}/agent/${agentSlug}/chat`, {
143
+ method: "POST",
144
+ headers,
145
+ body: JSON.stringify({
146
+ message
147
+ })
148
+ });
149
+ if (!retryResponse.ok) {
150
+ const errorText = await retryResponse.text();
151
+ throw new Error(`Retry failed: ${retryResponse.status} - ${errorText}`);
152
+ }
153
+ return await retryResponse.json();
75
154
  } catch (error) {
76
155
  const errorMessage = error instanceof Error ? error.message : "Unknown error occurred during payment flow";
77
156
  throw new Error(`PaymentService Failed: ${errorMessage}`);
78
157
  }
79
158
  }
80
159
  /**
81
- * Get AI response
82
- *
83
- * @param agentSlug
84
- * @returns
85
- */
86
- async generateAIResponse(agentSlug, message) {
160
+ * Get AI response
161
+ *
162
+ * @param agentSlug
163
+ * @returns
164
+ */
165
+ async generateAIResponseEscrow(agentSlug, message) {
87
166
  try {
88
- const initialResponse = await fetch(`${BASE_ENDPOINT}/agent/${agentSlug}/chat`, {
167
+ const initialResponse = await fetch(`${this.apiBaseUrl}/agent/escrow/${agentSlug}/chat`, {
89
168
  method: "POST",
90
169
  headers: {
91
170
  "Content-Type": "application/json"
@@ -98,32 +177,41 @@ var PaymentService = class {
98
177
  throw new Error(`Unexpected status code: ${initialResponse.status}`);
99
178
  }
100
179
  const paymentDetail = await initialResponse.json();
180
+ if (!paymentDetail) {
181
+ throw new Error("Payment detail not found in response.");
182
+ }
101
183
  const txId = paymentDetail.transactionId;
102
184
  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.");
185
+ const amountPayment = paymentDetail.amount;
186
+ const receiverAddress = paymentDetail.receiverAddress;
187
+ const amount = ethers.parseUnits(amountPayment.toString(), 6);
188
+ if (!receiverAddress) {
189
+ throw new Error("Receiver address not found in payment details.");
107
190
  }
108
191
  const musdContract = new ethers.Contract(MUSD_ADDRESS, ERC20_ABI, this.wallet);
109
- const approveTx = await musdContract.approve(contractAddress, amountPayment);
192
+ console.log(`Approving MUSD spending for ${escrowAddress}...`);
193
+ const approveTx = await musdContract.approve(escrowAddress, amount);
110
194
  await approveTx.wait(1);
111
- const contract = new ethers.Contract(contractAddress, ESCROW_ABI, this.wallet);
195
+ console.log(`Initiating Expect Payment to ${escrowAddress} for creator ${receiverAddress} (${amount} wei)`);
196
+ const contract = new ethers.Contract(escrowAddress, ESCROW_ABI, this.wallet);
112
197
  const txResponse = await contract.createTx(
113
198
  txId,
114
- escrowAddress,
115
- amountPayment
199
+ receiverAddress,
200
+ amount
116
201
  );
202
+ console.log(`Escrow payment sent: ${txResponse.hash}. Waiting for confirmation...`);
117
203
  const receipt = await txResponse.wait(1);
118
204
  if (!receipt || receipt.status !== 1) {
119
205
  throw new Error("Escrow transaction failed.");
120
206
  }
121
207
  const finalTxHash = receipt.hash;
122
208
  const headers = {
123
- "x-payment-tx": finalTxHash,
124
- "Content-Type": "application/json"
209
+ "Content-Type": "application/json",
210
+ "Accept": "application/json",
211
+ "x-payment-tx": finalTxHash
125
212
  };
126
- const retryResponse = await fetch(`${BASE_ENDPOINT}/agent/${agentSlug}/chat`, {
213
+ console.log(`Retry with txHash: ${finalTxHash}`);
214
+ const retryResponse = await fetch(`${this.apiBaseUrl}/agent/escrow/${agentSlug}/chat`, {
127
215
  method: "POST",
128
216
  headers,
129
217
  body: JSON.stringify({
@@ -148,7 +236,70 @@ var PaymentService = class {
148
236
  */
149
237
  async getProxyEndpoint(gatewaySlug) {
150
238
  try {
151
- const initialResponse = await fetch(`${BASE_ENDPOINT}/escrow/${gatewaySlug}`);
239
+ let initialResponse;
240
+ try {
241
+ initialResponse = await fetch(`${this.apiBaseUrl}/${gatewaySlug}`);
242
+ } catch (e) {
243
+ throw new Error(`Initial Endpoint Failed: ${e}`);
244
+ }
245
+ if (initialResponse.ok) {
246
+ return await initialResponse.json();
247
+ }
248
+ if (initialResponse.status !== 402) {
249
+ throw new Error(`Unexpected status code: ${initialResponse.status}`);
250
+ }
251
+ const paymentDetail = await initialResponse.json();
252
+ if (!paymentDetail) {
253
+ throw new Error("Payment Detail not found.");
254
+ }
255
+ console.log("Payment Detail:", paymentDetail);
256
+ const amountPayment = paymentDetail.amount;
257
+ const receiverAddress = paymentDetail.receiverAddress;
258
+ const amount = ethers.parseUnits(amountPayment.toString(), 6);
259
+ if (!receiverAddress) {
260
+ throw new Error("Receiver address not found in payment details.");
261
+ }
262
+ const musdContract = new ethers.Contract(MUSD_ADDRESS, ERC20_ABI, this.wallet);
263
+ console.log(`Initiating Expect Payment to ${receiverAddress} (${amount} wei)`);
264
+ const txResponse = await musdContract.transfer(receiverAddress, amount);
265
+ console.log(`Payment sent: ${txResponse.hash}. Waiting for confirmation...`);
266
+ const receipt = await txResponse.wait(1);
267
+ if (!receipt || receipt.status !== 1) {
268
+ throw new Error("Payment transaction failed.");
269
+ }
270
+ const finalTxHash = receipt.hash;
271
+ const headers = {
272
+ "x-payment-tx": finalTxHash
273
+ };
274
+ console.log("view header: ", headers);
275
+ const retryResponse = await fetch(`${this.apiBaseUrl}/${gatewaySlug}`, {
276
+ method: "GET",
277
+ headers
278
+ });
279
+ if (!retryResponse.ok) {
280
+ const errorText = await retryResponse.text();
281
+ throw new Error(`Retry failed: ${retryResponse.status} - ${errorText}`);
282
+ }
283
+ return await retryResponse.json();
284
+ } catch (error) {
285
+ const errorMessage = error instanceof Error ? error : "Unknown error in getProxyEndpoint";
286
+ throw new Error(`Proxy Endpoint Failed: ${errorMessage}`);
287
+ }
288
+ }
289
+ /**
290
+ * Get proxy endpoint escrow
291
+ *
292
+ * @param gatewaySlug
293
+ * @returns
294
+ */
295
+ async getProxyEndpointEscrow(gatewaySlug) {
296
+ try {
297
+ let initialResponse;
298
+ try {
299
+ initialResponse = await fetch(`${this.apiBaseUrl}/escrow/${gatewaySlug}`);
300
+ } catch (e) {
301
+ throw new Error(`Initial Endpoint Failed: ${e}`);
302
+ }
152
303
  if (initialResponse.ok) {
153
304
  return await initialResponse.json();
154
305
  }
@@ -156,32 +307,40 @@ var PaymentService = class {
156
307
  throw new Error(`Unexpected status code: ${initialResponse.status}`);
157
308
  }
158
309
  const paymentDetail = await initialResponse.json();
310
+ if (!paymentDetail) {
311
+ throw new Error("Payment Detail not found.");
312
+ }
313
+ console.log("Payment Detail:", paymentDetail);
159
314
  const txId = paymentDetail.transactionId;
160
315
  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.");
316
+ const amountPayment = paymentDetail.amount;
317
+ const receiverAddress = paymentDetail.receiverAddress;
318
+ const amount = ethers.parseUnits(amountPayment.toString(), 6);
319
+ if (!receiverAddress) {
320
+ throw new Error("Receiver address not found in payment details.");
165
321
  }
166
322
  const musdContract = new ethers.Contract(MUSD_ADDRESS, ERC20_ABI, this.wallet);
167
- const approveTx = await musdContract.approve(contractAddress, amountPayment);
323
+ console.log(`Approving MUSD spending for ${escrowAddress}`);
324
+ const approveTx = await musdContract.approve(escrowAddress, amount);
168
325
  await approveTx.wait(1);
169
- const contract = new ethers.Contract(contractAddress, ESCROW_ABI, this.wallet);
326
+ console.log(`Initiating Expect Payment to ${escrowAddress} for creator ${receiverAddress} (${amount} wei)`);
327
+ const contract = new ethers.Contract(escrowAddress, ESCROW_ABI, this.wallet);
170
328
  const txResponse = await contract.createTx(
171
329
  txId,
172
- escrowAddress,
173
- amountPayment
330
+ receiverAddress,
331
+ amount
174
332
  );
333
+ console.log(`Escrow payment sent: ${txResponse.hash}. Waiting for confirmation...`);
175
334
  const receipt = await txResponse.wait(1);
176
335
  if (!receipt || receipt.status !== 1) {
177
336
  throw new Error("Escrow transaction failed.");
178
337
  }
179
338
  const finalTxHash = receipt.hash;
180
339
  const headers = {
181
- "x-payment-tx": finalTxHash,
182
- "Content-Type": "application/json"
340
+ "x-payment-tx": finalTxHash
183
341
  };
184
- const retryResponse = await fetch(`${BASE_ENDPOINT}/${gatewaySlug}`, {
342
+ console.log("view header: ", headers);
343
+ const retryResponse = await fetch(`${this.apiBaseUrl}/escrow/${gatewaySlug}`, {
185
344
  method: "GET",
186
345
  headers
187
346
  });
@@ -191,7 +350,7 @@ var PaymentService = class {
191
350
  }
192
351
  return await retryResponse.json();
193
352
  } catch (error) {
194
- const errorMessage = error instanceof Error ? error.message : "Unknown error in getProxyEndpoint";
353
+ const errorMessage = error instanceof Error ? error : "Unknown error in getProxyEndpoint";
195
354
  throw new Error(`Proxy Endpoint Failed: ${errorMessage}`);
196
355
  }
197
356
  }
package/package.json CHANGED
@@ -1,10 +1,27 @@
1
1
  {
2
2
  "name": "@payroute/x402-sdk",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "SDK for automation payment gateway with x402",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
7
7
  "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": {
11
+ "types": "./dist/index.d.mts",
12
+ "default": "./dist/index.mjs"
13
+ },
14
+ "require": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ }
18
+ }
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "README.md",
23
+ "LICENSE"
24
+ ],
8
25
  "scripts": {
9
26
  "build": "tsup"
10
27
  },