@coinbase/agentkit 0.8.0 → 0.8.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.
@@ -27,6 +27,7 @@ const utils_1 = require("./utils");
27
27
  const constants_1 = require("./constants");
28
28
  const actions_1 = require("./api/actions");
29
29
  const vaults_1 = require("./api/vaults");
30
+ const historicalData_1 = require("./api/historicalData");
30
31
  /**
31
32
  * VaultsfyiActionProvider provides actions for vaultsfyi operations.
32
33
  *
@@ -52,10 +53,11 @@ class VaultsfyiActionProvider extends actionProvider_1.ActionProvider {
52
53
  * vaults action
53
54
  *
54
55
  * @param wallet - The wallet provider instance for blockchain interactions
55
- * @param args - Input arguments: token, network, transactionalOnly...
56
+ * @param args - Input arguments: token, network...
56
57
  * @returns A list of vaults.
57
58
  */
58
59
  async vaults(wallet, args) {
60
+ const apyRange = args.apyRange ?? "7day";
59
61
  const vaults = await (0, vaults_1.fetchVaults)(args, this.apiKey);
60
62
  if ("error" in vaults) {
61
63
  return `Failed to fetch vaults: ${vaults.error}, ${vaults.message}`;
@@ -66,24 +68,7 @@ class VaultsfyiActionProvider extends actionProvider_1.ActionProvider {
66
68
  .filter((value, index, self) => self.indexOf(value) === index);
67
69
  return `Protocol ${args.protocol} is not supported. Supported protocols are: ${supportedProtocols.join(", ")}`;
68
70
  }
69
- const transformedVaults = vaults.map(vault => ({
70
- name: vault.name,
71
- address: vault.address,
72
- network: vault.network,
73
- protocol: vault.protocol,
74
- tvlInUsd: Number(vault.tvlDetails.tvlUsd),
75
- apy: {
76
- base: vault.apy.base["7day"] / 100,
77
- rewards: vault.apy.rewards?.["7day"] ? vault.apy.rewards["7day"] / 100 : undefined,
78
- total: vault.apy.total["7day"] / 100,
79
- },
80
- token: {
81
- address: vault.token.assetAddress,
82
- name: vault.token.name,
83
- symbol: vault.token.symbol,
84
- },
85
- link: (0, utils_1.getVaultsLink)(vault),
86
- }));
71
+ const transformedVaults = vaults.map(vault => (0, utils_1.transformVault)(vault, apyRange));
87
72
  const filteredVaults = transformedVaults.filter(vault => args.protocol ? vault.protocol === args.protocol : true);
88
73
  const sortedVaults = filteredVaults.sort((a, b) => {
89
74
  if (args.sort?.field === "tvl") {
@@ -107,6 +92,49 @@ class VaultsfyiActionProvider extends actionProvider_1.ActionProvider {
107
92
  results,
108
93
  });
109
94
  }
95
+ /**
96
+ * vault details action
97
+ *
98
+ * @param wallet - The wallet provider instance for blockchain interactions
99
+ * @param args - Input arguments: address, network, apyRange
100
+ * @returns A detailed view of a single vault.
101
+ */
102
+ async vaultDetails(wallet, args) {
103
+ const vault = await (0, vaults_1.fetchVault)(args, this.apiKey);
104
+ if ("error" in vault) {
105
+ return `Failed to fetch vault: ${vault.error}, ${vault.message}`;
106
+ }
107
+ return JSON.stringify((0, utils_1.transformDetailedVault)(vault, args.apyRange ?? "7day"));
108
+ }
109
+ /**
110
+ * vault historical data action
111
+ *
112
+ * @param wallet - The wallet provider instance for blockchain interactions
113
+ * @param args - Input arguments: address, network, date, apyRange
114
+ * @returns A detailed view of a single vault.
115
+ */
116
+ async vaultHistoricalData(wallet, args) {
117
+ const data = await (0, historicalData_1.fetchVaultHistoricalData)(args, this.apiKey);
118
+ if ("error" in data) {
119
+ return `Failed to fetch vault: ${data.error}, ${data.message}`;
120
+ }
121
+ return JSON.stringify({
122
+ apy: {
123
+ apy: {
124
+ base: data.apy.apy.base / 100,
125
+ rewards: data.apy.apy.rewards ? data.apy.apy.rewards / 100 : undefined,
126
+ total: data.apy.apy.total / 100,
127
+ },
128
+ date: new Date(data.apy.timestamp * 1000).toISOString(),
129
+ blockNumber: data.apy.blockNumber,
130
+ },
131
+ tvl: {
132
+ tvlInUsd: data.tvl.tvlDetails.tvlUsd,
133
+ date: new Date(data.tvl.timestamp * 1000).toISOString(),
134
+ blockNumber: data.tvl.blockNumber,
135
+ },
136
+ });
137
+ }
110
138
  /**
111
139
  * Deposit action
112
140
  *
@@ -260,7 +288,7 @@ __decorate([
260
288
  This action returns a list of available vaults.
261
289
  Small vaults (under 100k TVL) are probably best avoided as they may be more risky. Unless the user is looking for high-risk, high-reward opportunities, don't include them.
262
290
  When the user asks for best vaults, optimize for apy, and if the user asks for safest/reliable vaults, optimize for TVL.
263
- Try to take a reasonable number of results so its easier to analyze the data.
291
+ Try to take a reasonable number of results so its easier to analyze the data. Include vaults.fyi links for each vault.
264
292
  Format result apys as: x% (base: x%, rewards: x%) if rewards apy is available, otherwise: x%
265
293
  Examples:
266
294
  User: "Show me the best vaults"
@@ -275,6 +303,7 @@ __decorate([
275
303
  args: { network: 'polygon', sort: { field: 'apy', direction: 'desc' }, take: 5, minTvl: 0 }
276
304
  User: "Show me some more of those"
277
305
  args: { network: 'polygon', sort: { field: 'apy', direction: 'desc' }, take: 5, minTvl: 0, page: 2 }
306
+ All optional fields should be null if not specified.
278
307
  `,
279
308
  schema: schemas_1.VaultsActionSchema,
280
309
  }),
@@ -282,6 +311,44 @@ __decorate([
282
311
  __metadata("design:paramtypes", [wallet_providers_1.EvmWalletProvider, void 0]),
283
312
  __metadata("design:returntype", Promise)
284
313
  ], VaultsfyiActionProvider.prototype, "vaults", null);
314
+ __decorate([
315
+ (0, actionDecorator_1.CreateAction)({
316
+ name: "vault_details",
317
+ description: `
318
+ This action returns a more detailed view of a single vault. Additional details include:
319
+ - Description
320
+ - Additional incentives (points etc)
321
+ - Rewards breakdown
322
+ Params:
323
+ - vaultAddress: The address of the vault to fetch details for
324
+ - network: The network of the vault
325
+ - apyRange: The APY moving average range (default: 7day)
326
+ `,
327
+ schema: schemas_1.VaultDetailsActionSchema,
328
+ }),
329
+ __metadata("design:type", Function),
330
+ __metadata("design:paramtypes", [wallet_providers_1.EvmWalletProvider, void 0]),
331
+ __metadata("design:returntype", Promise)
332
+ ], VaultsfyiActionProvider.prototype, "vaultDetails", null);
333
+ __decorate([
334
+ (0, actionDecorator_1.CreateAction)({
335
+ name: "vault_historical_data",
336
+ description: `
337
+ This action returns a historical data of a vault. It returns the APY and TVL data closest to the given date.
338
+ Always check if the results date is close to the requested date, as the data may not be available for the exact date.
339
+ If there is a more than 7 day difference between the requested date and the resulting date, don't provide the data, but rather with a message explaining the missing data.
340
+ If the resulting date is a lot later than the requested date, the reason for missing data might be that the vault has not been deployed yet.
341
+ Example queries:
342
+ params: { vaultAddress: "0x1234567890abcdef1234567890abcdef12345678", network: "arbitrum", date: "2025-01-01T00:00:00Z" }
343
+ result: { ..., date: "2025-02-16T14:59:59.000Z" }
344
+ response: "The requested date was 2025-01-01T00:00:00Z, but the closest data available is from 2025-02-16T14:59:59.000Z. This may indicate that the vault was not deployed at the requested date."
345
+ `,
346
+ schema: schemas_1.VaultHistoricalDataActionSchema,
347
+ }),
348
+ __metadata("design:type", Function),
349
+ __metadata("design:paramtypes", [wallet_providers_1.EvmWalletProvider, void 0]),
350
+ __metadata("design:returntype", Promise)
351
+ ], VaultsfyiActionProvider.prototype, "vaultHistoricalData", null);
285
352
  __decorate([
286
353
  (0, actionDecorator_1.CreateAction)({
287
354
  name: "deposit",
@@ -35,6 +35,30 @@ const mockVault = (num) => ({
35
35
  "7day": num * 100,
36
36
  },
37
37
  },
38
+ numberOfHolders: num,
39
+ rewards: [
40
+ {
41
+ apy: {
42
+ "7day": num * 100,
43
+ },
44
+ asset: {
45
+ name: `reward-token-${num}`,
46
+ symbol: `RT${num}`,
47
+ assetAddress: `0x${num.toString(16).padStart(40, "0")}`,
48
+ decimals: 18,
49
+ },
50
+ },
51
+ ],
52
+ description: `Description for vault-${num}`,
53
+ additionalIncentives: `Incentives for vault-${num}`,
54
+ score: {
55
+ vaultScore: num,
56
+ vaultTvlScore: num,
57
+ protocolTvlScore: num,
58
+ holderScore: num,
59
+ networkScore: num,
60
+ assetScore: num,
61
+ },
38
62
  isTransactional: true,
39
63
  },
40
64
  transformedResult: {
@@ -53,6 +77,8 @@ const mockVault = (num) => ({
53
77
  rewards: num,
54
78
  total: num,
55
79
  },
80
+ vaultsFyiScore: num,
81
+ numberOfHolders: num,
56
82
  link: `https://app.vaults.fyi/opportunity/network-${num}/0x${num.toString(16).padStart(40, "0")}`,
57
83
  },
58
84
  });
@@ -435,4 +461,143 @@ describe("VaultsfyiActionProvider", () => {
435
461
  expect(await provider.positions(mockWalletProvider)).toBe("Failed to fetch positions: Internal Server Error, some more info");
436
462
  });
437
463
  });
464
+ describe("vault_details action", () => {
465
+ it("should transform vault details correctly", async () => {
466
+ const detailedVault = mockVault(1);
467
+ mockedFetch.mockResolvedValue(mockFetchResult(200, detailedVault.apiResult));
468
+ const args = {
469
+ vaultAddress: "0x123456",
470
+ network: "mainnet",
471
+ };
472
+ const result = await provider.vaultDetails(mockWalletProvider, args);
473
+ const parsedResult = JSON.parse(result);
474
+ expect(parsedResult).toStrictEqual({
475
+ ...detailedVault.transformedResult,
476
+ description: detailedVault.apiResult.description,
477
+ additionalIncentives: detailedVault.apiResult.additionalIncentives,
478
+ rewards: [
479
+ {
480
+ apy: detailedVault.apiResult.rewards[0].apy["7day"] / 100,
481
+ asset: {
482
+ name: detailedVault.apiResult.rewards[0].asset.name,
483
+ symbol: detailedVault.apiResult.rewards[0].asset.symbol,
484
+ address: detailedVault.apiResult.rewards[0].asset.assetAddress,
485
+ },
486
+ },
487
+ ],
488
+ });
489
+ });
490
+ it("should return an error if the API request fails", async () => {
491
+ mockedFetch.mockResolvedValue(mockFetchResult(500, { error: "Internal Server Error", message: "some more info" }));
492
+ const args = {
493
+ vaultAddress: "0x123456",
494
+ network: "mainnet",
495
+ };
496
+ expect(await provider.vaultDetails(mockWalletProvider, args)).toBe("Failed to fetch vault: Internal Server Error, some more info");
497
+ });
498
+ });
499
+ describe("vault_historical_data action", () => {
500
+ it("should fetch and transform historical data correctly", async () => {
501
+ // Mock API responses for both TVL and APY data
502
+ const mockApyData = {
503
+ timestamp: 1704067200, // Jan 1, 2024
504
+ blockNumber: 12345678,
505
+ apy: {
506
+ base: 500,
507
+ rewards: 300,
508
+ total: 800,
509
+ },
510
+ };
511
+ const mockTvlData = {
512
+ timestamp: 1704067200, // Jan 1, 2024
513
+ blockNumber: 12345678,
514
+ tvlDetails: {
515
+ tvlUsd: 1000000,
516
+ },
517
+ };
518
+ // Set up the mock to return appropriate data for each call
519
+ mockedFetch.mockImplementation(url => {
520
+ if (url.includes("/historical-apy/")) {
521
+ return Promise.resolve(mockFetchResult(200, mockApyData));
522
+ }
523
+ else if (url.includes("/historical-tvl/")) {
524
+ return Promise.resolve(mockFetchResult(200, mockTvlData));
525
+ }
526
+ return Promise.resolve(mockFetchResult(500, { error: "Unexpected URL" }));
527
+ });
528
+ const args = {
529
+ vaultAddress: "0x123456",
530
+ network: "mainnet",
531
+ date: "2024-01-01T00:00:00Z",
532
+ };
533
+ const result = await provider.vaultHistoricalData(mockWalletProvider, args);
534
+ const parsedResult = JSON.parse(result);
535
+ expect(parsedResult).toEqual({
536
+ apy: {
537
+ apy: {
538
+ base: 5,
539
+ rewards: 3,
540
+ total: 8,
541
+ },
542
+ date: "2024-01-01T00:00:00.000Z",
543
+ blockNumber: 12345678,
544
+ },
545
+ tvl: {
546
+ tvlInUsd: 1000000,
547
+ date: "2024-01-01T00:00:00.000Z",
548
+ blockNumber: 12345678,
549
+ },
550
+ });
551
+ });
552
+ it("should return an error if the APY API request fails", async () => {
553
+ // Set up the mock to fail for APY but succeed for TVL
554
+ mockedFetch.mockImplementation(url => {
555
+ if (url.includes("/historical-apy/")) {
556
+ return Promise.resolve(mockFetchResult(500, {
557
+ error: "Internal Server Error",
558
+ message: "Failed to get historical APY data",
559
+ }));
560
+ }
561
+ else if (url.includes("/historical-tvl/")) {
562
+ return Promise.resolve(mockFetchResult(200, {
563
+ timestamp: 1704067200,
564
+ blockNumber: 12345678,
565
+ tvlDetails: { tvlUsd: 1000000 },
566
+ }));
567
+ }
568
+ return Promise.resolve(mockFetchResult(500, { error: "Unexpected URL" }));
569
+ });
570
+ const args = {
571
+ vaultAddress: "0x123456",
572
+ network: "mainnet",
573
+ date: "2024-01-01T00:00:00Z",
574
+ };
575
+ expect(await provider.vaultHistoricalData(mockWalletProvider, args)).toBe("Failed to fetch vault: Internal Server Error, Failed to get historical APY data");
576
+ });
577
+ it("should return an error if the TVL API request fails", async () => {
578
+ // Set up the mock to succeed for APY but fail for TVL
579
+ mockedFetch.mockImplementation(url => {
580
+ if (url.includes("/historical-apy/")) {
581
+ return Promise.resolve(mockFetchResult(200, {
582
+ timestamp: 1704067200,
583
+ blockNumber: 12345678,
584
+ apy: { base: 500, rewards: 300, total: 800 },
585
+ }));
586
+ }
587
+ else if (url.includes("/historical-tvl/")) {
588
+ return Promise.resolve(mockFetchResult(500, {
589
+ error: "Internal Server Error",
590
+ message: "Failed to get historical TVL data",
591
+ }));
592
+ }
593
+ return Promise.resolve(mockFetchResult(500, { error: "Unexpected URL" }));
594
+ });
595
+ const args = {
596
+ vaultAddress: "0x123456",
597
+ network: "mainnet",
598
+ date: "2024-01-01T00:00:00Z",
599
+ };
600
+ expect(await provider.vaultHistoricalData(mockWalletProvider, args)).toBe("Failed to fetch vault: Internal Server Error, Failed to get historical TVL data");
601
+ });
602
+ });
438
603
  });
@@ -0,0 +1 @@
1
+ export * from "./x402ActionProvider";
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./x402ActionProvider"), exports);
@@ -0,0 +1,30 @@
1
+ import { z } from "zod";
2
+ export declare const PaidRequestSchema: z.ZodObject<{
3
+ url: z.ZodString;
4
+ method: z.ZodDefault<z.ZodEnum<["GET", "POST", "PUT", "DELETE", "PATCH"]>>;
5
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
6
+ body: z.ZodOptional<z.ZodAny>;
7
+ }, "strip", z.ZodTypeAny, {
8
+ method: "POST" | "GET" | "PUT" | "DELETE" | "PATCH";
9
+ url: string;
10
+ body?: any;
11
+ headers?: Record<string, string> | undefined;
12
+ }, {
13
+ url: string;
14
+ method?: "POST" | "GET" | "PUT" | "DELETE" | "PATCH" | undefined;
15
+ body?: any;
16
+ headers?: Record<string, string> | undefined;
17
+ }>;
18
+ export declare const FetchPaymentInfoSchema: z.ZodObject<{
19
+ url: z.ZodString;
20
+ method: z.ZodDefault<z.ZodEnum<["GET", "POST", "PUT", "DELETE", "PATCH"]>>;
21
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
22
+ }, "strip", z.ZodTypeAny, {
23
+ method: "POST" | "GET" | "PUT" | "DELETE" | "PATCH";
24
+ url: string;
25
+ headers?: Record<string, string> | undefined;
26
+ }, {
27
+ url: string;
28
+ method?: "POST" | "GET" | "PUT" | "DELETE" | "PATCH" | undefined;
29
+ headers?: Record<string, string> | undefined;
30
+ }>;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FetchPaymentInfoSchema = exports.PaidRequestSchema = void 0;
4
+ const zod_1 = require("zod");
5
+ exports.PaidRequestSchema = zod_1.z
6
+ .object({
7
+ url: zod_1.z.string().url().describe("The URL of the x402-protected API endpoint"),
8
+ method: zod_1.z
9
+ .enum(["GET", "POST", "PUT", "DELETE", "PATCH"])
10
+ .default("GET")
11
+ .describe("The HTTP method to use for the request"),
12
+ headers: zod_1.z.record(zod_1.z.string()).optional().describe("Optional headers to include in the request"),
13
+ body: zod_1.z.any().optional().describe("Optional request body for POST/PUT/PATCH requests"),
14
+ })
15
+ .strip()
16
+ .describe("Instructions for making a paid request to an x402-protected API");
17
+ exports.FetchPaymentInfoSchema = zod_1.z
18
+ .object({
19
+ url: zod_1.z.string().url().describe("The URL of the x402-protected API endpoint"),
20
+ method: zod_1.z
21
+ .enum(["GET", "POST", "PUT", "DELETE", "PATCH"])
22
+ .default("GET")
23
+ .describe("The HTTP method to use for the request"),
24
+ headers: zod_1.z.record(zod_1.z.string()).optional().describe("Optional headers to include in the request"),
25
+ })
26
+ .strip()
27
+ .describe("Instructions for fetching payment information from an x402-protected API endpoint");
@@ -0,0 +1,38 @@
1
+ import { z } from "zod";
2
+ import { ActionProvider } from "../actionProvider";
3
+ import { Network } from "../../network";
4
+ import { PaidRequestSchema, FetchPaymentInfoSchema } from "./schemas";
5
+ import { EvmWalletProvider } from "../../wallet-providers";
6
+ /**
7
+ * X402ActionProvider is an action provider for making paid requests to x402-protected APIs.
8
+ */
9
+ export declare class X402ActionProvider extends ActionProvider<EvmWalletProvider> {
10
+ /**
11
+ * Constructor for the X402ActionProvider.
12
+ */
13
+ constructor();
14
+ /**
15
+ * Makes a paid request to an x402-protected API endpoint.
16
+ *
17
+ * @param walletProvider - The wallet provider to use for payment signing.
18
+ * @param args - The input arguments for the action.
19
+ * @returns A message containing the API response data.
20
+ */
21
+ paidRequest(walletProvider: EvmWalletProvider, args: z.infer<typeof PaidRequestSchema>): Promise<string>;
22
+ /**
23
+ * Fetches payment information from an x402-protected API endpoint without making the payment.
24
+ *
25
+ * @param walletProvider - The wallet provider (not used for this action but required by interface).
26
+ * @param args - The input arguments for the action.
27
+ * @returns A message containing the payment requirements and endpoint information.
28
+ */
29
+ fetchPaymentInfo(walletProvider: EvmWalletProvider, args: z.infer<typeof FetchPaymentInfoSchema>): Promise<string>;
30
+ /**
31
+ * Checks if the X402 action provider supports the given network.
32
+ *
33
+ * @param network - The network to check.
34
+ * @returns True if the X402 action provider supports the network, false otherwise.
35
+ */
36
+ supportsNetwork: (network: Network) => boolean;
37
+ }
38
+ export declare const x402ActionProvider: () => X402ActionProvider;