@coinbase/agentkit 0.10.3 → 0.10.4
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 +47 -10
- package/dist/action-providers/across/acrossActionProvider.js +2 -4
- package/dist/action-providers/across/acrossActionProvider.test.js +10 -5
- package/dist/action-providers/baseAccount/baseAccountActionProvider.js +5 -7
- package/dist/action-providers/clanker/utils.d.ts +2 -1
- package/dist/action-providers/clanker/utils.js +2 -2
- package/dist/action-providers/index.d.ts +1 -0
- package/dist/action-providers/index.js +1 -0
- package/dist/action-providers/jupiter/jupiterActionProvider.js +2 -2
- package/dist/action-providers/spl/splActionProvider.js +12 -13
- package/dist/action-providers/superfluid/graphQueries/superfluidGraphQueries.js +2 -2
- package/dist/action-providers/sushi/constants.d.ts +35 -0
- package/dist/action-providers/sushi/constants.js +7 -0
- package/dist/action-providers/sushi/index.d.ts +4 -0
- package/dist/action-providers/sushi/index.js +20 -0
- package/dist/action-providers/sushi/sushiDataActionProvider.d.ts +32 -0
- package/dist/action-providers/sushi/sushiDataActionProvider.js +113 -0
- package/dist/action-providers/sushi/sushiDataSchemas.d.ts +11 -0
- package/dist/action-providers/sushi/sushiDataSchemas.js +16 -0
- package/dist/action-providers/sushi/sushiRouterActionProvider.d.ts +40 -0
- package/dist/action-providers/sushi/sushiRouterActionProvider.js +386 -0
- package/dist/action-providers/sushi/sushiRouterActionProvider.test.d.ts +1 -0
- package/dist/action-providers/sushi/sushiRouterActionProvider.test.js +392 -0
- package/dist/action-providers/sushi/sushiRouterSchemas.d.ts +36 -0
- package/dist/action-providers/sushi/sushiRouterSchemas.js +55 -0
- package/dist/action-providers/vaultsfyi/constants.d.ts +8 -12
- package/dist/action-providers/vaultsfyi/constants.js +47 -13
- package/dist/action-providers/vaultsfyi/schemas.d.ts +120 -65
- package/dist/action-providers/vaultsfyi/schemas.js +72 -38
- package/dist/action-providers/vaultsfyi/sdk.d.ts +8 -0
- package/dist/action-providers/vaultsfyi/sdk.js +15 -0
- package/dist/action-providers/vaultsfyi/utils.d.ts +151 -55
- package/dist/action-providers/vaultsfyi/utils.js +29 -75
- package/dist/action-providers/vaultsfyi/vaultsfyiActionProvider.d.ts +55 -16
- package/dist/action-providers/vaultsfyi/vaultsfyiActionProvider.js +413 -217
- package/dist/action-providers/vaultsfyi/vaultsfyiActionProvider.test.js +509 -316
- package/dist/action-providers/x402/constants.d.ts +67 -0
- package/dist/action-providers/x402/constants.js +37 -0
- package/dist/action-providers/x402/schemas.d.ts +45 -5
- package/dist/action-providers/x402/schemas.js +81 -11
- package/dist/action-providers/x402/utils.d.ts +85 -10
- package/dist/action-providers/x402/utils.js +302 -35
- package/dist/action-providers/x402/x402ActionProvider.d.ts +15 -1
- package/dist/action-providers/x402/x402ActionProvider.js +230 -179
- package/dist/action-providers/x402/x402ActionProvider.test.js +222 -262
- package/dist/action-providers/zora/zoraActionProvider.js +4 -5
- package/package.json +10 -7
- package/dist/action-providers/vaultsfyi/api/actions.d.ts +0 -41
- package/dist/action-providers/vaultsfyi/api/actions.js +0 -28
- package/dist/action-providers/vaultsfyi/api/historicalData.d.ts +0 -31
- package/dist/action-providers/vaultsfyi/api/historicalData.js +0 -44
- package/dist/action-providers/vaultsfyi/api/types.d.ts +0 -34
- package/dist/action-providers/vaultsfyi/api/types.js +0 -2
- package/dist/action-providers/vaultsfyi/api/vaults.d.ts +0 -66
- package/dist/action-providers/vaultsfyi/api/vaults.js +0 -57
|
@@ -8,9 +8,6 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
8
8
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
9
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
10
|
};
|
|
11
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
-
};
|
|
14
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
12
|
exports.x402ActionProvider = exports.X402ActionProvider = void 0;
|
|
16
13
|
const zod_1 = require("zod");
|
|
@@ -18,12 +15,11 @@ const actionProvider_1 = require("../actionProvider");
|
|
|
18
15
|
const actionDecorator_1 = require("../actionDecorator");
|
|
19
16
|
const schemas_1 = require("./schemas");
|
|
20
17
|
const wallet_providers_1 = require("../../wallet-providers");
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const x402_1 = require("@coinbase/x402");
|
|
18
|
+
const fetch_1 = require("@x402/fetch");
|
|
19
|
+
const client_1 = require("@x402/evm/exact/client");
|
|
20
|
+
const client_2 = require("@x402/svm/exact/client");
|
|
25
21
|
const utils_1 = require("./utils");
|
|
26
|
-
const
|
|
22
|
+
const constants_1 = require("./constants");
|
|
27
23
|
/**
|
|
28
24
|
* X402ActionProvider provides actions for making HTTP requests, with optional x402 payment handling.
|
|
29
25
|
*/
|
|
@@ -40,107 +36,50 @@ class X402ActionProvider extends actionProvider_1.ActionProvider {
|
|
|
40
36
|
* @param network - The network to check support for
|
|
41
37
|
* @returns True if the network is supported, false otherwise
|
|
42
38
|
*/
|
|
43
|
-
this.supportsNetwork = (network) => SUPPORTED_NETWORKS.includes(network.networkId);
|
|
39
|
+
this.supportsNetwork = (network) => constants_1.SUPPORTED_NETWORKS.includes(network.networkId);
|
|
44
40
|
}
|
|
45
41
|
/**
|
|
46
42
|
* Discovers available x402 services with optional filtering.
|
|
47
43
|
*
|
|
48
44
|
* @param walletProvider - The wallet provider to use for network filtering
|
|
49
|
-
* @param args - Optional filters: maxUsdcPrice
|
|
45
|
+
* @param args - Optional filters: discoveryUrl, maxUsdcPrice
|
|
50
46
|
* @returns JSON string with the list of services (filtered by network and description)
|
|
51
47
|
*/
|
|
52
48
|
async discoverX402Services(walletProvider, args) {
|
|
53
49
|
try {
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
50
|
+
console.log("args", args);
|
|
51
|
+
const facilitatorUrl = (0, schemas_1.resolveFacilitatorUrl)(args.facilitator);
|
|
52
|
+
const discoveryUrl = facilitatorUrl + "/discovery/resources";
|
|
53
|
+
// Fetch all resources with pagination
|
|
54
|
+
const allResources = await (0, utils_1.fetchAllDiscoveryResources)(discoveryUrl);
|
|
55
|
+
if (allResources.length === 0) {
|
|
57
56
|
return JSON.stringify({
|
|
58
57
|
error: true,
|
|
59
58
|
message: "No services found",
|
|
60
59
|
});
|
|
61
60
|
}
|
|
62
|
-
// Get the
|
|
63
|
-
const
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const hasMatchingNetwork = accepts.some(req => req.network === walletNetwork);
|
|
72
|
-
// Filter out services with empty or default descriptions
|
|
73
|
-
const hasDescription = accepts.some(req => req.description &&
|
|
74
|
-
req.description.trim() !== "" &&
|
|
75
|
-
req.description.trim() !== "Access to protected content");
|
|
76
|
-
return hasMatchingNetwork && hasDescription;
|
|
77
|
-
});
|
|
78
|
-
// Apply USDC price filtering if maxUsdcPrice is provided (only consider USDC assets)
|
|
79
|
-
let priceFilteredServices = filteredServices;
|
|
80
|
-
if (hasValidMaxUsdcPrice) {
|
|
81
|
-
priceFilteredServices = [];
|
|
82
|
-
for (const item of filteredServices) {
|
|
83
|
-
const accepts = Array.isArray(item.accepts) ? item.accepts : [];
|
|
84
|
-
let shouldInclude = false;
|
|
85
|
-
for (const req of accepts) {
|
|
86
|
-
if (req.network === walletNetwork && req.asset && req.maxAmountRequired) {
|
|
87
|
-
// Only consider USDC assets when maxUsdcPrice filter is applied
|
|
88
|
-
if ((0, utils_1.isUsdcAsset)(req.asset, walletProvider)) {
|
|
89
|
-
try {
|
|
90
|
-
const maxUsdcPriceAtomic = await (0, utils_1.convertWholeUnitsToAtomic)(args.maxUsdcPrice, req.asset, walletProvider);
|
|
91
|
-
if (maxUsdcPriceAtomic) {
|
|
92
|
-
const requirement = BigInt(req.maxAmountRequired);
|
|
93
|
-
const maxUsdcPriceAtomicBigInt = BigInt(maxUsdcPriceAtomic);
|
|
94
|
-
if (requirement <= maxUsdcPriceAtomicBigInt) {
|
|
95
|
-
shouldInclude = true;
|
|
96
|
-
break;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
catch {
|
|
101
|
-
// If conversion fails, skip this requirement
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
if (shouldInclude) {
|
|
108
|
-
priceFilteredServices.push(item);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
61
|
+
// Get the wallet's network identifiers (both v1 and v2 formats)
|
|
62
|
+
const walletNetworks = (0, utils_1.getX402Networks)(walletProvider.getNetwork());
|
|
63
|
+
// Apply filter pipeline
|
|
64
|
+
let filteredResources = (0, utils_1.filterByNetwork)(allResources, walletNetworks);
|
|
65
|
+
filteredResources = (0, utils_1.filterByDescription)(filteredResources);
|
|
66
|
+
filteredResources = (0, utils_1.filterByX402Version)(filteredResources, args.x402Versions);
|
|
67
|
+
// Apply keyword filter if provided
|
|
68
|
+
if (args.keyword) {
|
|
69
|
+
filteredResources = (0, utils_1.filterByKeyword)(filteredResources, args.keyword);
|
|
111
70
|
}
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (matchingAccept?.maxAmountRequired && matchingAccept?.asset) {
|
|
119
|
-
formattedMaxAmount = await (0, utils_1.formatPaymentOption)({
|
|
120
|
-
asset: matchingAccept.asset,
|
|
121
|
-
maxAmountRequired: matchingAccept.maxAmountRequired,
|
|
122
|
-
network: matchingAccept.network,
|
|
123
|
-
}, walletProvider);
|
|
124
|
-
}
|
|
125
|
-
return {
|
|
126
|
-
resource: item.resource,
|
|
127
|
-
description: matchingAccept?.description || "",
|
|
128
|
-
cost: formattedMaxAmount,
|
|
129
|
-
...(matchingAccept?.outputSchema?.input && {
|
|
130
|
-
input: matchingAccept.outputSchema.input,
|
|
131
|
-
}),
|
|
132
|
-
...(matchingAccept?.outputSchema?.output && {
|
|
133
|
-
output: matchingAccept.outputSchema.output,
|
|
134
|
-
}),
|
|
135
|
-
...(item.metadata && item.metadata.length > 0 && { metadata: item.metadata }),
|
|
136
|
-
};
|
|
137
|
-
}));
|
|
71
|
+
// Apply price filter if maxUsdcPrice is provided
|
|
72
|
+
if (args.maxUsdcPrice !== undefined) {
|
|
73
|
+
filteredResources = await (0, utils_1.filterByMaxPrice)(filteredResources, args.maxUsdcPrice, walletProvider, walletNetworks);
|
|
74
|
+
}
|
|
75
|
+
// Format simplified output
|
|
76
|
+
const simplifiedResources = await (0, utils_1.formatSimplifiedResources)(filteredResources, walletNetworks, walletProvider);
|
|
138
77
|
return JSON.stringify({
|
|
139
78
|
success: true,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
79
|
+
services: simplifiedResources,
|
|
80
|
+
walletNetworks,
|
|
81
|
+
total: allResources.length,
|
|
82
|
+
returned: simplifiedResources.length,
|
|
144
83
|
}, null, 2);
|
|
145
84
|
}
|
|
146
85
|
catch (error) {
|
|
@@ -161,42 +100,89 @@ class X402ActionProvider extends actionProvider_1.ActionProvider {
|
|
|
161
100
|
*/
|
|
162
101
|
async makeHttpRequest(walletProvider, args) {
|
|
163
102
|
try {
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
103
|
+
const finalUrl = (0, utils_1.buildUrlWithParams)(args.url, args.queryParams);
|
|
104
|
+
let method = args.method ?? "GET";
|
|
105
|
+
let canHaveBody = ["POST", "PUT", "PATCH"].includes(method);
|
|
106
|
+
let response = await fetch(finalUrl, {
|
|
107
|
+
method,
|
|
167
108
|
headers: args.headers ?? undefined,
|
|
168
|
-
|
|
169
|
-
validateStatus: status => status === 402 || (status >= 200 && status < 300),
|
|
109
|
+
body: canHaveBody && args.body ? JSON.stringify(args.body) : undefined,
|
|
170
110
|
});
|
|
111
|
+
// Retry with other http method for 404 status code
|
|
112
|
+
if (response.status === 404) {
|
|
113
|
+
method = method === "GET" ? "POST" : "GET";
|
|
114
|
+
canHaveBody = ["POST", "PUT", "PATCH"].includes(method);
|
|
115
|
+
response = await fetch(finalUrl, {
|
|
116
|
+
method,
|
|
117
|
+
headers: args.headers ?? undefined,
|
|
118
|
+
body: canHaveBody && args.body ? JSON.stringify(args.body) : undefined,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
171
121
|
if (response.status !== 402) {
|
|
122
|
+
const data = await this.parseResponseData(response);
|
|
172
123
|
return JSON.stringify({
|
|
173
124
|
success: true,
|
|
174
|
-
url:
|
|
175
|
-
method
|
|
125
|
+
url: finalUrl,
|
|
126
|
+
method,
|
|
176
127
|
status: response.status,
|
|
177
|
-
data
|
|
128
|
+
data,
|
|
178
129
|
}, null, 2);
|
|
179
130
|
}
|
|
180
|
-
//
|
|
181
|
-
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
let
|
|
185
|
-
//
|
|
131
|
+
// Handle 402 Payment Required
|
|
132
|
+
// v2 sends requirements in PAYMENT-REQUIRED header; v1 sends in body
|
|
133
|
+
const walletNetworks = (0, utils_1.getX402Networks)(walletProvider.getNetwork());
|
|
134
|
+
let acceptsArray = [];
|
|
135
|
+
let paymentData = {};
|
|
136
|
+
// Check for v2 header-based payment requirements
|
|
137
|
+
const paymentRequiredHeader = response.headers.get("payment-required");
|
|
138
|
+
if (paymentRequiredHeader) {
|
|
139
|
+
try {
|
|
140
|
+
const decoded = JSON.parse(atob(paymentRequiredHeader));
|
|
141
|
+
acceptsArray = decoded.accepts ?? [];
|
|
142
|
+
paymentData = decoded;
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// Header parsing failed, fall back to body
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Fall back to v1 body-based requirements if header not present or empty
|
|
149
|
+
if (acceptsArray.length === 0) {
|
|
150
|
+
paymentData = await response.json();
|
|
151
|
+
acceptsArray = paymentData.accepts ?? [];
|
|
152
|
+
}
|
|
153
|
+
const availableNetworks = acceptsArray.map(option => option.network);
|
|
154
|
+
const hasMatchingNetwork = availableNetworks.some((net) => walletNetworks.includes(net));
|
|
155
|
+
let paymentOptionsText = `The wallet networks ${walletNetworks.join(", ")} do not match any available payment options (${availableNetworks.join(", ")}).`;
|
|
186
156
|
if (hasMatchingNetwork) {
|
|
187
|
-
const matchingOptions =
|
|
188
|
-
const formattedOptions = await Promise.all(matchingOptions.map(option => (0, utils_1.formatPaymentOption)(
|
|
157
|
+
const matchingOptions = acceptsArray.filter(option => walletNetworks.includes(option.network));
|
|
158
|
+
const formattedOptions = await Promise.all(matchingOptions.map(option => (0, utils_1.formatPaymentOption)({
|
|
159
|
+
asset: option.asset,
|
|
160
|
+
maxAmountRequired: option.maxAmountRequired ?? option.amount ?? "0",
|
|
161
|
+
network: option.network,
|
|
162
|
+
}, walletProvider)));
|
|
189
163
|
paymentOptionsText = `The payment options are: ${formattedOptions.join(", ")}`;
|
|
190
164
|
}
|
|
165
|
+
// Extract discovery info from v2 response (description, mimeType, extensions)
|
|
166
|
+
const discoveryInfo = {};
|
|
167
|
+
if (paymentData.description)
|
|
168
|
+
discoveryInfo.description = paymentData.description;
|
|
169
|
+
if (paymentData.mimeType)
|
|
170
|
+
discoveryInfo.mimeType = paymentData.mimeType;
|
|
171
|
+
if (paymentData.extensions)
|
|
172
|
+
discoveryInfo.extensions = paymentData.extensions;
|
|
191
173
|
return JSON.stringify({
|
|
192
174
|
status: "error_402_payment_required",
|
|
193
|
-
acceptablePaymentOptions:
|
|
175
|
+
acceptablePaymentOptions: acceptsArray,
|
|
176
|
+
...(Object.keys(discoveryInfo).length > 0 && { discoveryInfo }),
|
|
194
177
|
nextSteps: [
|
|
195
178
|
"Inform the user that the requested server replied with a 402 Payment Required response.",
|
|
196
179
|
paymentOptionsText,
|
|
180
|
+
"Include the description of the service in the response.",
|
|
181
|
+
"IMPORTANT: Identify required or optional query or body parameters based on this response. If there are any, you must inform the user and request them to provide the values. Always suggest example values.",
|
|
182
|
+
"CRITICAL: For POST/PUT/PATCH requests, you MUST use the 'body' parameter (NOT queryParams) to send data.",
|
|
197
183
|
hasMatchingNetwork ? "Ask the user if they want to retry the request with payment." : "",
|
|
198
184
|
hasMatchingNetwork
|
|
199
|
-
?
|
|
185
|
+
? "Use retry_http_request_with_x402 to retry the request with payment. IMPORTANT: You must retry_http_request_with_x402 with the correct Http method. "
|
|
200
186
|
: "",
|
|
201
187
|
],
|
|
202
188
|
});
|
|
@@ -214,14 +200,15 @@ class X402ActionProvider extends actionProvider_1.ActionProvider {
|
|
|
214
200
|
*/
|
|
215
201
|
async retryWithX402(walletProvider, args) {
|
|
216
202
|
try {
|
|
203
|
+
console.log("args", args);
|
|
217
204
|
// Check network compatibility before attempting payment
|
|
218
|
-
const
|
|
205
|
+
const walletNetworks = (0, utils_1.getX402Networks)(walletProvider.getNetwork());
|
|
219
206
|
const selectedNetwork = args.selectedPaymentOption.network;
|
|
220
|
-
if (
|
|
207
|
+
if (!walletNetworks.includes(selectedNetwork)) {
|
|
221
208
|
return JSON.stringify({
|
|
222
209
|
error: true,
|
|
223
210
|
message: "Network mismatch",
|
|
224
|
-
details: `Wallet is on ${
|
|
211
|
+
details: `Wallet is on ${walletNetworks.join(", ")} but payment requires ${selectedNetwork}`,
|
|
225
212
|
}, null, 2);
|
|
226
213
|
}
|
|
227
214
|
// Check if wallet provider is supported
|
|
@@ -232,58 +219,68 @@ class X402ActionProvider extends actionProvider_1.ActionProvider {
|
|
|
232
219
|
details: "Only SvmWalletProvider and EvmWalletProvider are supported",
|
|
233
220
|
}, null, 2);
|
|
234
221
|
}
|
|
222
|
+
// Create x402 client with appropriate signer
|
|
223
|
+
const client = await this.createX402Client(walletProvider);
|
|
224
|
+
const fetchWithPayment = (0, fetch_1.wrapFetchWithPayment)(fetch, client);
|
|
225
|
+
// Build URL with query params and determine if body is allowed
|
|
226
|
+
const finalUrl = (0, utils_1.buildUrlWithParams)(args.url, args.queryParams);
|
|
227
|
+
const method = args.method ?? "GET";
|
|
228
|
+
const canHaveBody = ["POST", "PUT", "PATCH"].includes(method);
|
|
229
|
+
// Build headers, adding Content-Type for JSON body
|
|
230
|
+
const headers = { ...(args.headers ?? {}) };
|
|
231
|
+
if (canHaveBody && args.body) {
|
|
232
|
+
headers["Content-Type"] = "application/json";
|
|
233
|
+
}
|
|
235
234
|
// Make the request with payment handling
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
235
|
+
const response = await fetchWithPayment(finalUrl, {
|
|
236
|
+
method,
|
|
237
|
+
headers,
|
|
238
|
+
body: canHaveBody && args.body ? JSON.stringify(args.body) : undefined,
|
|
239
|
+
});
|
|
240
|
+
const data = await this.parseResponseData(response);
|
|
241
|
+
// Check for payment proof in headers (v2: payment-response, v1: x-payment-response)
|
|
242
|
+
const paymentResponseHeader = response.headers.get("payment-response") ?? response.headers.get("x-payment-response");
|
|
243
|
+
let paymentProof = null;
|
|
244
|
+
if (paymentResponseHeader) {
|
|
245
|
+
try {
|
|
246
|
+
paymentProof = JSON.parse(atob(paymentResponseHeader));
|
|
245
247
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
accept.asset === asset);
|
|
250
|
-
if (paymentRequirements) {
|
|
251
|
-
return paymentRequirements;
|
|
248
|
+
catch {
|
|
249
|
+
// If parsing fails, include raw header
|
|
250
|
+
paymentProof = { raw: paymentResponseHeader };
|
|
252
251
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
252
|
+
}
|
|
253
|
+
// Get the amount used (supports both v1 and v2 formats)
|
|
254
|
+
const amountUsed = args.selectedPaymentOption.maxAmountRequired ??
|
|
255
|
+
args.selectedPaymentOption.amount ??
|
|
256
|
+
args.selectedPaymentOption.price;
|
|
257
|
+
// Check if the response was successful
|
|
258
|
+
// Payment is only settled on 200 status
|
|
259
|
+
if (response.status !== 200) {
|
|
260
|
+
return JSON.stringify({
|
|
261
|
+
status: "error",
|
|
262
|
+
message: `Request failed with status ${response.status}. Payment was not settled.`,
|
|
263
|
+
httpStatus: response.status,
|
|
264
|
+
data,
|
|
265
|
+
details: {
|
|
266
|
+
url: finalUrl,
|
|
267
|
+
method,
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
}
|
|
268
271
|
return JSON.stringify({
|
|
269
272
|
status: "success",
|
|
270
|
-
data
|
|
273
|
+
data,
|
|
271
274
|
message: "Request completed successfully with payment",
|
|
272
275
|
details: {
|
|
273
|
-
url:
|
|
274
|
-
method
|
|
276
|
+
url: finalUrl,
|
|
277
|
+
method,
|
|
275
278
|
paymentUsed: {
|
|
276
279
|
network: args.selectedPaymentOption.network,
|
|
277
280
|
asset: args.selectedPaymentOption.asset,
|
|
278
|
-
amount:
|
|
281
|
+
amount: amountUsed,
|
|
279
282
|
},
|
|
280
|
-
paymentProof
|
|
281
|
-
? {
|
|
282
|
-
transaction: paymentProof.transaction,
|
|
283
|
-
network: paymentProof.network,
|
|
284
|
-
payer: paymentProof.payer,
|
|
285
|
-
}
|
|
286
|
-
: null,
|
|
283
|
+
paymentProof,
|
|
287
284
|
},
|
|
288
285
|
});
|
|
289
286
|
}
|
|
@@ -307,39 +304,93 @@ class X402ActionProvider extends actionProvider_1.ActionProvider {
|
|
|
307
304
|
details: "Only SvmWalletProvider and EvmWalletProvider are supported",
|
|
308
305
|
}, null, 2);
|
|
309
306
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
307
|
+
// Create x402 client with appropriate signer
|
|
308
|
+
const client = await this.createX402Client(walletProvider);
|
|
309
|
+
const fetchWithPayment = (0, fetch_1.wrapFetchWithPayment)(fetch, client);
|
|
310
|
+
// Build URL with query params and determine if body is allowed
|
|
311
|
+
const finalUrl = (0, utils_1.buildUrlWithParams)(args.url, args.queryParams);
|
|
312
|
+
const method = args.method ?? "GET";
|
|
313
|
+
const canHaveBody = ["POST", "PUT", "PATCH"].includes(method);
|
|
314
|
+
// Build headers, adding Content-Type for JSON body
|
|
315
|
+
const headers = { ...(args.headers ?? {}) };
|
|
316
|
+
if (canHaveBody && args.body) {
|
|
317
|
+
headers["Content-Type"] = "application/json";
|
|
318
|
+
}
|
|
319
|
+
const response = await fetchWithPayment(finalUrl, {
|
|
320
|
+
method,
|
|
321
|
+
headers,
|
|
322
|
+
body: canHaveBody && args.body ? JSON.stringify(args.body) : undefined,
|
|
318
323
|
});
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
324
|
+
const data = await this.parseResponseData(response);
|
|
325
|
+
// Check for payment proof in headers (v2: payment-response, v1: x-payment-response)
|
|
326
|
+
const paymentResponseHeader = response.headers.get("payment-response") ?? response.headers.get("x-payment-response");
|
|
327
|
+
let paymentProof = null;
|
|
328
|
+
if (paymentResponseHeader) {
|
|
329
|
+
try {
|
|
330
|
+
paymentProof = JSON.parse(atob(paymentResponseHeader));
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
// If parsing fails, include raw header
|
|
334
|
+
paymentProof = { raw: paymentResponseHeader };
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
// Check if the response was successful
|
|
338
|
+
// Payment is only settled on 200 status
|
|
339
|
+
if (response.status !== 200) {
|
|
340
|
+
return JSON.stringify({
|
|
341
|
+
success: false,
|
|
342
|
+
message: `Request failed with status ${response.status}. Payment was not settled.`,
|
|
343
|
+
url: finalUrl,
|
|
344
|
+
method,
|
|
345
|
+
status: response.status,
|
|
346
|
+
data,
|
|
347
|
+
}, null, 2);
|
|
348
|
+
}
|
|
323
349
|
return JSON.stringify({
|
|
324
350
|
success: true,
|
|
325
351
|
message: "Request completed successfully (payment handled automatically if required)",
|
|
326
|
-
url:
|
|
327
|
-
method
|
|
352
|
+
url: finalUrl,
|
|
353
|
+
method,
|
|
328
354
|
status: response.status,
|
|
329
|
-
data
|
|
330
|
-
paymentProof
|
|
331
|
-
? {
|
|
332
|
-
transaction: paymentProof.transaction,
|
|
333
|
-
network: paymentProof.network,
|
|
334
|
-
payer: paymentProof.payer,
|
|
335
|
-
}
|
|
336
|
-
: null,
|
|
355
|
+
data,
|
|
356
|
+
paymentProof,
|
|
337
357
|
}, null, 2);
|
|
338
358
|
}
|
|
339
359
|
catch (error) {
|
|
340
360
|
return (0, utils_1.handleHttpError)(error, args.url);
|
|
341
361
|
}
|
|
342
362
|
}
|
|
363
|
+
/**
|
|
364
|
+
* Creates an x402 client configured for the given wallet provider.
|
|
365
|
+
*
|
|
366
|
+
* @param walletProvider - The wallet provider to configure the client for
|
|
367
|
+
* @returns Configured x402Client
|
|
368
|
+
*/
|
|
369
|
+
async createX402Client(walletProvider) {
|
|
370
|
+
const client = new fetch_1.x402Client();
|
|
371
|
+
if (walletProvider instanceof wallet_providers_1.EvmWalletProvider) {
|
|
372
|
+
const signer = walletProvider.toSigner();
|
|
373
|
+
(0, client_1.registerExactEvmScheme)(client, { signer });
|
|
374
|
+
}
|
|
375
|
+
else if (walletProvider instanceof wallet_providers_1.SvmWalletProvider) {
|
|
376
|
+
const signer = await walletProvider.toSigner();
|
|
377
|
+
(0, client_2.registerExactSvmScheme)(client, { signer });
|
|
378
|
+
}
|
|
379
|
+
return client;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Parses response data based on content type.
|
|
383
|
+
*
|
|
384
|
+
* @param response - The fetch Response object
|
|
385
|
+
* @returns Parsed response data
|
|
386
|
+
*/
|
|
387
|
+
async parseResponseData(response) {
|
|
388
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
389
|
+
if (contentType.includes("application/json")) {
|
|
390
|
+
return response.json();
|
|
391
|
+
}
|
|
392
|
+
return response.text();
|
|
393
|
+
}
|
|
343
394
|
}
|
|
344
395
|
exports.X402ActionProvider = X402ActionProvider;
|
|
345
396
|
__decorate([
|
|
@@ -362,9 +413,9 @@ it will return payment details that can be used with retry_http_request_with_x40
|
|
|
362
413
|
EXAMPLES:
|
|
363
414
|
- Production API: make_http_request("https://api.example.com/weather")
|
|
364
415
|
- Local development: make_http_request("http://localhost:3000/api/data")
|
|
365
|
-
- Testing x402: make_http_request("http://localhost:3000/protected")
|
|
366
416
|
|
|
367
|
-
If you receive a 402 Payment Required response, use retry_http_request_with_x402 to handle the payment
|
|
417
|
+
If you receive a 402 Payment Required response, use retry_http_request_with_x402 to handle the payment.
|
|
418
|
+
`,
|
|
368
419
|
schema: schemas_1.HttpRequestSchema,
|
|
369
420
|
}),
|
|
370
421
|
__metadata("design:type", Function),
|
|
@@ -394,7 +445,7 @@ __decorate([
|
|
|
394
445
|
(0, actionDecorator_1.CreateAction)({
|
|
395
446
|
name: "make_http_request_with_x402",
|
|
396
447
|
description: `
|
|
397
|
-
|
|
448
|
+
WARNING: This action automatically handles payments without asking for confirmation!
|
|
398
449
|
Only use this when explicitly told to skip the confirmation flow.
|
|
399
450
|
|
|
400
451
|
For most cases, you should:
|