@payroute/x402-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,110 @@
1
+ # Payroute x402 SDK
2
+
3
+ The official Node.js and TypeScript SDK for the **Payroute Protocol** on Mantle Network.
4
+
5
+ This SDK abstracts the complexity of **HTTP 402 Pay-Per-Hit** workflows, enabling seamless autonomous payments for premium APIs, static content, and AI Agents. It handles wallet management, token approvals, on-chain escrow transactions, and automatic request retries.
6
+
7
+ ## Features
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.
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install payroute-x402-sdk ethers
19
+ ```
20
+
21
+ _Note: `ethers` peer dependency (v6) is required._
22
+
23
+ ## Quick Start
24
+
25
+ ### 1. Initialize the Service
26
+
27
+ ```typescript
28
+ import { PaymentService } from "payroute-x402-sdk";
29
+
30
+ const service = new PaymentService({
31
+ privateKey: process.env.WALLET_PRIVATE_KEY, // Your EVM private key
32
+ network: "mantle", // 'mantle' | 'mantleTestnet' | 'localhost'
33
+ });
34
+ ```
35
+
36
+ ### 2. Consume a Paid Proxy Endpoint
37
+
38
+ Access premium content served behind a Payroute gateway.
39
+
40
+ ```typescript
41
+ try {
42
+ const content = await service.getProxyEndpoint("my-premium-blog-post");
43
+ console.log("Accessed Content:", content);
44
+ } catch (error) {
45
+ console.error("Payment or Fetch Failed:", error);
46
+ }
47
+ ```
48
+
49
+ ### 3. Interact with a Paid AI Agent
50
+
51
+ Send messages to an AI agent that requires per-message payments.
52
+
53
+ ```typescript
54
+ try {
55
+ const response = await service.generateAIResponse(
56
+ "finance-advisor-agent",
57
+ "What is the outlook for MNT?"
58
+ );
59
+ console.log("AI Response:", response);
60
+ } catch (error) {
61
+ console.error("Agent Interaction Failed:", error);
62
+ }
63
+ ```
64
+
65
+ ## Advanced Usage
66
+
67
+ ### Custom RPC Provider
68
+
69
+ You can override the default RPC URLs for custom configuration.
70
+
71
+ ```typescript
72
+ const service = new PaymentService({
73
+ privateKey: "...",
74
+ rpcUrl: "https://rpc.ankr.com/mantle",
75
+ });
76
+ ```
77
+
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
+ ## Architecture
97
+
98
+ The SDK implements the **Payroute x402 Protocol**:
99
+
100
+ 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.
104
+ 5. **Confirmation**: SDK waits for blockchain confirmation.
105
+ 6. **Retry**: SDK retries the original request with the transaction hash in the `x-payment-tx` header.
106
+ 7. **Response**: Server validates the transaction and returns the content.
107
+
108
+ ## License
109
+
110
+ MIT © [Payroute Protocol](https://github.com/payroute-protocol)
@@ -0,0 +1,56 @@
1
+ /**
2
+ * PaymentData interface for transaction details
3
+ */
4
+ interface PaymentData {
5
+ amount: string;
6
+ recipient: string;
7
+ currency?: string;
8
+ }
9
+ /**
10
+ * Configuration options for the PaymentService
11
+ */
12
+ interface PaymentServiceConfig {
13
+ privateKey: string;
14
+ network?: 'mantle' | 'mantleTestnet' | 'localhost';
15
+ rpcUrl?: string;
16
+ }
17
+ /**
18
+ * PaymentService class
19
+ * Handles EVM wallet initialization, transaction signing, and payment flow with retries.
20
+ */
21
+ declare class PaymentService {
22
+ private wallet;
23
+ private provider;
24
+ constructor(config: PaymentServiceConfig);
25
+ /**
26
+ * Performs a payment on-chain and retries the original request with proof of payment.
27
+ *
28
+ * @param params.paymentData - The payment details (amount, recipient).
29
+ * @param params.retryRequest - A callback that performs the HTTP request. Must accept headers.
30
+ * @returns The response from the retried request.
31
+ */
32
+ payAndRetry<T>(params: {
33
+ paymentData: PaymentData;
34
+ retryRequest: (headers: Record<string, string>) => Promise<T>;
35
+ }): Promise<T>;
36
+ /**
37
+ * Get AI response
38
+ *
39
+ * @param agentSlug
40
+ * @returns
41
+ */
42
+ generateAIResponse<T = any>(agentSlug: string, message: string): Promise<T>;
43
+ /**
44
+ * Get proxy endpoint
45
+ *
46
+ * @param gatewaySlug
47
+ * @returns
48
+ */
49
+ getProxyEndpoint<T = any>(gatewaySlug: string): Promise<T>;
50
+ /**
51
+ * Helper to get the current wallet address
52
+ */
53
+ getAddress(): string;
54
+ }
55
+
56
+ export { type PaymentData, PaymentService, type PaymentServiceConfig };
@@ -0,0 +1,56 @@
1
+ /**
2
+ * PaymentData interface for transaction details
3
+ */
4
+ interface PaymentData {
5
+ amount: string;
6
+ recipient: string;
7
+ currency?: string;
8
+ }
9
+ /**
10
+ * Configuration options for the PaymentService
11
+ */
12
+ interface PaymentServiceConfig {
13
+ privateKey: string;
14
+ network?: 'mantle' | 'mantleTestnet' | 'localhost';
15
+ rpcUrl?: string;
16
+ }
17
+ /**
18
+ * PaymentService class
19
+ * Handles EVM wallet initialization, transaction signing, and payment flow with retries.
20
+ */
21
+ declare class PaymentService {
22
+ private wallet;
23
+ private provider;
24
+ constructor(config: PaymentServiceConfig);
25
+ /**
26
+ * Performs a payment on-chain and retries the original request with proof of payment.
27
+ *
28
+ * @param params.paymentData - The payment details (amount, recipient).
29
+ * @param params.retryRequest - A callback that performs the HTTP request. Must accept headers.
30
+ * @returns The response from the retried request.
31
+ */
32
+ payAndRetry<T>(params: {
33
+ paymentData: PaymentData;
34
+ retryRequest: (headers: Record<string, string>) => Promise<T>;
35
+ }): Promise<T>;
36
+ /**
37
+ * Get AI response
38
+ *
39
+ * @param agentSlug
40
+ * @returns
41
+ */
42
+ generateAIResponse<T = any>(agentSlug: string, message: string): Promise<T>;
43
+ /**
44
+ * Get proxy endpoint
45
+ *
46
+ * @param gatewaySlug
47
+ * @returns
48
+ */
49
+ getProxyEndpoint<T = any>(gatewaySlug: string): Promise<T>;
50
+ /**
51
+ * Helper to get the current wallet address
52
+ */
53
+ getAddress(): string;
54
+ }
55
+
56
+ export { type PaymentData, PaymentService, type PaymentServiceConfig };
package/dist/index.js ADDED
@@ -0,0 +1,234 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ PaymentService: () => PaymentService
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+
27
+ // src/PaymentService.ts
28
+ var import_ethers = require("ethers");
29
+ var NETWORKS = {
30
+ mantle: {
31
+ name: "Mantle Mainnet",
32
+ rpc: "https://rpc.mantle.xyz",
33
+ chainId: 5e3
34
+ },
35
+ mantleTestnet: {
36
+ name: "Mantle Testnet",
37
+ rpc: "https://rpc.sepolia.mantle.xyz",
38
+ chainId: 5003
39
+ },
40
+ localhost: {
41
+ name: "Localhost",
42
+ rpc: "http://127.0.0.1:8545",
43
+ chainId: 31337
44
+ }
45
+ };
46
+ var BASE_ENDPOINT = "https://x402-services.vercel.app";
47
+ var ESCROW_ABI = [
48
+ "function createTx(string txId, address creator, uint256 amount) external payable"
49
+ ];
50
+ var MUSD_ADDRESS = "0x4dABf45C8cF333Ef1e874c3FDFC3C86799af80c8";
51
+ var ERC20_ABI = [
52
+ "function approve(address spender, uint256 amount) external returns (bool)"
53
+ ];
54
+ var PaymentService = class {
55
+ wallet;
56
+ provider;
57
+ constructor(config) {
58
+ const networkKey = config.network || "mantle";
59
+ const networkConfig = NETWORKS[networkKey];
60
+ if (!networkConfig && !config.rpcUrl) {
61
+ throw new Error(`Invalid network: ${networkKey} and no RPC URL provided.`);
62
+ }
63
+ const rpcUrl = config.rpcUrl || networkConfig?.rpc;
64
+ this.provider = new import_ethers.ethers.JsonRpcProvider(rpcUrl);
65
+ try {
66
+ this.wallet = new import_ethers.ethers.Wallet(config.privateKey, this.provider);
67
+ } catch (error) {
68
+ throw new Error("Invalid private key provided.");
69
+ }
70
+ }
71
+ /**
72
+ * Performs a payment on-chain and retries the original request with proof of payment.
73
+ *
74
+ * @param params.paymentData - The payment details (amount, recipient).
75
+ * @param params.retryRequest - A callback that performs the HTTP request. Must accept headers.
76
+ * @returns The response from the retried request.
77
+ */
78
+ async payAndRetry(params) {
79
+ const { paymentData, retryRequest } = params;
80
+ try {
81
+ if (!import_ethers.ethers.isAddress(paymentData.recipient)) {
82
+ throw new Error(`Invalid recipient address: ${paymentData.recipient}`);
83
+ }
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);
90
+ const receipt = await txResponse.wait(1);
91
+ if (!receipt || receipt.status !== 1) {
92
+ throw new Error("Transaction failed or was reverted on-chain.");
93
+ }
94
+ const txHash = receipt.hash;
95
+ const headers = {
96
+ "X-Payment-Tx": txHash,
97
+ "Content-Type": "application/json"
98
+ // Default content type, extendable if needed
99
+ };
100
+ return await retryRequest(headers);
101
+ } catch (error) {
102
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred during payment flow";
103
+ throw new Error(`PaymentService Failed: ${errorMessage}`);
104
+ }
105
+ }
106
+ /**
107
+ * Get AI response
108
+ *
109
+ * @param agentSlug
110
+ * @returns
111
+ */
112
+ async generateAIResponse(agentSlug, message) {
113
+ try {
114
+ const initialResponse = await fetch(`${BASE_ENDPOINT}/agent/${agentSlug}/chat`, {
115
+ method: "POST",
116
+ headers: {
117
+ "Content-Type": "application/json"
118
+ },
119
+ body: JSON.stringify({
120
+ message
121
+ })
122
+ });
123
+ if (!initialResponse.ok && initialResponse.status !== 402) {
124
+ throw new Error(`Unexpected status code: ${initialResponse.status}`);
125
+ }
126
+ const paymentDetail = await initialResponse.json();
127
+ const txId = paymentDetail.transactionId;
128
+ 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.");
133
+ }
134
+ const musdContract = new import_ethers.ethers.Contract(MUSD_ADDRESS, ERC20_ABI, this.wallet);
135
+ const approveTx = await musdContract.approve(contractAddress, amountPayment);
136
+ await approveTx.wait(1);
137
+ const contract = new import_ethers.ethers.Contract(contractAddress, ESCROW_ABI, this.wallet);
138
+ const txResponse = await contract.createTx(
139
+ txId,
140
+ escrowAddress,
141
+ amountPayment
142
+ );
143
+ const receipt = await txResponse.wait(1);
144
+ if (!receipt || receipt.status !== 1) {
145
+ throw new Error("Escrow transaction failed.");
146
+ }
147
+ const finalTxHash = receipt.hash;
148
+ const headers = {
149
+ "x-payment-tx": finalTxHash,
150
+ "Content-Type": "application/json"
151
+ };
152
+ const retryResponse = await fetch(`${BASE_ENDPOINT}/agent/${agentSlug}/chat`, {
153
+ method: "POST",
154
+ headers,
155
+ body: JSON.stringify({
156
+ message
157
+ })
158
+ });
159
+ if (!retryResponse.ok) {
160
+ const errorText = await retryResponse.text();
161
+ throw new Error(`Retry failed: ${retryResponse.status} - ${errorText}`);
162
+ }
163
+ return await retryResponse.json();
164
+ } catch (error) {
165
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred during payment flow";
166
+ throw new Error(`PaymentService Failed: ${errorMessage}`);
167
+ }
168
+ }
169
+ /**
170
+ * Get proxy endpoint
171
+ *
172
+ * @param gatewaySlug
173
+ * @returns
174
+ */
175
+ async getProxyEndpoint(gatewaySlug) {
176
+ try {
177
+ const initialResponse = await fetch(`${BASE_ENDPOINT}/escrow/${gatewaySlug}`);
178
+ if (initialResponse.ok) {
179
+ return await initialResponse.json();
180
+ }
181
+ if (initialResponse.status !== 402) {
182
+ throw new Error(`Unexpected status code: ${initialResponse.status}`);
183
+ }
184
+ const paymentDetail = await initialResponse.json();
185
+ const txId = paymentDetail.transactionId;
186
+ 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.");
191
+ }
192
+ const musdContract = new import_ethers.ethers.Contract(MUSD_ADDRESS, ERC20_ABI, this.wallet);
193
+ const approveTx = await musdContract.approve(contractAddress, amountPayment);
194
+ await approveTx.wait(1);
195
+ const contract = new import_ethers.ethers.Contract(contractAddress, ESCROW_ABI, this.wallet);
196
+ const txResponse = await contract.createTx(
197
+ txId,
198
+ escrowAddress,
199
+ amountPayment
200
+ );
201
+ const receipt = await txResponse.wait(1);
202
+ if (!receipt || receipt.status !== 1) {
203
+ throw new Error("Escrow transaction failed.");
204
+ }
205
+ const finalTxHash = receipt.hash;
206
+ const headers = {
207
+ "x-payment-tx": finalTxHash,
208
+ "Content-Type": "application/json"
209
+ };
210
+ const retryResponse = await fetch(`${BASE_ENDPOINT}/${gatewaySlug}`, {
211
+ method: "GET",
212
+ headers
213
+ });
214
+ if (!retryResponse.ok) {
215
+ const errorText = await retryResponse.text();
216
+ throw new Error(`Retry failed: ${retryResponse.status} - ${errorText}`);
217
+ }
218
+ return await retryResponse.json();
219
+ } catch (error) {
220
+ const errorMessage = error instanceof Error ? error.message : "Unknown error in getProxyEndpoint";
221
+ throw new Error(`Proxy Endpoint Failed: ${errorMessage}`);
222
+ }
223
+ }
224
+ /**
225
+ * Helper to get the current wallet address
226
+ */
227
+ getAddress() {
228
+ return this.wallet.address;
229
+ }
230
+ };
231
+ // Annotate the CommonJS export names for ESM import in node:
232
+ 0 && (module.exports = {
233
+ PaymentService
234
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,207 @@
1
+ // src/PaymentService.ts
2
+ import { ethers } from "ethers";
3
+ var NETWORKS = {
4
+ mantle: {
5
+ name: "Mantle Mainnet",
6
+ rpc: "https://rpc.mantle.xyz",
7
+ chainId: 5e3
8
+ },
9
+ mantleTestnet: {
10
+ name: "Mantle Testnet",
11
+ rpc: "https://rpc.sepolia.mantle.xyz",
12
+ chainId: 5003
13
+ },
14
+ localhost: {
15
+ name: "Localhost",
16
+ rpc: "http://127.0.0.1:8545",
17
+ chainId: 31337
18
+ }
19
+ };
20
+ var BASE_ENDPOINT = "https://x402-services.vercel.app";
21
+ var ESCROW_ABI = [
22
+ "function createTx(string txId, address creator, uint256 amount) external payable"
23
+ ];
24
+ var MUSD_ADDRESS = "0x4dABf45C8cF333Ef1e874c3FDFC3C86799af80c8";
25
+ var ERC20_ABI = [
26
+ "function approve(address spender, uint256 amount) external returns (bool)"
27
+ ];
28
+ var PaymentService = class {
29
+ wallet;
30
+ provider;
31
+ constructor(config) {
32
+ const networkKey = config.network || "mantle";
33
+ const networkConfig = NETWORKS[networkKey];
34
+ if (!networkConfig && !config.rpcUrl) {
35
+ throw new Error(`Invalid network: ${networkKey} and no RPC URL provided.`);
36
+ }
37
+ const rpcUrl = config.rpcUrl || networkConfig?.rpc;
38
+ this.provider = new ethers.JsonRpcProvider(rpcUrl);
39
+ try {
40
+ this.wallet = new ethers.Wallet(config.privateKey, this.provider);
41
+ } catch (error) {
42
+ throw new Error("Invalid private key provided.");
43
+ }
44
+ }
45
+ /**
46
+ * Performs a payment on-chain and retries the original request with proof of payment.
47
+ *
48
+ * @param params.paymentData - The payment details (amount, recipient).
49
+ * @param params.retryRequest - A callback that performs the HTTP request. Must accept headers.
50
+ * @returns The response from the retried request.
51
+ */
52
+ async payAndRetry(params) {
53
+ const { paymentData, retryRequest } = params;
54
+ try {
55
+ if (!ethers.isAddress(paymentData.recipient)) {
56
+ throw new Error(`Invalid recipient address: ${paymentData.recipient}`);
57
+ }
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);
64
+ const receipt = await txResponse.wait(1);
65
+ if (!receipt || receipt.status !== 1) {
66
+ throw new Error("Transaction failed or was reverted on-chain.");
67
+ }
68
+ const txHash = receipt.hash;
69
+ const headers = {
70
+ "X-Payment-Tx": txHash,
71
+ "Content-Type": "application/json"
72
+ // Default content type, extendable if needed
73
+ };
74
+ return await retryRequest(headers);
75
+ } catch (error) {
76
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred during payment flow";
77
+ throw new Error(`PaymentService Failed: ${errorMessage}`);
78
+ }
79
+ }
80
+ /**
81
+ * Get AI response
82
+ *
83
+ * @param agentSlug
84
+ * @returns
85
+ */
86
+ async generateAIResponse(agentSlug, message) {
87
+ try {
88
+ const initialResponse = await fetch(`${BASE_ENDPOINT}/agent/${agentSlug}/chat`, {
89
+ method: "POST",
90
+ headers: {
91
+ "Content-Type": "application/json"
92
+ },
93
+ body: JSON.stringify({
94
+ message
95
+ })
96
+ });
97
+ if (!initialResponse.ok && initialResponse.status !== 402) {
98
+ throw new Error(`Unexpected status code: ${initialResponse.status}`);
99
+ }
100
+ const paymentDetail = await initialResponse.json();
101
+ const txId = paymentDetail.transactionId;
102
+ 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.");
107
+ }
108
+ const musdContract = new ethers.Contract(MUSD_ADDRESS, ERC20_ABI, this.wallet);
109
+ const approveTx = await musdContract.approve(contractAddress, amountPayment);
110
+ await approveTx.wait(1);
111
+ const contract = new ethers.Contract(contractAddress, ESCROW_ABI, this.wallet);
112
+ const txResponse = await contract.createTx(
113
+ txId,
114
+ escrowAddress,
115
+ amountPayment
116
+ );
117
+ const receipt = await txResponse.wait(1);
118
+ if (!receipt || receipt.status !== 1) {
119
+ throw new Error("Escrow transaction failed.");
120
+ }
121
+ const finalTxHash = receipt.hash;
122
+ const headers = {
123
+ "x-payment-tx": finalTxHash,
124
+ "Content-Type": "application/json"
125
+ };
126
+ const retryResponse = await fetch(`${BASE_ENDPOINT}/agent/${agentSlug}/chat`, {
127
+ method: "POST",
128
+ headers,
129
+ body: JSON.stringify({
130
+ message
131
+ })
132
+ });
133
+ if (!retryResponse.ok) {
134
+ const errorText = await retryResponse.text();
135
+ throw new Error(`Retry failed: ${retryResponse.status} - ${errorText}`);
136
+ }
137
+ return await retryResponse.json();
138
+ } catch (error) {
139
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred during payment flow";
140
+ throw new Error(`PaymentService Failed: ${errorMessage}`);
141
+ }
142
+ }
143
+ /**
144
+ * Get proxy endpoint
145
+ *
146
+ * @param gatewaySlug
147
+ * @returns
148
+ */
149
+ async getProxyEndpoint(gatewaySlug) {
150
+ try {
151
+ const initialResponse = await fetch(`${BASE_ENDPOINT}/escrow/${gatewaySlug}`);
152
+ if (initialResponse.ok) {
153
+ return await initialResponse.json();
154
+ }
155
+ if (initialResponse.status !== 402) {
156
+ throw new Error(`Unexpected status code: ${initialResponse.status}`);
157
+ }
158
+ const paymentDetail = await initialResponse.json();
159
+ const txId = paymentDetail.transactionId;
160
+ 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.");
165
+ }
166
+ const musdContract = new ethers.Contract(MUSD_ADDRESS, ERC20_ABI, this.wallet);
167
+ const approveTx = await musdContract.approve(contractAddress, amountPayment);
168
+ await approveTx.wait(1);
169
+ const contract = new ethers.Contract(contractAddress, ESCROW_ABI, this.wallet);
170
+ const txResponse = await contract.createTx(
171
+ txId,
172
+ escrowAddress,
173
+ amountPayment
174
+ );
175
+ const receipt = await txResponse.wait(1);
176
+ if (!receipt || receipt.status !== 1) {
177
+ throw new Error("Escrow transaction failed.");
178
+ }
179
+ const finalTxHash = receipt.hash;
180
+ const headers = {
181
+ "x-payment-tx": finalTxHash,
182
+ "Content-Type": "application/json"
183
+ };
184
+ const retryResponse = await fetch(`${BASE_ENDPOINT}/${gatewaySlug}`, {
185
+ method: "GET",
186
+ headers
187
+ });
188
+ if (!retryResponse.ok) {
189
+ const errorText = await retryResponse.text();
190
+ throw new Error(`Retry failed: ${retryResponse.status} - ${errorText}`);
191
+ }
192
+ return await retryResponse.json();
193
+ } catch (error) {
194
+ const errorMessage = error instanceof Error ? error.message : "Unknown error in getProxyEndpoint";
195
+ throw new Error(`Proxy Endpoint Failed: ${errorMessage}`);
196
+ }
197
+ }
198
+ /**
199
+ * Helper to get the current wallet address
200
+ */
201
+ getAddress() {
202
+ return this.wallet.address;
203
+ }
204
+ };
205
+ export {
206
+ PaymentService
207
+ };
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@payroute/x402-sdk",
3
+ "version": "1.0.0",
4
+ "description": "SDK for automation payment gateway with x402",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "scripts": {
9
+ "build": "tsup"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/payroute-protocol/payroute-x402-sdk.git"
14
+ },
15
+ "keywords": [
16
+ "x402",
17
+ "payroute",
18
+ "payment",
19
+ "gateway",
20
+ "sdk"
21
+ ],
22
+ "author": "",
23
+ "license": "MIT",
24
+ "bugs": {
25
+ "url": "https://github.com/payroute-protocol/payroute-x402-sdk/issues"
26
+ },
27
+ "homepage": "https://github.com/payroute-protocol/payroute-x402-sdk#readme",
28
+ "devDependencies": {
29
+ "tsup": "^8.5.1",
30
+ "typescript": "^5.9.3",
31
+ "vitest": "^4.0.16"
32
+ },
33
+ "dependencies": {
34
+ "ethers": "^6.16.0"
35
+ }
36
+ }