@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 +111 -27
- package/dist/index.d.mts +16 -4
- package/dist/index.d.ts +16 -4
- package/dist/index.js +209 -50
- package/dist/index.mjs +209 -50
- package/package.json +18 -1
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
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
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
|
|
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
|
|
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("
|
|
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
|
-
"
|
|
57
|
-
"
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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 (
|
|
102
|
-
3. **Approval**: SDK approves the required token (MUSD) for the escrow contract.
|
|
103
|
-
4. **Payment**:
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
82
|
-
|
|
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
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const
|
|
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("
|
|
160
|
+
throw new Error("Payment transaction failed.");
|
|
93
161
|
}
|
|
94
|
-
const
|
|
162
|
+
const finalTxHash = receipt.hash;
|
|
95
163
|
const headers = {
|
|
96
|
-
"
|
|
97
|
-
"
|
|
98
|
-
// Default content type, extendable if needed
|
|
164
|
+
"Content-Type": "application/json",
|
|
165
|
+
"x-payment-tx": finalTxHash
|
|
99
166
|
};
|
|
100
|
-
|
|
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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
async
|
|
186
|
+
* Get AI response
|
|
187
|
+
*
|
|
188
|
+
* @param agentSlug
|
|
189
|
+
* @returns
|
|
190
|
+
*/
|
|
191
|
+
async generateAIResponseEscrow(agentSlug, message) {
|
|
113
192
|
try {
|
|
114
|
-
const initialResponse = await fetch(`${
|
|
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.
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
218
|
+
console.log(`Approving MUSD spending for ${escrowAddress}...`);
|
|
219
|
+
const approveTx = await musdContract.approve(escrowAddress, amount);
|
|
136
220
|
await approveTx.wait(1);
|
|
137
|
-
|
|
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
|
-
|
|
141
|
-
|
|
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
|
-
"
|
|
150
|
-
"
|
|
235
|
+
"Content-Type": "application/json",
|
|
236
|
+
"Accept": "application/json",
|
|
237
|
+
"x-payment-tx": finalTxHash
|
|
151
238
|
};
|
|
152
|
-
|
|
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
|
-
|
|
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.
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
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
|
-
|
|
349
|
+
console.log(`Approving MUSD spending for ${escrowAddress}`);
|
|
350
|
+
const approveTx = await musdContract.approve(escrowAddress, amount);
|
|
194
351
|
await approveTx.wait(1);
|
|
195
|
-
|
|
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
|
-
|
|
199
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
56
|
-
|
|
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
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const
|
|
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("
|
|
134
|
+
throw new Error("Payment transaction failed.");
|
|
67
135
|
}
|
|
68
|
-
const
|
|
136
|
+
const finalTxHash = receipt.hash;
|
|
69
137
|
const headers = {
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
// Default content type, extendable if needed
|
|
138
|
+
"Content-Type": "application/json",
|
|
139
|
+
"x-payment-tx": finalTxHash
|
|
73
140
|
};
|
|
74
|
-
|
|
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
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
async
|
|
160
|
+
* Get AI response
|
|
161
|
+
*
|
|
162
|
+
* @param agentSlug
|
|
163
|
+
* @returns
|
|
164
|
+
*/
|
|
165
|
+
async generateAIResponseEscrow(agentSlug, message) {
|
|
87
166
|
try {
|
|
88
|
-
const initialResponse = await fetch(`${
|
|
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.
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
|
|
192
|
+
console.log(`Approving MUSD spending for ${escrowAddress}...`);
|
|
193
|
+
const approveTx = await musdContract.approve(escrowAddress, amount);
|
|
110
194
|
await approveTx.wait(1);
|
|
111
|
-
|
|
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
|
-
|
|
115
|
-
|
|
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
|
-
"
|
|
124
|
-
"
|
|
209
|
+
"Content-Type": "application/json",
|
|
210
|
+
"Accept": "application/json",
|
|
211
|
+
"x-payment-tx": finalTxHash
|
|
125
212
|
};
|
|
126
|
-
|
|
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
|
-
|
|
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.
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
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
|
-
|
|
323
|
+
console.log(`Approving MUSD spending for ${escrowAddress}`);
|
|
324
|
+
const approveTx = await musdContract.approve(escrowAddress, amount);
|
|
168
325
|
await approveTx.wait(1);
|
|
169
|
-
|
|
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
|
-
|
|
173
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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
|
},
|