@coinbase/agentkit 0.10.2 → 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.
Files changed (107) hide show
  1. package/README.md +89 -10
  2. package/dist/action-providers/across/acrossActionProvider.js +2 -4
  3. package/dist/action-providers/across/acrossActionProvider.test.js +10 -5
  4. package/dist/action-providers/baseAccount/baseAccountActionProvider.js +5 -7
  5. package/dist/action-providers/cdp/cdpApiActionProvider.js +7 -30
  6. package/dist/action-providers/cdp/cdpApiActionProvider.test.js +2 -8
  7. package/dist/action-providers/cdp/faucetUtils.d.ts +38 -0
  8. package/dist/action-providers/cdp/faucetUtils.js +81 -0
  9. package/dist/action-providers/clanker/schemas.d.ts +4 -4
  10. package/dist/action-providers/clanker/utils.d.ts +2 -1
  11. package/dist/action-providers/clanker/utils.js +2 -2
  12. package/dist/action-providers/enso/constants.d.ts +4 -0
  13. package/dist/action-providers/enso/constants.js +10 -0
  14. package/dist/action-providers/enso/ensoActionProvider.d.ts +34 -0
  15. package/dist/action-providers/enso/ensoActionProvider.js +125 -0
  16. package/dist/action-providers/enso/ensoActionProvider.test.d.ts +1 -0
  17. package/dist/action-providers/enso/ensoActionProvider.test.js +141 -0
  18. package/dist/action-providers/enso/index.d.ts +1 -0
  19. package/dist/action-providers/enso/index.js +17 -0
  20. package/dist/action-providers/enso/schemas.d.ts +23 -0
  21. package/dist/action-providers/enso/schemas.js +22 -0
  22. package/dist/action-providers/erc20/constants.d.ts +2 -0
  23. package/dist/action-providers/erc20/constants.js +2 -0
  24. package/dist/action-providers/erc20/erc20ActionProvider.d.ts +17 -1
  25. package/dist/action-providers/erc20/erc20ActionProvider.js +103 -1
  26. package/dist/action-providers/erc20/erc20ActionProvider.test.js +201 -0
  27. package/dist/action-providers/erc20/schemas.d.ts +29 -0
  28. package/dist/action-providers/erc20/schemas.js +34 -1
  29. package/dist/action-providers/index.d.ts +4 -1
  30. package/dist/action-providers/index.js +4 -1
  31. package/dist/action-providers/jupiter/jupiterActionProvider.js +2 -2
  32. package/dist/action-providers/spl/splActionProvider.js +12 -13
  33. package/dist/action-providers/superfluid/graphQueries/superfluidGraphQueries.js +2 -2
  34. package/dist/action-providers/sushi/constants.d.ts +35 -0
  35. package/dist/action-providers/sushi/constants.js +7 -0
  36. package/dist/action-providers/sushi/index.d.ts +4 -0
  37. package/dist/action-providers/sushi/index.js +20 -0
  38. package/dist/action-providers/sushi/sushiDataActionProvider.d.ts +32 -0
  39. package/dist/action-providers/sushi/sushiDataActionProvider.js +113 -0
  40. package/dist/action-providers/sushi/sushiDataSchemas.d.ts +11 -0
  41. package/dist/action-providers/sushi/sushiDataSchemas.js +16 -0
  42. package/dist/action-providers/sushi/sushiRouterActionProvider.d.ts +40 -0
  43. package/dist/action-providers/sushi/sushiRouterActionProvider.js +386 -0
  44. package/dist/action-providers/sushi/sushiRouterActionProvider.test.d.ts +1 -0
  45. package/dist/action-providers/sushi/sushiRouterActionProvider.test.js +392 -0
  46. package/dist/action-providers/sushi/sushiRouterSchemas.d.ts +36 -0
  47. package/dist/action-providers/sushi/sushiRouterSchemas.js +55 -0
  48. package/dist/action-providers/vaultsfyi/constants.d.ts +8 -12
  49. package/dist/action-providers/vaultsfyi/constants.js +47 -13
  50. package/dist/action-providers/vaultsfyi/schemas.d.ts +120 -65
  51. package/dist/action-providers/vaultsfyi/schemas.js +72 -38
  52. package/dist/action-providers/vaultsfyi/sdk.d.ts +8 -0
  53. package/dist/action-providers/vaultsfyi/sdk.js +15 -0
  54. package/dist/action-providers/vaultsfyi/utils.d.ts +151 -55
  55. package/dist/action-providers/vaultsfyi/utils.js +29 -75
  56. package/dist/action-providers/vaultsfyi/vaultsfyiActionProvider.d.ts +55 -16
  57. package/dist/action-providers/vaultsfyi/vaultsfyiActionProvider.js +413 -217
  58. package/dist/action-providers/vaultsfyi/vaultsfyiActionProvider.test.js +509 -316
  59. package/dist/action-providers/wallet/walletActionProvider.js +1 -1
  60. package/dist/action-providers/weth/constants.d.ts +0 -1
  61. package/dist/action-providers/weth/constants.js +1 -2
  62. package/dist/action-providers/weth/schemas.js +6 -2
  63. package/dist/action-providers/weth/wethActionProvider.d.ts +7 -0
  64. package/dist/action-providers/weth/wethActionProvider.js +57 -32
  65. package/dist/action-providers/weth/wethActionProvider.test.js +60 -11
  66. package/dist/action-providers/x402/constants.d.ts +67 -0
  67. package/dist/action-providers/x402/constants.js +37 -0
  68. package/dist/action-providers/x402/schemas.d.ts +45 -5
  69. package/dist/action-providers/x402/schemas.js +81 -11
  70. package/dist/action-providers/x402/utils.d.ts +89 -14
  71. package/dist/action-providers/x402/utils.js +335 -31
  72. package/dist/action-providers/x402/x402ActionProvider.d.ts +21 -7
  73. package/dist/action-providers/x402/x402ActionProvider.js +250 -184
  74. package/dist/action-providers/x402/x402ActionProvider.test.js +240 -236
  75. package/dist/action-providers/yelay/constants.d.ts +64 -0
  76. package/dist/action-providers/yelay/constants.js +137 -0
  77. package/dist/action-providers/yelay/index.d.ts +2 -0
  78. package/dist/action-providers/yelay/index.js +18 -0
  79. package/dist/action-providers/yelay/schemas.d.ts +47 -0
  80. package/dist/action-providers/yelay/schemas.js +59 -0
  81. package/dist/action-providers/yelay/types.d.ts +24 -0
  82. package/dist/action-providers/yelay/yelayActionProvider.d.ts +70 -0
  83. package/dist/action-providers/yelay/yelayActionProvider.js +329 -0
  84. package/dist/action-providers/yelay/yelayActionProvider.test.d.ts +1 -0
  85. package/dist/action-providers/yelay/yelayActionProvider.test.js +302 -0
  86. package/dist/action-providers/zora/zoraActionProvider.js +4 -5
  87. package/dist/wallet-providers/cdpSmartWalletProvider.js +1 -3
  88. package/dist/wallet-providers/cdpSolanaWalletProvider.d.ts +14 -0
  89. package/dist/wallet-providers/cdpSolanaWalletProvider.js +39 -3
  90. package/dist/wallet-providers/cdpSolanaWalletProvider.test.js +16 -0
  91. package/dist/wallet-providers/privySvmWalletProvider.d.ts +14 -0
  92. package/dist/wallet-providers/privySvmWalletProvider.js +17 -0
  93. package/dist/wallet-providers/privySvmWalletProvider.test.js +10 -0
  94. package/dist/wallet-providers/solanaKeypairWalletProvider.d.ts +14 -0
  95. package/dist/wallet-providers/solanaKeypairWalletProvider.js +17 -0
  96. package/dist/wallet-providers/svmWalletProvider.d.ts +34 -0
  97. package/dist/wallet-providers/svmWalletProvider.js +43 -0
  98. package/dist/wallet-providers/svmWalletProvider.test.js +10 -0
  99. package/package.json +11 -6
  100. package/dist/action-providers/vaultsfyi/api/actions.d.ts +0 -41
  101. package/dist/action-providers/vaultsfyi/api/actions.js +0 -28
  102. package/dist/action-providers/vaultsfyi/api/historicalData.d.ts +0 -31
  103. package/dist/action-providers/vaultsfyi/api/historicalData.js +0 -44
  104. package/dist/action-providers/vaultsfyi/api/types.d.ts +0 -34
  105. package/dist/action-providers/vaultsfyi/api/vaults.d.ts +0 -66
  106. package/dist/action-providers/vaultsfyi/api/vaults.js +0 -57
  107. /package/dist/action-providers/{vaultsfyi/api → yelay}/types.js +0 -0
@@ -0,0 +1,392 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const sushiRouterSchemas_1 = require("./sushiRouterSchemas");
4
+ const evm_1 = require("sushi/evm");
5
+ const sushiRouterActionProvider_1 = require("./sushiRouterActionProvider");
6
+ const viem_1 = require("viem");
7
+ const constants_1 = require("./constants");
8
+ // Mock the entire module
9
+ jest.mock("sushi/evm", () => {
10
+ const originalModule = jest.requireActual("sushi/evm");
11
+ return {
12
+ __esModule: true,
13
+ ...originalModule,
14
+ getSwap: jest.fn(originalModule.getSwap),
15
+ };
16
+ });
17
+ const mockedGetSwap = evm_1.getSwap;
18
+ describe("Sushi Action Provider Input Schemas", () => {
19
+ describe("Swap Schema", () => {
20
+ it("should successfully parse valid input", () => {
21
+ const validInput = {
22
+ fromAssetAddress: "0xe6b2af36b3bb8d47206a129ff11d5a2de2a63c83",
23
+ amount: "0.0001",
24
+ toAssetAddress: "0x1234567890123456789012345678901234567890",
25
+ maxSlippage: 0.005,
26
+ };
27
+ const result = sushiRouterSchemas_1.SushiSwapSchema.safeParse(validInput);
28
+ expect(result.success).toBe(true);
29
+ expect(result.data).toEqual(validInput);
30
+ });
31
+ it("should fail parsing invalid fromAssetAddress", () => {
32
+ const invalidInput = {
33
+ fromAssetAddress: "invalid-address",
34
+ amount: "0.0001",
35
+ toAssetAddress: "0x1234567890123456789012345678901234567890",
36
+ maxSlippage: 0.005,
37
+ };
38
+ const result = sushiRouterSchemas_1.SushiSwapSchema.safeParse(invalidInput);
39
+ expect(result.success).toBe(false);
40
+ });
41
+ it("should fail parsing invalid toAssetAddress", () => {
42
+ const invalidInput = {
43
+ fromAssetAddress: "0xe6b2af36b3bb8d47206a129ff11d5a2de2a63c83",
44
+ amount: "0.0001",
45
+ toAssetAddress: "invalid-address",
46
+ maxSlippage: 0.005,
47
+ };
48
+ const result = sushiRouterSchemas_1.SushiSwapSchema.safeParse(invalidInput);
49
+ expect(result.success).toBe(false);
50
+ });
51
+ it("should fail parsing invalid maxSlippage (>1)", () => {
52
+ const invalidInput = {
53
+ fromAssetAddress: "0xe6b2af36b3bb8d47206a129ff11d5a2de2a63c83",
54
+ amount: "0.0001",
55
+ toAssetAddress: "0x1234567890123456789012345678901234567890",
56
+ maxSlippage: 1.1,
57
+ };
58
+ const result = sushiRouterSchemas_1.SushiSwapSchema.safeParse(invalidInput);
59
+ expect(result.success).toBe(false);
60
+ });
61
+ it("should fail parsing invalid maxSlippage (<0)", () => {
62
+ const invalidInput = {
63
+ fromAssetAddress: "0xe6b2af36b3bb8d47206a129ff11d5a2de2a63c83",
64
+ amount: "0.0001",
65
+ toAssetAddress: "0x1234567890123456789012345678901234567890",
66
+ maxSlippage: -1.1,
67
+ };
68
+ const result = sushiRouterSchemas_1.SushiSwapSchema.safeParse(invalidInput);
69
+ expect(result.success).toBe(false);
70
+ });
71
+ });
72
+ describe("Quote Schema", () => {
73
+ it("should successfully parse valid input", () => {
74
+ const validInput = {
75
+ fromAssetAddress: "0xe6b2af36b3bb8d47206a129ff11d5a2de2a63c83",
76
+ amount: "0.0001",
77
+ toAssetAddress: "0x1234567890123456789012345678901234567890",
78
+ };
79
+ const result = sushiRouterSchemas_1.SushiQuoteSchema.safeParse(validInput);
80
+ expect(result.success).toBe(true);
81
+ expect(result.data).toEqual(validInput);
82
+ });
83
+ it("should fail parsing invalid fromAssetAddress", () => {
84
+ const invalidInput = {
85
+ fromAssetAddress: "invalid-address",
86
+ amount: "0.0001",
87
+ toAssetAddress: "0x1234567890123456789012345678901234567890",
88
+ maxSlippage: 0.005,
89
+ };
90
+ const result = sushiRouterSchemas_1.SushiQuoteSchema.safeParse(invalidInput);
91
+ expect(result.success).toBe(false);
92
+ });
93
+ it("should fail parsing invalid toAssetAddress", () => {
94
+ const invalidInput = {
95
+ fromAssetAddress: "0xe6b2af36b3bb8d47206a129ff11d5a2de2a63c83",
96
+ amount: "0.0001",
97
+ toAssetAddress: "invalid-address",
98
+ maxSlippage: 0.005,
99
+ };
100
+ const result = sushiRouterSchemas_1.SushiQuoteSchema.safeParse(invalidInput);
101
+ expect(result.success).toBe(false);
102
+ });
103
+ });
104
+ });
105
+ describe("Sushi Action Provider", () => {
106
+ let actionProvider;
107
+ let mockWallet;
108
+ const amountIn = BigInt(1000000);
109
+ const amountOut = BigInt(500000);
110
+ const nativeToken = {
111
+ address: evm_1.nativeAddress,
112
+ symbol: "ETH",
113
+ name: "Ether",
114
+ decimals: 18,
115
+ };
116
+ const tokenIn = {
117
+ address: "0xaAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaaAa",
118
+ symbol: "TIN",
119
+ name: "Token In",
120
+ decimals: 18,
121
+ };
122
+ const tokenOut = {
123
+ address: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
124
+ symbol: "TOU",
125
+ name: "Token Out",
126
+ decimals: 18,
127
+ };
128
+ const user = "0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF";
129
+ const txHash = "0xhash";
130
+ const chainId = 1;
131
+ const getRouteLog = ({ tokenIn, tokenOut, amountIn, amountOut, }) => [
132
+ {
133
+ data: (0, viem_1.encodeAbiParameters)((0, viem_1.parseAbiParameters)("address to, address tokenOut, uint256 amountIn, uint256 amountOut, int256 slippage, bytes32 diagnosticsFirst32"), [user, tokenOut.address, amountIn, amountOut, 0n, `0x${"00".repeat(32)}`]),
134
+ topics: (0, viem_1.encodeEventTopics)({
135
+ abi: constants_1.routeProcessor9Abi_Route,
136
+ eventName: "Route",
137
+ args: {
138
+ from: user,
139
+ tokenIn: tokenIn.address,
140
+ referralCode: 0,
141
+ },
142
+ }),
143
+ },
144
+ ];
145
+ const getSuccessfullSwapResponse = async ({ tokenIn, amountIn, tokenOut, amountOut, }) => ({
146
+ amountIn: String(amountIn),
147
+ assumedAmountOut: String(amountOut),
148
+ priceImpact: 0,
149
+ status: evm_1.RouteStatus.Success,
150
+ swapPrice: 1,
151
+ tokens: [tokenIn, tokenOut],
152
+ tokenFrom: tokenIn,
153
+ tokenTo: tokenOut,
154
+ tx: {
155
+ to: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
156
+ data: "0x",
157
+ from: user,
158
+ value: BigInt(0),
159
+ gas: "1000000",
160
+ gasPrice: 1000000000,
161
+ },
162
+ });
163
+ beforeEach(() => {
164
+ // Reset all mocks before each test
165
+ jest.clearAllMocks();
166
+ actionProvider = new sushiRouterActionProvider_1.SushiRouterActionProvider();
167
+ mockWallet = {
168
+ readContract: jest.fn(),
169
+ sendTransaction: jest.fn(),
170
+ waitForTransactionReceipt: jest.fn(),
171
+ getBalance: jest.fn(),
172
+ getNetwork: jest.fn().mockResolvedValue({
173
+ protocolFamily: "evm",
174
+ networkId: "ethereum-mainnet",
175
+ chainId: String(chainId),
176
+ }),
177
+ getAddress: jest.fn().mockReturnValue(user),
178
+ };
179
+ });
180
+ describe("swap", () => {
181
+ it("should successfully perform a swap (token -> token)", async () => {
182
+ const args = {
183
+ amount: (0, viem_1.formatUnits)(amountIn, tokenIn.decimals),
184
+ fromAssetAddress: tokenIn.address,
185
+ toAssetAddress: tokenOut.address,
186
+ maxSlippage: 0.005,
187
+ };
188
+ /*
189
+ * 1. Mock the readContract which checks the decimals of the fromAssetAddress token (18, default)
190
+ * 2. Mock the readContract which checks for the balance of the fromAssetAddress token (1000000, enough balance)
191
+ * 3. Mock the readContract which checks for the approval (0, not approved)
192
+ */
193
+ mockWallet.readContract
194
+ .mockResolvedValueOnce(tokenIn.decimals)
195
+ .mockResolvedValueOnce(amountIn)
196
+ .mockResolvedValueOnce(BigInt(0));
197
+ mockWallet.sendTransaction.mockResolvedValue(txHash);
198
+ /*
199
+ * 1. Mock the waitForTransactionReceipt to return success for the approval tx
200
+ * 2. Mock the waitForTransactionReceipt to return success for the swap tx, including the Route log
201
+ */
202
+ mockWallet.waitForTransactionReceipt
203
+ .mockResolvedValueOnce({
204
+ status: "success",
205
+ })
206
+ .mockResolvedValueOnce({
207
+ status: "success",
208
+ logs: getRouteLog({
209
+ tokenIn,
210
+ tokenOut,
211
+ amountIn,
212
+ amountOut,
213
+ }),
214
+ });
215
+ mockedGetSwap.mockReturnValue(getSuccessfullSwapResponse({
216
+ tokenIn,
217
+ amountIn,
218
+ tokenOut,
219
+ amountOut,
220
+ }));
221
+ const result = await actionProvider.swap(mockWallet, args);
222
+ expect(mockWallet.readContract).toHaveBeenCalledTimes(3); // Decimals + Balance + Approval
223
+ expect(mockWallet.sendTransaction).toHaveBeenCalledTimes(2); // Approval + Swap
224
+ expect(mockedGetSwap).toHaveBeenCalledTimes(2);
225
+ expect(result).toContain(`Swapped ${(0, viem_1.formatUnits)(amountIn, tokenIn.decimals)} of ${tokenIn.symbol} (${tokenIn.address}) for ${(0, viem_1.formatUnits)(amountOut, tokenOut.decimals)} of ${tokenOut.symbol} (${tokenOut.address})`);
226
+ expect(result).toContain(`Transaction hash: ${txHash}`);
227
+ expect(result).toContain(`Transaction link: ${(0, evm_1.getEvmChainById)(chainId).getTransactionUrl(txHash)}`);
228
+ expect(result).toContain(`on ${(0, evm_1.getEvmChainById)(chainId).shortName}`);
229
+ });
230
+ it("should successfully perform a swap (native -> token)", async () => {
231
+ const args = {
232
+ amount: (0, viem_1.formatUnits)(amountIn, tokenIn.decimals),
233
+ fromAssetAddress: nativeToken.address,
234
+ toAssetAddress: tokenOut.address,
235
+ maxSlippage: 0.005,
236
+ };
237
+ // Mock the readContract which checks for the balance of the fromAssetAddress token (1000000, enough balance)
238
+ mockWallet.getBalance.mockResolvedValue(amountIn);
239
+ mockWallet.sendTransaction.mockResolvedValue(txHash);
240
+ // Mock the waitForTransactionReceipt to return success for the swap tx, including the Route log
241
+ mockWallet.waitForTransactionReceipt.mockResolvedValueOnce({
242
+ status: "success",
243
+ logs: getRouteLog({
244
+ tokenIn: nativeToken,
245
+ tokenOut,
246
+ amountIn,
247
+ amountOut,
248
+ }),
249
+ });
250
+ mockedGetSwap.mockReturnValue(getSuccessfullSwapResponse({
251
+ tokenIn: nativeToken,
252
+ amountIn,
253
+ tokenOut,
254
+ amountOut,
255
+ }));
256
+ const result = await actionProvider.swap(mockWallet, args);
257
+ expect(mockWallet.getBalance).toHaveBeenCalledTimes(1);
258
+ expect(mockWallet.readContract).toHaveBeenCalledTimes(0); // No balance check nor approval
259
+ expect(mockWallet.sendTransaction).toHaveBeenCalledTimes(1); // Swap
260
+ expect(mockedGetSwap).toHaveBeenCalledTimes(2);
261
+ expect(result).toContain(`Swapped ${(0, viem_1.formatUnits)(amountIn, nativeToken.decimals)} of ${nativeToken.symbol} (${nativeToken.address}) for ${(0, viem_1.formatUnits)(amountOut, tokenOut.decimals)} of ${tokenOut.symbol} (${tokenOut.address})`);
262
+ expect(result).toContain(`Transaction hash: ${txHash}`);
263
+ expect(result).toContain(`Transaction link: ${(0, evm_1.getEvmChainById)(chainId).getTransactionUrl(txHash)}`);
264
+ expect(result).toContain(`on ${(0, evm_1.getEvmChainById)(chainId).shortName}`);
265
+ });
266
+ it("should fail if there isn't enough balance (native)", async () => {
267
+ const args = {
268
+ amount: (0, viem_1.formatUnits)(amountIn, tokenIn.decimals),
269
+ fromAssetAddress: nativeToken.address,
270
+ toAssetAddress: tokenOut.address,
271
+ maxSlippage: 0.005,
272
+ };
273
+ // Mock the readContract which checks for the balance of the fromAssetAddress token (99, not enough balance)
274
+ mockWallet.getBalance.mockResolvedValue(amountIn - BigInt(1));
275
+ const result = await actionProvider.swap(mockWallet, args);
276
+ expect(mockWallet.getBalance).toHaveBeenCalledTimes(1);
277
+ expect(mockWallet.readContract).toHaveBeenCalledTimes(0);
278
+ expect(mockWallet.sendTransaction).toHaveBeenCalledTimes(0);
279
+ expect(mockedGetSwap).toHaveBeenCalledTimes(1);
280
+ expect(result).toContain(`Swap failed: Insufficient balance for ${nativeToken.symbol} (${nativeToken.address})`);
281
+ });
282
+ it("should fail if there isn't enough balance (token)", async () => {
283
+ const args = {
284
+ amount: (0, viem_1.formatUnits)(amountIn, tokenIn.decimals),
285
+ fromAssetAddress: tokenIn.address,
286
+ toAssetAddress: tokenOut.address,
287
+ maxSlippage: 0.005,
288
+ };
289
+ /*
290
+ * 1. Mock the readContract which checks the decimals of the fromAssetAddress token (18, default)
291
+ * 2. Mock the readContract which checks for the balance of the fromAssetAddress token (1000000, enough balance)
292
+ */
293
+ mockWallet.readContract.mockResolvedValueOnce(18).mockResolvedValue(amountIn - BigInt(1));
294
+ mockedGetSwap.mockReturnValue(getSuccessfullSwapResponse({
295
+ tokenIn,
296
+ amountIn,
297
+ tokenOut,
298
+ amountOut,
299
+ }));
300
+ const result = await actionProvider.swap(mockWallet, args);
301
+ expect(mockWallet.getBalance).toHaveBeenCalledTimes(0);
302
+ expect(mockWallet.readContract).toHaveBeenCalledTimes(2);
303
+ expect(mockWallet.sendTransaction).toHaveBeenCalledTimes(0);
304
+ expect(mockedGetSwap).toHaveBeenCalledTimes(1);
305
+ expect(result).toContain(`Swap failed: Insufficient balance for ${tokenIn.symbol} (${tokenIn.address})`);
306
+ });
307
+ it("should not approve if already approved", async () => {
308
+ const args = {
309
+ amount: (0, viem_1.formatUnits)(amountIn, tokenIn.decimals),
310
+ fromAssetAddress: tokenIn.address,
311
+ toAssetAddress: tokenOut.address,
312
+ maxSlippage: 0.005,
313
+ };
314
+ /*
315
+ * 1. Mock the readContract which checks the decimals of the fromAssetAddress token (18, default)
316
+ * 2. Mock the readContract which checks for the balance of the fromAssetAddress token (1000000, enough balance)
317
+ * 3. Mock the readContract which checks for the approval (1000000, approved)
318
+ */
319
+ mockWallet.readContract
320
+ .mockResolvedValueOnce(tokenIn.decimals)
321
+ .mockResolvedValueOnce(amountIn)
322
+ .mockResolvedValueOnce(amountIn);
323
+ mockWallet.sendTransaction.mockResolvedValue(txHash);
324
+ // Mock the waitForTransactionReceipt to return success for the swap tx, including the Route log
325
+ mockWallet.waitForTransactionReceipt.mockResolvedValueOnce({
326
+ status: "success",
327
+ logs: getRouteLog({
328
+ tokenIn,
329
+ tokenOut,
330
+ amountIn,
331
+ amountOut,
332
+ }),
333
+ });
334
+ mockedGetSwap.mockReturnValue(getSuccessfullSwapResponse({
335
+ tokenIn,
336
+ amountIn,
337
+ tokenOut,
338
+ amountOut,
339
+ }));
340
+ const result = await actionProvider.swap(mockWallet, args);
341
+ expect(mockWallet.getBalance).toHaveBeenCalledTimes(0);
342
+ expect(mockWallet.readContract).toHaveBeenCalledTimes(3); // Decimals + Balance + Allowance
343
+ expect(mockWallet.sendTransaction).toHaveBeenCalledTimes(1); // Swap
344
+ expect(mockedGetSwap).toHaveBeenCalledTimes(2);
345
+ expect(result).toContain(`Swapped`);
346
+ });
347
+ it("should fail if there's no route", async () => {
348
+ const args = {
349
+ amount: (0, viem_1.formatUnits)(amountIn, tokenIn.decimals),
350
+ fromAssetAddress: tokenIn.address,
351
+ toAssetAddress: tokenOut.address,
352
+ maxSlippage: 0.005,
353
+ };
354
+ /*
355
+ * 1. Mock the readContract which checks for decimals of the fromAssetAddress token (18, default)
356
+ * 2. Mock the readContract which checks for the balance of the fromAssetAddress token (1000000, enough balance)
357
+ */
358
+ mockWallet.readContract
359
+ .mockResolvedValueOnce(tokenIn.decimals)
360
+ .mockResolvedValueOnce(amountIn);
361
+ mockedGetSwap.mockReturnValue(new Promise(r => r({
362
+ status: evm_1.RouteStatus.NoWay,
363
+ })));
364
+ const result = await actionProvider.swap(mockWallet, args);
365
+ expect(mockWallet.getBalance).toHaveBeenCalledTimes(0);
366
+ expect(mockWallet.readContract).toHaveBeenCalledTimes(1); // Decimals
367
+ expect(mockWallet.sendTransaction).toHaveBeenCalledTimes(0);
368
+ expect(mockedGetSwap).toHaveBeenCalledTimes(1);
369
+ expect(result).toContain(`No route found to swap ${amountIn} of ${tokenIn.address} for ${tokenOut.address}`);
370
+ });
371
+ });
372
+ describe("quote", () => {
373
+ it("should successfully fetch a quote (token -> token)", async () => {
374
+ const args = {
375
+ amount: (0, viem_1.formatUnits)(amountIn, tokenIn.decimals),
376
+ fromAssetAddress: tokenIn.address,
377
+ toAssetAddress: tokenOut.address,
378
+ };
379
+ mockedGetSwap.mockReturnValue(getSuccessfullSwapResponse({
380
+ tokenIn,
381
+ amountIn,
382
+ tokenOut,
383
+ amountOut,
384
+ }));
385
+ const result = await actionProvider.quote(mockWallet, args);
386
+ expect(mockedGetSwap).toHaveBeenCalledTimes(1);
387
+ expect(result).toContain(`Found a quote for ${tokenIn.symbol} (${tokenIn.address}) -> ${tokenOut.symbol} (${tokenOut.address})`);
388
+ expect(result).toContain(`AmountIn: ${(0, viem_1.formatUnits)(amountIn, tokenIn.decimals)}`);
389
+ expect(result).toContain(`AmountOut: ${(0, viem_1.formatUnits)(amountOut, tokenOut.decimals)}`);
390
+ });
391
+ });
392
+ });
@@ -0,0 +1,36 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Input schema for asset swap action
4
+ */
5
+ export declare const SushiSwapSchema: z.ZodObject<{
6
+ fromAssetAddress: z.ZodEffects<z.ZodString, `0x${string}`, string>;
7
+ amount: z.ZodString;
8
+ toAssetAddress: z.ZodEffects<z.ZodString, `0x${string}`, string>;
9
+ maxSlippage: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
10
+ }, "strip", z.ZodTypeAny, {
11
+ amount: string;
12
+ fromAssetAddress: `0x${string}`;
13
+ toAssetAddress: `0x${string}`;
14
+ maxSlippage: number;
15
+ }, {
16
+ amount: string;
17
+ fromAssetAddress: string;
18
+ toAssetAddress: string;
19
+ maxSlippage?: number | undefined;
20
+ }>;
21
+ /**
22
+ * Input schema for quote action
23
+ */
24
+ export declare const SushiQuoteSchema: z.ZodObject<{
25
+ fromAssetAddress: z.ZodEffects<z.ZodString, `0x${string}`, string>;
26
+ amount: z.ZodString;
27
+ toAssetAddress: z.ZodEffects<z.ZodString, `0x${string}`, string>;
28
+ }, "strip", z.ZodTypeAny, {
29
+ amount: string;
30
+ fromAssetAddress: `0x${string}`;
31
+ toAssetAddress: `0x${string}`;
32
+ }, {
33
+ amount: string;
34
+ fromAssetAddress: string;
35
+ toAssetAddress: string;
36
+ }>;
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SushiQuoteSchema = exports.SushiSwapSchema = void 0;
4
+ const zod_1 = require("zod");
5
+ /**
6
+ * Input schema for asset swap action
7
+ */
8
+ exports.SushiSwapSchema = zod_1.z
9
+ .object({
10
+ fromAssetAddress: zod_1.z
11
+ .string()
12
+ .regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address format")
13
+ .transform(val => val)
14
+ .describe("The Ethereum address of the input asset"),
15
+ amount: zod_1.z
16
+ .string()
17
+ .regex(/^\d+(\.\d+)?$/, "Invalid number format")
18
+ .describe("The amount of the input asset to swap, in the human readable format"),
19
+ toAssetAddress: zod_1.z
20
+ .string()
21
+ .regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address format")
22
+ .transform(val => val)
23
+ .describe("The Ethereum address of the output asset"),
24
+ maxSlippage: zod_1.z
25
+ .number()
26
+ .min(0)
27
+ .max(1)
28
+ .optional()
29
+ .default(0.005) // 0.05%
30
+ .describe("The maximum slippage allowed for the swap, where 0 is 0% and 1 is 100%"),
31
+ })
32
+ .strip()
33
+ .describe("Instructions for trading assets");
34
+ /**
35
+ * Input schema for quote action
36
+ */
37
+ exports.SushiQuoteSchema = zod_1.z
38
+ .object({
39
+ fromAssetAddress: zod_1.z
40
+ .string()
41
+ .regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address format")
42
+ .transform(val => val)
43
+ .describe("The Ethereum address of the input asset"),
44
+ amount: zod_1.z
45
+ .string()
46
+ .regex(/^\d+(\.\d+)?$/, "Invalid number format")
47
+ .describe("The amount of the input asset to get a quote for"),
48
+ toAssetAddress: zod_1.z
49
+ .string()
50
+ .regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address format")
51
+ .transform(val => val)
52
+ .describe("The Ethereum address of the output asset"),
53
+ })
54
+ .strip()
55
+ .describe("Instructions for fetching a quote for a trade");
@@ -1,12 +1,8 @@
1
- export declare const VAULTS_API_URL = "https://api.vaults.fyi/v1";
2
- export declare const VAULTSFYI_SUPPORTED_CHAINS: {
3
- readonly 1: "mainnet";
4
- readonly 42161: "arbitrum";
5
- readonly 10: "optimism";
6
- readonly 137: "polygon";
7
- readonly 100: "gnosis";
8
- readonly 8453: "base";
9
- readonly 130: "unichain";
10
- readonly 1923: "swellchain";
11
- readonly 42220: "celo";
12
- };
1
+ export declare const SUPPORTED_CHAIN_IDS: string[];
2
+ /**
3
+ * Get the network name from a chain id
4
+ *
5
+ * @param chainId - The chain id
6
+ * @returns The network name
7
+ */
8
+ export declare function getNetworkNameFromChainId(chainId: string): string | undefined;
@@ -1,15 +1,49 @@
1
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.VAULTSFYI_SUPPORTED_CHAINS = exports.VAULTS_API_URL = void 0;
4
- exports.VAULTS_API_URL = "https://api.vaults.fyi/v1";
5
- exports.VAULTSFYI_SUPPORTED_CHAINS = {
6
- 1: "mainnet",
7
- 42161: "arbitrum",
8
- 10: "optimism",
9
- 137: "polygon",
10
- 100: "gnosis",
11
- 8453: "base",
12
- 130: "unichain",
13
- 1923: "swellchain",
14
- 42220: "celo",
15
- };
36
+ exports.SUPPORTED_CHAIN_IDS = void 0;
37
+ exports.getNetworkNameFromChainId = getNetworkNameFromChainId;
38
+ const sdk_1 = require("@vaultsfyi/sdk");
39
+ const viemChains = __importStar(require("viem/chains"));
40
+ exports.SUPPORTED_CHAIN_IDS = sdk_1.SUPPORTED_NETWORKS.map(network => viemChains[network]?.id.toString()).filter(id => id !== undefined);
41
+ /**
42
+ * Get the network name from a chain id
43
+ *
44
+ * @param chainId - The chain id
45
+ * @returns The network name
46
+ */
47
+ function getNetworkNameFromChainId(chainId) {
48
+ return sdk_1.SUPPORTED_NETWORKS.find(network => viemChains[network]?.id.toString() === chainId);
49
+ }