@coinbase/agentkit 0.0.0-nightly-20250915210424 → 0.0.0-nightly-20250917210422

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.
Files changed (36) hide show
  1. package/README.md +9 -1
  2. package/dist/action-providers/pyth/pythActionProvider.d.ts +2 -2
  3. package/dist/action-providers/pyth/pythActionProvider.js +83 -31
  4. package/dist/action-providers/pyth/pythActionProvider.test.js +178 -26
  5. package/dist/action-providers/pyth/schemas.d.ts +6 -0
  6. package/dist/action-providers/pyth/schemas.js +9 -1
  7. package/dist/action-providers/x402/schemas.d.ts +7 -0
  8. package/dist/action-providers/x402/schemas.js +11 -1
  9. package/dist/action-providers/x402/utils.d.ts +55 -0
  10. package/dist/action-providers/x402/utils.js +160 -0
  11. package/dist/action-providers/x402/x402ActionProvider.d.ts +9 -9
  12. package/dist/action-providers/x402/x402ActionProvider.js +158 -39
  13. package/dist/action-providers/x402/x402ActionProvider.test.js +116 -10
  14. package/dist/wallet-providers/cdpEvmWalletProvider.d.ts +7 -0
  15. package/dist/wallet-providers/cdpEvmWalletProvider.js +9 -0
  16. package/dist/wallet-providers/cdpEvmWalletProvider.test.js +7 -0
  17. package/dist/wallet-providers/cdpSmartWalletProvider.d.ts +7 -0
  18. package/dist/wallet-providers/cdpSmartWalletProvider.js +13 -1
  19. package/dist/wallet-providers/cdpSmartWalletProvider.test.js +6 -2
  20. package/dist/wallet-providers/evmWalletProvider.d.ts +9 -2
  21. package/dist/wallet-providers/evmWalletProvider.js +4 -0
  22. package/dist/wallet-providers/legacyCdpSmartWalletProvider.d.ts +9 -0
  23. package/dist/wallet-providers/legacyCdpSmartWalletProvider.js +11 -0
  24. package/dist/wallet-providers/legacyCdpWalletProvider.d.ts +7 -0
  25. package/dist/wallet-providers/legacyCdpWalletProvider.js +16 -0
  26. package/dist/wallet-providers/legacyCdpWalletProvider.test.js +6 -0
  27. package/dist/wallet-providers/privyEvmDelegatedEmbeddedWalletProvider.d.ts +7 -0
  28. package/dist/wallet-providers/privyEvmDelegatedEmbeddedWalletProvider.js +27 -0
  29. package/dist/wallet-providers/privyEvmWalletProvider.test.js +11 -0
  30. package/dist/wallet-providers/viemWalletProvider.d.ts +7 -0
  31. package/dist/wallet-providers/viemWalletProvider.js +16 -0
  32. package/dist/wallet-providers/viemWalletProvider.test.js +9 -0
  33. package/dist/wallet-providers/zeroDevWalletProvider.d.ts +7 -0
  34. package/dist/wallet-providers/zeroDevWalletProvider.js +12 -0
  35. package/dist/wallet-providers/zeroDevWalletProvider.test.js +10 -0
  36. package/package.json +5 -4
package/README.md CHANGED
@@ -407,7 +407,7 @@ const agent = createReactAgent({
407
407
  </tr>
408
408
  <tr>
409
409
  <td width="200"><code>fetch_price_feed_id</code></td>
410
- <td width="768">Retrieves the unique price feed identifier for a given token symbol.</td>
410
+ <td width="768">Retrieves the unique price feed identifier for a given asset symbol.</td>
411
411
  </tr>
412
412
  </table>
413
413
  </details>
@@ -541,6 +541,10 @@ const agent = createReactAgent({
541
541
  <details>
542
542
  <summary><strong>x402</strong></summary>
543
543
  <table width="100%">
544
+ <tr>
545
+ <td width="200"><code>discover_x402_services</code></td>
546
+ <td width="768">Discover available x402 services with optional filtering by maximum USDC price.</td>
547
+ </tr>
544
548
  <tr>
545
549
  <td width="200"><code>make_http_request</code></td>
546
550
  <td width="768">Makes a basic HTTP request to an API endpoint. If the endpoint requires payment (returns 402),
@@ -553,6 +557,10 @@ it will return payment details that can be used on retry.</td>
553
557
  <tr>
554
558
  <td width="200"><code>make_http_request_with_x402</code></td>
555
559
  <td width="768">Combines make_http_request and retry_http_request_with_x402 into a single step.</td>
560
+ </tr>
561
+ </table>
562
+ </details>
563
+ <details>
556
564
  <summary><strong>ZeroX</strong></summary>
557
565
  <table width="100%">
558
566
  <tr>
@@ -13,14 +13,14 @@ export declare class PythActionProvider extends ActionProvider {
13
13
  * Fetch the price feed ID for a given token symbol from Pyth.
14
14
  *
15
15
  * @param args - The arguments for the action.
16
- * @returns The price feed ID as a string.
16
+ * @returns The price feed ID as stringified JSON.
17
17
  */
18
18
  fetchPriceFeed(args: z.infer<typeof PythFetchPriceFeedIDSchema>): Promise<string>;
19
19
  /**
20
20
  * Fetches the price from Pyth given a Pyth price feed ID.
21
21
  *
22
22
  * @param args - The arguments for the action.
23
- * @returns The price as a string.
23
+ * @returns The price as stringified JSON.
24
24
  */
25
25
  fetchPrice(args: z.infer<typeof PythFetchPriceSchema>): Promise<string>;
26
26
  /**
@@ -34,68 +34,120 @@ class PythActionProvider extends actionProvider_1.ActionProvider {
34
34
  * Fetch the price feed ID for a given token symbol from Pyth.
35
35
  *
36
36
  * @param args - The arguments for the action.
37
- * @returns The price feed ID as a string.
37
+ * @returns The price feed ID as stringified JSON.
38
38
  */
39
39
  async fetchPriceFeed(args) {
40
- // Stop-gap solution: Return hardcoded price feed ID for ETH
41
- // This is temporary until proper new API link is provided after talking to the Pyth team
42
- if (args.tokenSymbol.toUpperCase() === "ETH") {
43
- return "0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace";
44
- }
45
- const url = `https://hermes.pyth.network/v2/price_feeds?query=${args.tokenSymbol}&asset_type=crypto`;
40
+ const url = `https://hermes.pyth.network/v2/price_feeds?query=${args.tokenSymbol}&asset_type=${args.assetType}`;
46
41
  const response = await fetch(url);
47
42
  if (!response.ok) {
48
- throw new Error(`HTTP error! status: ${response.status}`);
43
+ return JSON.stringify({
44
+ success: false,
45
+ error: `HTTP error! status: ${response.status}`,
46
+ });
49
47
  }
50
48
  const data = await response.json();
51
49
  if (data.length === 0) {
52
- throw new Error(`No price feed found for ${args.tokenSymbol}`);
50
+ return JSON.stringify({
51
+ success: false,
52
+ error: `No price feed found for ${args.tokenSymbol}`,
53
+ });
53
54
  }
54
55
  const filteredData = data.filter(
55
56
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
56
- (item) => item.attributes.base.toLowerCase() === args.tokenSymbol.toLowerCase());
57
+ (item) => item.attributes.base.toLowerCase() === args.tokenSymbol.toLowerCase() &&
58
+ item.attributes.quote_currency.toLowerCase() === args.quoteCurrency.toLowerCase());
57
59
  if (filteredData.length === 0) {
58
- throw new Error(`No price feed found for ${args.tokenSymbol}`);
60
+ return JSON.stringify({
61
+ success: false,
62
+ error: `No price feed found for ${args.tokenSymbol}/${args.quoteCurrency}`,
63
+ });
64
+ }
65
+ // For equities, select the regular feed over special market hours feeds
66
+ let selectedFeed = filteredData[0];
67
+ if (args.assetType === "equity") {
68
+ // Look for regular market feed (no PRE, POST, ON, EXT suffixes)
69
+ const regularMarketFeed = filteredData.find(
70
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
71
+ (item) => !item.attributes.symbol.includes(".PRE") &&
72
+ !item.attributes.symbol.includes(".POST") &&
73
+ !item.attributes.symbol.includes(".ON") &&
74
+ !item.attributes.symbol.includes(".EXT"));
75
+ if (regularMarketFeed) {
76
+ selectedFeed = regularMarketFeed;
77
+ }
59
78
  }
60
- return filteredData[0].id;
79
+ return JSON.stringify({
80
+ success: true,
81
+ priceFeedID: selectedFeed.id,
82
+ tokenSymbol: args.tokenSymbol,
83
+ quoteCurrency: args.quoteCurrency,
84
+ feedType: selectedFeed.attributes.display_symbol,
85
+ });
61
86
  }
62
87
  /**
63
88
  * Fetches the price from Pyth given a Pyth price feed ID.
64
89
  *
65
90
  * @param args - The arguments for the action.
66
- * @returns The price as a string.
91
+ * @returns The price as stringified JSON.
67
92
  */
68
93
  async fetchPrice(args) {
69
94
  const url = `https://hermes.pyth.network/v2/updates/price/latest?ids[]=${args.priceFeedID}`;
70
95
  const response = await fetch(url);
71
96
  if (!response.ok) {
72
- throw new Error(`HTTP error! status: ${response.status}`);
97
+ return JSON.stringify({
98
+ success: false,
99
+ error: `HTTP error! status: ${response.status}`,
100
+ });
73
101
  }
74
102
  const data = await response.json();
75
103
  const parsedData = data.parsed;
76
104
  if (parsedData.length === 0) {
77
- throw new Error(`No price data found for ${args.priceFeedID}`);
105
+ return JSON.stringify({
106
+ success: false,
107
+ error: `No price data found for ${args.priceFeedID}`,
108
+ });
78
109
  }
110
+ // Helper function to format price
111
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
112
+ const formatPrice = (priceInfo) => {
113
+ const price = BigInt(priceInfo.price);
114
+ const exponent = priceInfo.expo;
115
+ if (exponent < 0) {
116
+ const adjustedPrice = price * BigInt(100);
117
+ const divisor = BigInt(10) ** BigInt(-exponent);
118
+ const scaledPrice = adjustedPrice / BigInt(divisor);
119
+ const priceStr = scaledPrice.toString();
120
+ const formattedPrice = `${priceStr.slice(0, -2)}.${priceStr.slice(-2)}`;
121
+ return formattedPrice.startsWith(".") ? `0${formattedPrice}` : formattedPrice;
122
+ }
123
+ const scaledPrice = price / BigInt(10) ** BigInt(exponent);
124
+ return scaledPrice.toString();
125
+ };
79
126
  const priceInfo = parsedData[0].price;
80
- const price = BigInt(priceInfo.price);
81
- const exponent = priceInfo.expo;
82
- if (exponent < 0) {
83
- const adjustedPrice = price * BigInt(100);
84
- const divisor = BigInt(10) ** BigInt(-exponent);
85
- const scaledPrice = adjustedPrice / BigInt(divisor);
86
- const priceStr = scaledPrice.toString();
87
- const formattedPrice = `${priceStr.slice(0, -2)}.${priceStr.slice(-2)}`;
88
- return formattedPrice.startsWith(".") ? `0${formattedPrice}` : formattedPrice;
89
- }
90
- const scaledPrice = price / BigInt(10) ** BigInt(exponent);
91
- return scaledPrice.toString();
127
+ return JSON.stringify({
128
+ success: true,
129
+ priceFeedID: args.priceFeedID,
130
+ price: formatPrice(priceInfo),
131
+ });
92
132
  }
93
133
  }
94
134
  exports.PythActionProvider = PythActionProvider;
95
135
  __decorate([
96
136
  (0, actionDecorator_1.CreateAction)({
97
137
  name: "fetch_price_feed",
98
- description: "Fetch the price feed ID for a given token symbol from Pyth.",
138
+ description: `Fetch the price feed ID for a given token symbol from Pyth.
139
+
140
+ Inputs:
141
+ - tokenSymbol: The asset ticker/symbol to fetch the price feed ID for (e.g. BTC, ETH, COIN, XAU, EUR, etc.)
142
+ - quoteCurrency: The quote currency to filter by (defaults to USD)
143
+ - assetType: The asset type to search for (crypto, equity, fx, metal) - defaults to crypto
144
+
145
+ Examples:
146
+ - Crypto: BTC, ETH, SOL
147
+ - Equities: COIN, AAPL, TSLA
148
+ - FX: EUR, GBP, JPY
149
+ - Metals: XAU (Gold), XAG (Silver), XPT (Platinum), XPD (Palladium)
150
+ `,
99
151
  schema: schemas_1.PythFetchPriceFeedIDSchema,
100
152
  }),
101
153
  __metadata("design:type", Function),
@@ -105,16 +157,16 @@ __decorate([
105
157
  __decorate([
106
158
  (0, actionDecorator_1.CreateAction)({
107
159
  name: "fetch_price",
108
- description: `Fetch the price of a given price feed from Pyth.
160
+ description: `Fetch the price of a price feed from Pyth.
109
161
 
110
162
  Inputs:
111
- - Pyth price feed ID
163
+ - priceFeedID: Price feed ID (string)
112
164
 
113
165
  Important notes:
114
166
  - Do not assume that a random ID is a Pyth price feed ID. If you are confused, ask a clarifying question.
115
167
  - This action only fetches price inputs from Pyth price feeds. No other source.
116
168
  - If you are asked to fetch the price from Pyth for a ticker symbol such as BTC, you must first use the pyth_fetch_price_feed_id
117
- action to retrieve the price feed ID before invoking the pyth_Fetch_price action
169
+ action to retrieve the price feed ID before invoking the pyth_fetch_price action
118
170
  `,
119
171
  schema: schemas_1.PythFetchPriceSchema,
120
172
  }),
@@ -9,39 +9,180 @@ describe("PythActionProvider", () => {
9
9
  jest.resetAllMocks().restoreAllMocks();
10
10
  });
11
11
  describe("fetchPriceFeed", () => {
12
- it("should return the first price feed ID that matches the input token symbol", async () => {
12
+ it("should return the first price feed ID that matches the input token symbol for crypto", async () => {
13
13
  fetchMock.mockResolvedValueOnce({
14
14
  ok: true,
15
- json: async () => [{ id: "some-price-feed-id", attributes: { base: "BTC" } }],
15
+ json: async () => [
16
+ { id: "some-price-feed-id", attributes: { base: "BTC", quote_currency: "USD" } },
17
+ ],
16
18
  });
17
- const priceFeedId = await provider.fetchPriceFeed({ tokenSymbol: "BTC" });
18
- expect(priceFeedId).toEqual("some-price-feed-id");
19
+ const result = await provider.fetchPriceFeed({
20
+ tokenSymbol: "BTC",
21
+ assetType: "crypto",
22
+ quoteCurrency: "USD",
23
+ });
24
+ const parsed = JSON.parse(result);
25
+ expect(parsed.success).toBe(true);
26
+ expect(parsed.priceFeedID).toEqual("some-price-feed-id");
27
+ });
28
+ it("should return the first price feed ID that matches the input token symbol for metals", async () => {
29
+ fetchMock.mockResolvedValueOnce({
30
+ ok: true,
31
+ json: async () => [
32
+ { id: "gold-price-feed-id", attributes: { base: "XAU", quote_currency: "USD" } },
33
+ ],
34
+ });
35
+ const result = await provider.fetchPriceFeed({
36
+ tokenSymbol: "XAU",
37
+ assetType: "metal",
38
+ quoteCurrency: "USD",
39
+ });
40
+ const parsed = JSON.parse(result);
41
+ expect(parsed.success).toBe(true);
42
+ expect(parsed.priceFeedID).toEqual("gold-price-feed-id");
43
+ });
44
+ it("should return the first price feed ID that matches the input token symbol for commodities", async () => {
45
+ fetchMock.mockResolvedValueOnce({
46
+ ok: true,
47
+ json: async () => [
48
+ { id: "oil-price-feed-id", attributes: { base: "WTI", quote_currency: "USD" } },
49
+ ],
50
+ });
51
+ const result = await provider.fetchPriceFeed({
52
+ tokenSymbol: "WTI",
53
+ assetType: "metal",
54
+ quoteCurrency: "USD",
55
+ });
56
+ const parsed = JSON.parse(result);
57
+ expect(parsed.success).toBe(true);
58
+ expect(parsed.priceFeedID).toEqual("oil-price-feed-id");
59
+ });
60
+ it("should return the first price feed ID that matches the input token symbol for equities", async () => {
61
+ fetchMock.mockResolvedValueOnce({
62
+ ok: true,
63
+ json: async () => [
64
+ {
65
+ id: "apple-price-feed-id",
66
+ attributes: {
67
+ base: "AAPL",
68
+ quote_currency: "USD",
69
+ symbol: "Equity.US.AAPL/USD",
70
+ display_symbol: "AAPL/USD",
71
+ },
72
+ },
73
+ ],
74
+ });
75
+ const result = await provider.fetchPriceFeed({
76
+ tokenSymbol: "AAPL",
77
+ assetType: "equity",
78
+ quoteCurrency: "USD",
79
+ });
80
+ const parsed = JSON.parse(result);
81
+ expect(parsed.success).toBe(true);
82
+ expect(parsed.priceFeedID).toEqual("apple-price-feed-id");
19
83
  });
20
- it("should throw an error if no price feed is found", async () => {
84
+ it("should return the first price feed ID that matches the input token symbol for FX", async () => {
21
85
  fetchMock.mockResolvedValueOnce({
22
86
  ok: true,
23
- json: async () => [{ id: "some-price-feed-id", attributes: { base: "BTC" } }],
87
+ json: async () => [
88
+ { id: "eur-price-feed-id", attributes: { base: "EUR", quote_currency: "USD" } },
89
+ ],
90
+ });
91
+ const result = await provider.fetchPriceFeed({
92
+ tokenSymbol: "EUR",
93
+ assetType: "fx",
94
+ quoteCurrency: "USD",
24
95
  });
25
- await expect(provider.fetchPriceFeed({ tokenSymbol: "SOL" })).rejects.toThrow("No price feed found for SOL");
96
+ const parsed = JSON.parse(result);
97
+ expect(parsed.success).toBe(true);
98
+ expect(parsed.priceFeedID).toEqual("eur-price-feed-id");
26
99
  });
27
- it("should return hardcoded price feed ID for ETH", async () => {
28
- const priceFeedId = await provider.fetchPriceFeed({ tokenSymbol: "ETH" });
29
- expect(priceFeedId).toEqual("0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace");
100
+ it("should return error if no price feed is found", async () => {
101
+ fetchMock.mockResolvedValueOnce({
102
+ ok: true,
103
+ json: async () => [
104
+ { id: "some-price-feed-id", attributes: { base: "BTC", quote_currency: "USD" } },
105
+ ],
106
+ });
107
+ const result = await provider.fetchPriceFeed({
108
+ tokenSymbol: "SOL",
109
+ assetType: "crypto",
110
+ quoteCurrency: "USD",
111
+ });
112
+ const parsed = JSON.parse(result);
113
+ expect(parsed.success).toBe(false);
114
+ expect(parsed.error).toContain("No price feed found for SOL/USD");
30
115
  });
31
- it("should throw an error if the response is not ok", async () => {
116
+ it("should return error if the response is not ok", async () => {
32
117
  fetchMock.mockResolvedValueOnce({
33
118
  ok: false,
34
119
  status: 404,
35
120
  });
36
- await expect(provider.fetchPriceFeed({ tokenSymbol: "BTC" })).rejects.toThrow("HTTP error! status: 404");
121
+ const result = await provider.fetchPriceFeed({
122
+ tokenSymbol: "BTC",
123
+ assetType: "crypto",
124
+ quoteCurrency: "USD",
125
+ });
126
+ const parsed = JSON.parse(result);
127
+ expect(parsed.success).toBe(false);
128
+ expect(parsed.error).toContain("HTTP error! status: 404");
37
129
  });
38
- it("should throw an error if response is ok but no data is returned", async () => {
130
+ it("should return error if response is ok but no data is returned", async () => {
39
131
  fetchMock.mockResolvedValueOnce({
40
132
  ok: true,
41
133
  json: async () => [],
42
134
  });
43
- const provider = (0, pythActionProvider_1.pythActionProvider)();
44
- await expect(provider.fetchPriceFeed({ tokenSymbol: "BTC" })).rejects.toThrow("No price feed found for BTC");
135
+ const result = await provider.fetchPriceFeed({
136
+ tokenSymbol: "BTC",
137
+ assetType: "crypto",
138
+ quoteCurrency: "USD",
139
+ });
140
+ const parsed = JSON.parse(result);
141
+ expect(parsed.success).toBe(false);
142
+ expect(parsed.error).toContain("No price feed found for BTC");
143
+ });
144
+ it("should prefer regular market hours feed for equities over pre/post market", async () => {
145
+ fetchMock.mockResolvedValueOnce({
146
+ ok: true,
147
+ json: async () => [
148
+ {
149
+ id: "post-market-feed-id",
150
+ attributes: {
151
+ base: "COIN",
152
+ quote_currency: "USD",
153
+ symbol: "Equity.US.COIN/USD.POST",
154
+ display_symbol: "COIN/USD POST MARKET",
155
+ },
156
+ },
157
+ {
158
+ id: "regular-market-feed-id",
159
+ attributes: {
160
+ base: "COIN",
161
+ quote_currency: "USD",
162
+ symbol: "Equity.US.COIN/USD",
163
+ display_symbol: "COIN/USD",
164
+ },
165
+ },
166
+ {
167
+ id: "pre-market-feed-id",
168
+ attributes: {
169
+ base: "COIN",
170
+ quote_currency: "USD",
171
+ symbol: "Equity.US.COIN/USD.PRE",
172
+ display_symbol: "COIN/USD PRE MARKET",
173
+ },
174
+ },
175
+ ],
176
+ });
177
+ const result = await provider.fetchPriceFeed({
178
+ tokenSymbol: "COIN",
179
+ assetType: "equity",
180
+ quoteCurrency: "USD",
181
+ });
182
+ const parsed = JSON.parse(result);
183
+ expect(parsed.success).toBe(true);
184
+ expect(parsed.priceFeedID).toEqual("regular-market-feed-id");
185
+ expect(parsed.feedType).toEqual("COIN/USD");
45
186
  });
46
187
  });
47
188
  describe("fetchPrice", () => {
@@ -59,8 +200,10 @@ describe("PythActionProvider", () => {
59
200
  ],
60
201
  }),
61
202
  });
62
- const price = await provider.fetchPrice({ priceFeedID: "some-price-feed-id" });
63
- expect(price).toEqual("1");
203
+ const result = await provider.fetchPrice({ priceFeedID: "some-price-feed-id" });
204
+ const parsed = JSON.parse(result);
205
+ expect(parsed.success).toBe(true);
206
+ expect(parsed.price).toEqual("1");
64
207
  });
65
208
  it("should return the price for a given price feed ID with a negative exponent", async () => {
66
209
  fetchMock.mockResolvedValueOnce({
@@ -76,9 +219,10 @@ describe("PythActionProvider", () => {
76
219
  ],
77
220
  }),
78
221
  });
79
- const provider = (0, pythActionProvider_1.pythActionProvider)();
80
- const price = await provider.fetchPrice({ priceFeedID: "some-price-feed-id" });
81
- expect(price).toEqual("1.00");
222
+ const result = await provider.fetchPrice({ priceFeedID: "some-price-feed-id" });
223
+ const parsed = JSON.parse(result);
224
+ expect(parsed.success).toBe(true);
225
+ expect(parsed.price).toEqual("1.00");
82
226
  });
83
227
  it("should handle scaled price starting with a decimal", async () => {
84
228
  fetchMock.mockResolvedValueOnce({
@@ -94,24 +238,32 @@ describe("PythActionProvider", () => {
94
238
  ],
95
239
  }),
96
240
  });
97
- const price = await provider.fetchPrice({ priceFeedID: "some-price-feed-id" });
98
- expect(price).toEqual("0.25");
241
+ const result = await provider.fetchPrice({ priceFeedID: "some-price-feed-id" });
242
+ const parsed = JSON.parse(result);
243
+ expect(parsed.success).toBe(true);
244
+ expect(parsed.price).toEqual("0.25");
99
245
  });
100
- it("should throw an error if there is no price data", async () => {
246
+ it("should return error if there is no price data", async () => {
101
247
  fetchMock.mockResolvedValueOnce({
102
248
  ok: true,
103
249
  json: async () => ({
104
250
  parsed: [],
105
251
  }),
106
252
  });
107
- await expect(provider.fetchPrice({ priceFeedID: "some-price-feed-id" })).rejects.toThrow("No price data found for some-price-feed-id");
253
+ const result = await provider.fetchPrice({ priceFeedID: "some-price-feed-id" });
254
+ const parsed = JSON.parse(result);
255
+ expect(parsed.success).toBe(false);
256
+ expect(parsed.error).toContain("No price data found for some-price-feed-id");
108
257
  });
109
- it("should throw an error if response is not ok", async () => {
258
+ it("should return error if response is not ok", async () => {
110
259
  fetchMock.mockResolvedValueOnce({
111
260
  ok: false,
112
261
  status: 404,
113
262
  });
114
- await expect(provider.fetchPrice({ priceFeedID: "some-price-feed-id" })).rejects.toThrow("HTTP error! status: 404");
263
+ const result = await provider.fetchPrice({ priceFeedID: "some-price-feed-id" });
264
+ const parsed = JSON.parse(result);
265
+ expect(parsed.success).toBe(false);
266
+ expect(parsed.error).toContain("HTTP error! status: 404");
115
267
  });
116
268
  });
117
269
  });
@@ -4,10 +4,16 @@ import { z } from "zod";
4
4
  */
5
5
  export declare const PythFetchPriceFeedIDSchema: z.ZodObject<{
6
6
  tokenSymbol: z.ZodString;
7
+ quoteCurrency: z.ZodDefault<z.ZodString>;
8
+ assetType: z.ZodDefault<z.ZodEnum<["crypto", "equity", "fx", "metal"]>>;
7
9
  }, "strict", z.ZodTypeAny, {
8
10
  tokenSymbol: string;
11
+ quoteCurrency: string;
12
+ assetType: "crypto" | "equity" | "fx" | "metal";
9
13
  }, {
10
14
  tokenSymbol: string;
15
+ quoteCurrency?: string | undefined;
16
+ assetType?: "crypto" | "equity" | "fx" | "metal" | undefined;
11
17
  }>;
12
18
  /**
13
19
  * Input schema for Pyth fetch price action.
@@ -7,7 +7,15 @@ const zod_1 = require("zod");
7
7
  */
8
8
  exports.PythFetchPriceFeedIDSchema = zod_1.z
9
9
  .object({
10
- tokenSymbol: zod_1.z.string().describe("The token symbol to fetch the price feed ID for"),
10
+ tokenSymbol: zod_1.z.string().describe("The asset ticker/symbol to fetch the price feed ID for"),
11
+ quoteCurrency: zod_1.z
12
+ .string()
13
+ .default("USD")
14
+ .describe("The quote currency to filter by (defaults to USD)"),
15
+ assetType: zod_1.z
16
+ .enum(["crypto", "equity", "fx", "metal"])
17
+ .default("crypto")
18
+ .describe("The asset type to search for (crypto, equity, fx, metal)"),
11
19
  })
12
20
  .strict();
13
21
  /**
@@ -1,4 +1,11 @@
1
1
  import { z } from "zod";
2
+ export declare const ListX402ServicesSchema: z.ZodObject<{
3
+ maxUsdcPrice: z.ZodOptional<z.ZodNumber>;
4
+ }, "strip", z.ZodTypeAny, {
5
+ maxUsdcPrice?: number | undefined;
6
+ }, {
7
+ maxUsdcPrice?: number | undefined;
8
+ }>;
2
9
  export declare const HttpRequestSchema: z.ZodObject<{
3
10
  url: z.ZodString;
4
11
  method: z.ZodDefault<z.ZodNullable<z.ZodEnum<["GET", "POST", "PUT", "DELETE", "PATCH"]>>>;
@@ -1,7 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DirectX402RequestSchema = exports.RetryWithX402Schema = exports.HttpRequestSchema = void 0;
3
+ exports.DirectX402RequestSchema = exports.RetryWithX402Schema = exports.HttpRequestSchema = exports.ListX402ServicesSchema = void 0;
4
4
  const zod_1 = require("zod");
5
+ // Schema for listing x402 services
6
+ exports.ListX402ServicesSchema = zod_1.z
7
+ .object({
8
+ maxUsdcPrice: zod_1.z
9
+ .number()
10
+ .optional()
11
+ .describe("Optional maximum price in USDC whole units (e.g., 0.1 for 0.10 USDC). Only USDC payment options will be considered when this filter is applied."),
12
+ })
13
+ .strip()
14
+ .describe("Parameters for listing x402 services with optional filtering");
5
15
  // Schema for initial HTTP request
6
16
  exports.HttpRequestSchema = zod_1.z
7
17
  .object({
@@ -0,0 +1,55 @@
1
+ import { Network } from "../../network";
2
+ import { AxiosError } from "axios";
3
+ import { EvmWalletProvider } from "../../wallet-providers";
4
+ /**
5
+ * Supported network types for x402 protocol
6
+ */
7
+ export type X402Network = "base" | "base-sepolia" | "solana" | "solana-devnet";
8
+ /**
9
+ * Converts the internal network ID to the format expected by the x402 protocol.
10
+ *
11
+ * @param network - The network to convert
12
+ * @returns The network ID in x402 format
13
+ * @throws Error if the network is not supported
14
+ */
15
+ export declare function getX402Network(network: Network): X402Network | string | undefined;
16
+ /**
17
+ * Helper method to handle HTTP errors consistently.
18
+ *
19
+ * @param error - The axios error to handle
20
+ * @param url - The URL that was being accessed when the error occurred
21
+ * @returns A JSON string containing formatted error details
22
+ */
23
+ export declare function handleHttpError(error: AxiosError, url: string): string;
24
+ /**
25
+ * Formats a payment option into a human-readable string.
26
+ *
27
+ * @param option - The payment option to format
28
+ * @param option.asset - The asset address or identifier
29
+ * @param option.maxAmountRequired - The maximum amount required for the payment
30
+ * @param option.network - The network identifier
31
+ * @param walletProvider - The wallet provider for token details lookup
32
+ * @returns A formatted string like "0.1 USDC on base"
33
+ */
34
+ export declare function formatPaymentOption(option: {
35
+ asset: string;
36
+ maxAmountRequired: string;
37
+ network: string;
38
+ }, walletProvider: EvmWalletProvider): Promise<string>;
39
+ /**
40
+ * Checks if an asset is USDC on any supported network.
41
+ *
42
+ * @param asset - The asset address or identifier
43
+ * @param walletProvider - The wallet provider for network context
44
+ * @returns True if the asset is USDC, false otherwise
45
+ */
46
+ export declare function isUsdcAsset(asset: string, walletProvider: EvmWalletProvider): boolean;
47
+ /**
48
+ * Converts whole units to atomic units for a given asset.
49
+ *
50
+ * @param wholeUnits - The amount in whole units (e.g., 0.1 for 0.1 USDC)
51
+ * @param asset - The asset address or identifier
52
+ * @param walletProvider - The wallet provider for token details lookup
53
+ * @returns The amount in atomic units as a string, or null if conversion fails
54
+ */
55
+ export declare function convertWholeUnitsToAtomic(wholeUnits: number, asset: string, walletProvider: EvmWalletProvider): Promise<string | null>;