@coinbase/agentkit 0.10.0 → 0.10.1

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 (131) hide show
  1. package/README.md +75 -0
  2. package/dist/action-providers/across/acrossActionProvider.js +3 -3
  3. package/dist/action-providers/cdp/cdpApiActionProvider.d.ts +3 -12
  4. package/dist/action-providers/cdp/cdpApiActionProvider.js +2 -81
  5. package/dist/action-providers/cdp/cdpApiActionProvider.test.js +0 -125
  6. package/dist/action-providers/cdp/cdpEvmWalletActionProvider.d.ts +18 -3
  7. package/dist/action-providers/cdp/cdpEvmWalletActionProvider.js +223 -23
  8. package/dist/action-providers/cdp/cdpEvmWalletActionProvider.test.js +278 -0
  9. package/dist/action-providers/cdp/cdpSmartWalletActionProvider.d.ts +17 -2
  10. package/dist/action-providers/cdp/cdpSmartWalletActionProvider.js +223 -18
  11. package/dist/action-providers/cdp/cdpSmartWalletActionProvider.test.js +265 -1
  12. package/dist/action-providers/cdp/schemas.d.ts +12 -12
  13. package/dist/action-providers/cdp/schemas.js +17 -5
  14. package/dist/action-providers/cdp/swapUtils.d.ts +32 -0
  15. package/dist/action-providers/cdp/swapUtils.js +142 -0
  16. package/dist/action-providers/clanker/clankerActionProvider.d.ts +43 -0
  17. package/dist/action-providers/clanker/clankerActionProvider.js +130 -0
  18. package/dist/action-providers/clanker/clankerActionProvider.test.d.ts +4 -0
  19. package/dist/action-providers/clanker/clankerActionProvider.test.js +119 -0
  20. package/dist/action-providers/clanker/index.d.ts +2 -0
  21. package/dist/action-providers/clanker/index.js +18 -0
  22. package/dist/action-providers/clanker/schemas.d.ts +56 -0
  23. package/dist/action-providers/clanker/schemas.js +47 -0
  24. package/dist/action-providers/clanker/utils.d.ts +9 -0
  25. package/dist/action-providers/clanker/utils.js +23 -0
  26. package/dist/action-providers/compound/constants.d.ts +1 -1
  27. package/dist/action-providers/compound/constants.js +2 -2
  28. package/dist/action-providers/erc20/constants.d.ts +35 -135
  29. package/dist/action-providers/erc20/constants.js +37 -189
  30. package/dist/action-providers/erc20/erc20ActionProvider.d.ts +9 -1
  31. package/dist/action-providers/erc20/erc20ActionProvider.js +87 -35
  32. package/dist/action-providers/erc20/erc20ActionProvider.test.js +115 -52
  33. package/dist/action-providers/erc20/schemas.d.ts +25 -12
  34. package/dist/action-providers/erc20/schemas.js +34 -6
  35. package/dist/action-providers/erc20/utils.d.ts +19 -0
  36. package/dist/action-providers/erc20/utils.js +54 -0
  37. package/dist/action-providers/flaunch/constants.d.ts +1 -1
  38. package/dist/action-providers/flaunch/constants.js +2 -2
  39. package/dist/action-providers/flaunch/flaunchActionProvider.js +3 -11
  40. package/dist/action-providers/flaunch/flaunchActionProvider.test.js +5 -0
  41. package/dist/action-providers/index.d.ts +3 -0
  42. package/dist/action-providers/index.js +3 -0
  43. package/dist/action-providers/jupiter/schemas.d.ts +1 -1
  44. package/dist/action-providers/moonwell/schemas.d.ts +2 -2
  45. package/dist/action-providers/morpho/morphoActionProvider.js +5 -5
  46. package/dist/action-providers/morpho/schemas.d.ts +2 -2
  47. package/dist/action-providers/pyth/pythActionProvider.js +5 -0
  48. package/dist/action-providers/pyth/pythActionProvider.test.js +5 -1
  49. package/dist/action-providers/superfluid/constants.d.ts +814 -0
  50. package/dist/action-providers/superfluid/constants.js +2826 -0
  51. package/dist/action-providers/superfluid/graphQueries/endpoints.d.ts +2 -0
  52. package/dist/action-providers/superfluid/graphQueries/endpoints.js +5 -0
  53. package/dist/action-providers/superfluid/graphQueries/queries.d.ts +1 -0
  54. package/dist/action-providers/superfluid/graphQueries/queries.js +35 -0
  55. package/dist/action-providers/superfluid/graphQueries/superfluidGraphQueries.d.ts +8 -0
  56. package/dist/action-providers/superfluid/graphQueries/superfluidGraphQueries.js +24 -0
  57. package/dist/action-providers/superfluid/graphQueries/types.d.ts +27 -0
  58. package/dist/action-providers/superfluid/graphQueries/types.js +2 -0
  59. package/dist/action-providers/superfluid/index.d.ts +7 -0
  60. package/dist/action-providers/superfluid/index.js +23 -0
  61. package/dist/action-providers/superfluid/schemas.d.ts +86 -0
  62. package/dist/action-providers/superfluid/schemas.js +103 -0
  63. package/dist/action-providers/superfluid/superfluidActionProvider.d.ts +20 -0
  64. package/dist/action-providers/superfluid/superfluidActionProvider.js +36 -0
  65. package/dist/action-providers/superfluid/superfluidPoolActionProvider.d.ts +46 -0
  66. package/dist/action-providers/superfluid/superfluidPoolActionProvider.js +143 -0
  67. package/dist/action-providers/superfluid/superfluidPoolActionProvider.test.d.ts +1 -0
  68. package/dist/action-providers/superfluid/superfluidPoolActionProvider.test.js +92 -0
  69. package/dist/action-providers/superfluid/superfluidQueryActionProvider.d.ts +27 -0
  70. package/dist/action-providers/superfluid/superfluidQueryActionProvider.js +71 -0
  71. package/dist/action-providers/superfluid/superfluidQueryActionProvider.test.d.ts +1 -0
  72. package/dist/action-providers/superfluid/superfluidQueryActionProvider.test.js +57 -0
  73. package/dist/action-providers/superfluid/superfluidStreamActionProvider.d.ts +56 -0
  74. package/dist/action-providers/superfluid/superfluidStreamActionProvider.js +191 -0
  75. package/dist/action-providers/superfluid/superfluidStreamActionProvider.test.d.ts +1 -0
  76. package/dist/action-providers/superfluid/superfluidStreamActionProvider.test.js +80 -0
  77. package/dist/action-providers/superfluid/superfluidSuperTokenCreatorActionProvider.d.ts +30 -0
  78. package/dist/action-providers/superfluid/superfluidSuperTokenCreatorActionProvider.js +108 -0
  79. package/dist/action-providers/superfluid/superfluidSuperTokenCreatorActionProvider.test.d.ts +1 -0
  80. package/dist/action-providers/superfluid/superfluidSuperTokenCreatorActionProvider.test.js +75 -0
  81. package/dist/action-providers/superfluid/superfluidWrapperActionProvider.d.ts +32 -0
  82. package/dist/action-providers/superfluid/superfluidWrapperActionProvider.js +101 -0
  83. package/dist/action-providers/superfluid/superfluidWrapperActionProvider.test.d.ts +1 -0
  84. package/dist/action-providers/superfluid/superfluidWrapperActionProvider.test.js +85 -0
  85. package/dist/action-providers/superfluid/utils/parseLogs.d.ts +18 -0
  86. package/dist/action-providers/superfluid/utils/parseLogs.js +78 -0
  87. package/dist/action-providers/truemarkets/truemarketsActionProvider.d.ts +4 -16
  88. package/dist/action-providers/truemarkets/truemarketsActionProvider.js +20 -41
  89. package/dist/action-providers/truemarkets/truemarketsActionProvider.test.js +11 -33
  90. package/dist/action-providers/wallet/walletActionProvider.js +21 -10
  91. package/dist/action-providers/wallet/walletActionProvider.test.js +6 -2
  92. package/dist/action-providers/zeroX/index.d.ts +1 -0
  93. package/dist/action-providers/zeroX/index.js +17 -0
  94. package/dist/action-providers/zeroX/schemas.d.ts +51 -0
  95. package/dist/action-providers/zeroX/schemas.js +82 -0
  96. package/dist/action-providers/zeroX/utils.d.ts +23 -0
  97. package/dist/action-providers/zeroX/utils.js +106 -0
  98. package/dist/action-providers/zeroX/zeroXActionProvider.d.ts +57 -0
  99. package/dist/action-providers/zeroX/zeroXActionProvider.js +407 -0
  100. package/dist/action-providers/zeroX/zeroXActionProvider.test.d.ts +1 -0
  101. package/dist/action-providers/zeroX/zeroXActionProvider.test.js +445 -0
  102. package/dist/wallet-providers/cdpEvmWalletProvider.d.ts +20 -2
  103. package/dist/wallet-providers/cdpEvmWalletProvider.js +40 -15
  104. package/dist/wallet-providers/cdpShared.d.ts +5 -0
  105. package/dist/wallet-providers/cdpSmartWalletProvider.d.ts +22 -3
  106. package/dist/wallet-providers/cdpSmartWalletProvider.js +43 -19
  107. package/dist/wallet-providers/cdpSolanaWalletProvider.d.ts +1 -1
  108. package/dist/wallet-providers/cdpSolanaWalletProvider.js +7 -7
  109. package/dist/wallet-providers/cdpSolanaWalletProvider.test.js +15 -12
  110. package/dist/wallet-providers/evmWalletProvider.d.ts +5 -1
  111. package/dist/wallet-providers/legacyCdpSmartWalletProvider.d.ts +9 -2
  112. package/dist/wallet-providers/legacyCdpSmartWalletProvider.js +12 -2
  113. package/dist/wallet-providers/legacyCdpWalletProvider.d.ts +12 -2
  114. package/dist/wallet-providers/legacyCdpWalletProvider.js +11 -2
  115. package/dist/wallet-providers/privyEvmDelegatedEmbeddedWalletProvider.d.ts +10 -2
  116. package/dist/wallet-providers/privyEvmDelegatedEmbeddedWalletProvider.js +12 -3
  117. package/dist/wallet-providers/privyEvmDelegatedEmbeddedWalletProvider.test.js +1 -1
  118. package/dist/wallet-providers/privyEvmWalletProvider.d.ts +2 -0
  119. package/dist/wallet-providers/privyEvmWalletProvider.js +2 -1
  120. package/dist/wallet-providers/privyEvmWalletProvider.test.js +1 -1
  121. package/dist/wallet-providers/solanaKeypairWalletProvider.d.ts +1 -1
  122. package/dist/wallet-providers/solanaKeypairWalletProvider.js +3 -4
  123. package/dist/wallet-providers/solanaKeypairWalletProvider.test.js +4 -2
  124. package/dist/wallet-providers/viemWalletProvider.d.ts +12 -2
  125. package/dist/wallet-providers/viemWalletProvider.js +12 -3
  126. package/dist/wallet-providers/viemWalletProvider.test.js +6 -5
  127. package/dist/wallet-providers/walletProvider.d.ts +1 -1
  128. package/dist/wallet-providers/zeroDevWalletProvider.d.ts +10 -2
  129. package/dist/wallet-providers/zeroDevWalletProvider.js +14 -5
  130. package/dist/wallet-providers/zeroDevWalletProvider.test.js +2 -2
  131. package/package.json +4 -2
@@ -0,0 +1,445 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const zeroXActionProvider_1 = require("./zeroXActionProvider");
4
+ const schemas_1 = require("./schemas");
5
+ // Mock the fetch function
6
+ global.fetch = jest.fn();
7
+ describe("ZeroX Schema Validation", () => {
8
+ it("should validate GetSwapPrice schema with valid input", () => {
9
+ const validInput = {
10
+ sellToken: "0x1234567890123456789012345678901234567890",
11
+ buyToken: "0x0987654321098765432109876543210987654321",
12
+ sellAmount: "1.5",
13
+ slippageBps: 50,
14
+ };
15
+ const result = schemas_1.GetSwapPriceSchema.safeParse(validInput);
16
+ expect(result.success).toBe(true);
17
+ });
18
+ it("should fail validation with invalid address format", () => {
19
+ const invalidInput = {
20
+ sellToken: "invalid-address",
21
+ buyToken: "0x0987654321098765432109876543210987654321",
22
+ sellAmount: "1.5",
23
+ slippageBps: 50,
24
+ };
25
+ const result = schemas_1.GetSwapPriceSchema.safeParse(invalidInput);
26
+ expect(result.success).toBe(false);
27
+ });
28
+ it("should use default slippageBps when not provided", () => {
29
+ const inputWithoutSlippage = {
30
+ sellToken: "0x1234567890123456789012345678901234567890",
31
+ buyToken: "0x0987654321098765432109876543210987654321",
32
+ sellAmount: "1.5",
33
+ };
34
+ const result = schemas_1.GetSwapPriceSchema.safeParse(inputWithoutSlippage);
35
+ expect(result.success).toBe(true);
36
+ if (result.success) {
37
+ expect(result.data.slippageBps).toBe(100); // Default value from schema
38
+ }
39
+ });
40
+ it("should validate swap fee parameters when both provided", () => {
41
+ const inputWithSwapFees = {
42
+ sellToken: "0x1234567890123456789012345678901234567890",
43
+ buyToken: "0x0987654321098765432109876543210987654321",
44
+ sellAmount: "1.5",
45
+ swapFeeRecipient: "0xabcdef1234567890abcdef1234567890abcdef12",
46
+ swapFeeBps: 50,
47
+ };
48
+ const result = schemas_1.GetSwapPriceSchema.safeParse(inputWithSwapFees);
49
+ expect(result.success).toBe(true);
50
+ });
51
+ it("should validate when only swapFeeRecipient provided (swapFeeBps defaults to 100)", () => {
52
+ const inputWithOnlyRecipient = {
53
+ sellToken: "0x1234567890123456789012345678901234567890",
54
+ buyToken: "0x0987654321098765432109876543210987654321",
55
+ sellAmount: "1.5",
56
+ swapFeeBps: 100,
57
+ swapFeeRecipient: "0xabcdef1234567890abcdef1234567890abcdef12",
58
+ };
59
+ const result = schemas_1.GetSwapPriceSchema.safeParse(inputWithOnlyRecipient);
60
+ expect(result.success).toBe(true);
61
+ if (result.success) {
62
+ expect(result.data.swapFeeBps).toBe(100); // Default value
63
+ }
64
+ });
65
+ it("should fail validation when swapFeeBps exceeds maximum", () => {
66
+ const inputWithInvalidSwapFeeBps = {
67
+ sellToken: "0x1234567890123456789012345678901234567890",
68
+ buyToken: "0x0987654321098765432109876543210987654321",
69
+ sellAmount: "1.5",
70
+ swapFeeRecipient: "0xabcdef1234567890abcdef1234567890abcdef12",
71
+ swapFeeBps: 1500, // Exceeds maximum of 1000
72
+ };
73
+ const result = schemas_1.GetSwapPriceSchema.safeParse(inputWithInvalidSwapFeeBps);
74
+ expect(result.success).toBe(false);
75
+ });
76
+ it("should validate ExecuteSwap schema with valid input", () => {
77
+ const validInput = {
78
+ sellToken: "0x1234567890123456789012345678901234567890",
79
+ buyToken: "0x0987654321098765432109876543210987654321",
80
+ sellAmount: "1.5",
81
+ slippageBps: 50,
82
+ };
83
+ const result = schemas_1.ExecuteSwapSchema.safeParse(validInput);
84
+ expect(result.success).toBe(true);
85
+ });
86
+ });
87
+ describe("ZeroX Action Provider", () => {
88
+ let provider;
89
+ let mockWalletProvider;
90
+ const MOCK_SELL_TOKEN = "0x1234567890123456789012345678901234567890";
91
+ const MOCK_BUY_TOKEN = "0x0987654321098765432109876543210987654321";
92
+ const MOCK_SELL_AMOUNT = "1.5";
93
+ const MOCK_CHAIN_ID = 1;
94
+ const MOCK_ADDRESS = "0xabcdef1234567890abcdef1234567890abcdef12";
95
+ beforeEach(() => {
96
+ provider = (0, zeroXActionProvider_1.zeroXActionProvider)({ apiKey: "test-api-key" });
97
+ mockWalletProvider = {
98
+ getAddress: jest.fn().mockReturnValue(MOCK_ADDRESS),
99
+ getNetwork: jest.fn().mockReturnValue({
100
+ chainId: MOCK_CHAIN_ID,
101
+ protocolFamily: "evm",
102
+ networkId: "ethereum-mainnet",
103
+ }),
104
+ readContract: jest.fn(),
105
+ getPublicClient: jest.fn().mockReturnValue({
106
+ multicall: jest.fn(),
107
+ }),
108
+ sendTransaction: jest.fn(),
109
+ waitForTransactionReceipt: jest.fn(),
110
+ signTypedData: jest.fn(),
111
+ };
112
+ // Reset mocks
113
+ global.fetch.mockReset();
114
+ });
115
+ describe("getSwapPrice", () => {
116
+ beforeEach(() => {
117
+ // Mock multicall for token details (decimals and names)
118
+ const mockMulticallResults = [
119
+ { status: "success", result: 18 }, // sellToken decimals
120
+ { status: "success", result: "TEST" }, // sellToken name
121
+ { status: "success", result: 6 }, // buyToken decimals
122
+ { status: "success", result: "USDC" }, // buyToken name
123
+ ];
124
+ mockWalletProvider.getPublicClient().multicall.mockResolvedValue(mockMulticallResults);
125
+ // Mock fetch for price API
126
+ const mockPriceResponse = {
127
+ buyAmount: "1000000", // 1 USDC with 6 decimals
128
+ minBuyAmount: "990000", // 0.99 USDC with 6 decimals
129
+ totalNetworkFee: "100000000000000", // 0.0001 ETH
130
+ issues: { balance: null },
131
+ liquidityAvailable: true,
132
+ };
133
+ global.fetch.mockResolvedValueOnce({
134
+ ok: true,
135
+ json: jest.fn().mockResolvedValueOnce(mockPriceResponse),
136
+ });
137
+ });
138
+ it("should get swap price successfully", async () => {
139
+ const args = {
140
+ sellToken: MOCK_SELL_TOKEN,
141
+ buyToken: MOCK_BUY_TOKEN,
142
+ sellAmount: MOCK_SELL_AMOUNT,
143
+ slippageBps: 50,
144
+ swapFeeBps: 100,
145
+ };
146
+ const response = await provider.getSwapPrice(mockWalletProvider, args);
147
+ const parsedResponse = JSON.parse(response);
148
+ // Verify fetch was called with correct URL params
149
+ expect(global.fetch).toHaveBeenCalledTimes(1);
150
+ expect(global.fetch.mock.calls[0][0]).toContain("api.0x.org/swap/permit2/price");
151
+ expect(global.fetch.mock.calls[0][0]).toContain(`chainId=${MOCK_CHAIN_ID}`);
152
+ expect(global.fetch.mock.calls[0][0]).toContain(`sellToken=${MOCK_SELL_TOKEN}`);
153
+ expect(global.fetch.mock.calls[0][0]).toContain(`buyToken=${MOCK_BUY_TOKEN}`);
154
+ // Verify response formatting
155
+ expect(parsedResponse.success).toBe(true);
156
+ expect(parsedResponse.sellToken).toBe(MOCK_SELL_TOKEN);
157
+ expect(parsedResponse.sellTokenName).toBe("TEST");
158
+ expect(parsedResponse.buyToken).toBe(MOCK_BUY_TOKEN);
159
+ expect(parsedResponse.buyTokenName).toBe("USDC");
160
+ expect(parsedResponse.liquidityAvailable).toBe(true);
161
+ expect(parsedResponse.balanceEnough).toBe(true);
162
+ expect(parsedResponse.slippageBps).toBe(50);
163
+ expect(parsedResponse.buyAmount).toBeDefined();
164
+ expect(parsedResponse.minBuyAmount).toBeDefined();
165
+ });
166
+ it("should handle API errors", async () => {
167
+ global.fetch.mockReset();
168
+ global.fetch.mockResolvedValueOnce({
169
+ ok: false,
170
+ status: 400,
171
+ statusText: "Bad Request",
172
+ text: jest.fn().mockResolvedValueOnce("Invalid request parameters"),
173
+ });
174
+ const args = {
175
+ sellToken: MOCK_SELL_TOKEN,
176
+ buyToken: MOCK_BUY_TOKEN,
177
+ sellAmount: MOCK_SELL_AMOUNT,
178
+ slippageBps: 50,
179
+ swapFeeBps: 100,
180
+ };
181
+ const response = await provider.getSwapPrice(mockWalletProvider, args);
182
+ const parsedResponse = JSON.parse(response);
183
+ expect(parsedResponse.success).toBe(false);
184
+ expect(parsedResponse.error).toContain("Error fetching swap price");
185
+ });
186
+ it("should handle fetch errors", async () => {
187
+ global.fetch.mockReset();
188
+ global.fetch.mockRejectedValueOnce(new Error("Network error"));
189
+ const args = {
190
+ sellToken: MOCK_SELL_TOKEN,
191
+ buyToken: MOCK_BUY_TOKEN,
192
+ sellAmount: MOCK_SELL_AMOUNT,
193
+ slippageBps: 50,
194
+ swapFeeBps: 100,
195
+ };
196
+ const response = await provider.getSwapPrice(mockWalletProvider, args);
197
+ const parsedResponse = JSON.parse(response);
198
+ expect(parsedResponse.success).toBe(false);
199
+ expect(parsedResponse.error).toContain("Error fetching swap price");
200
+ });
201
+ it("should include swap fee parameters in API call when provided", async () => {
202
+ const args = {
203
+ sellToken: MOCK_SELL_TOKEN,
204
+ buyToken: MOCK_BUY_TOKEN,
205
+ sellAmount: MOCK_SELL_AMOUNT,
206
+ slippageBps: 50,
207
+ swapFeeRecipient: "0xabcdef1234567890abcdef1234567890abcdef12",
208
+ swapFeeBps: 100,
209
+ };
210
+ await provider.getSwapPrice(mockWalletProvider, args);
211
+ // Verify fetch was called with swap fee parameters
212
+ expect(global.fetch).toHaveBeenCalledTimes(1);
213
+ const fetchUrl = global.fetch.mock.calls[0][0];
214
+ expect(fetchUrl).toContain("swapFeeRecipient=0xabcdef1234567890abcdef1234567890abcdef12");
215
+ expect(fetchUrl).toContain("swapFeeBps=100");
216
+ expect(fetchUrl).toContain(`swapFeeToken=${MOCK_SELL_TOKEN}`);
217
+ });
218
+ it("should not include swap fee parameters when not provided", async () => {
219
+ const args = {
220
+ sellToken: MOCK_SELL_TOKEN,
221
+ buyToken: MOCK_BUY_TOKEN,
222
+ sellAmount: MOCK_SELL_AMOUNT,
223
+ slippageBps: 50,
224
+ swapFeeBps: 100,
225
+ };
226
+ await provider.getSwapPrice(mockWalletProvider, args);
227
+ // Verify fetch was called without swap fee parameters
228
+ expect(global.fetch).toHaveBeenCalledTimes(1);
229
+ const fetchUrl = global.fetch.mock.calls[0][0];
230
+ expect(fetchUrl).not.toContain("swapFeeRecipient");
231
+ expect(fetchUrl).not.toContain("swapFeeBps");
232
+ expect(fetchUrl).not.toContain("swapFeeToken");
233
+ });
234
+ it("should include swap fee parameters with default swapFeeBps when only recipient provided", async () => {
235
+ const args = {
236
+ sellToken: MOCK_SELL_TOKEN,
237
+ buyToken: MOCK_BUY_TOKEN,
238
+ sellAmount: MOCK_SELL_AMOUNT,
239
+ slippageBps: 50,
240
+ swapFeeBps: 100,
241
+ swapFeeRecipient: "0xabcdef1234567890abcdef1234567890abcdef12",
242
+ };
243
+ await provider.getSwapPrice(mockWalletProvider, args);
244
+ // Verify fetch was called with swap fee parameters including default swapFeeBps
245
+ expect(global.fetch).toHaveBeenCalledTimes(1);
246
+ const fetchUrl = global.fetch.mock.calls[0][0];
247
+ expect(fetchUrl).toContain("swapFeeRecipient=0xabcdef1234567890abcdef1234567890abcdef12");
248
+ expect(fetchUrl).toContain("swapFeeBps=100"); // Default value
249
+ expect(fetchUrl).toContain(`swapFeeToken=${MOCK_SELL_TOKEN}`);
250
+ });
251
+ });
252
+ describe("executeSwap", () => {
253
+ const MOCK_TX_HASH = "0xtxhash123456";
254
+ beforeEach(() => {
255
+ // Mock multicall for token details (decimals and names)
256
+ const mockMulticallResults = [
257
+ { status: "success", result: 18 }, // sellToken decimals
258
+ { status: "success", result: "TEST" }, // sellToken name
259
+ { status: "success", result: 6 }, // buyToken decimals
260
+ { status: "success", result: "USDC" }, // buyToken name
261
+ ];
262
+ mockWalletProvider.getPublicClient().multicall.mockResolvedValue(mockMulticallResults);
263
+ // Mock API responses
264
+ const mockPriceResponse = {
265
+ buyAmount: "1000000", // 1 USDC with 6 decimals
266
+ minBuyAmount: "990000", // 0.99 USDC with 6 decimals
267
+ totalNetworkFee: "100000000000000", // 0.0001 ETH
268
+ issues: null,
269
+ liquidityAvailable: true,
270
+ };
271
+ const mockQuoteResponse = {
272
+ buyAmount: "1000000",
273
+ minBuyAmount: "990000",
274
+ totalNetworkFee: "100000000000000",
275
+ transaction: {
276
+ to: "0x0000000000000000000000000000000000000001",
277
+ data: "0x12345678",
278
+ value: "1500000000000000000", // 1.5 ETH
279
+ gas: "300000",
280
+ gasPrice: "20000000000",
281
+ },
282
+ };
283
+ // First fetch for price
284
+ global.fetch.mockResolvedValueOnce({
285
+ ok: true,
286
+ json: jest.fn().mockResolvedValueOnce(mockPriceResponse),
287
+ });
288
+ // Second fetch for quote
289
+ global.fetch.mockResolvedValueOnce({
290
+ ok: true,
291
+ json: jest.fn().mockResolvedValueOnce(mockQuoteResponse),
292
+ });
293
+ // Mock transaction functions
294
+ mockWalletProvider.sendTransaction.mockResolvedValueOnce(MOCK_TX_HASH);
295
+ mockWalletProvider.waitForTransactionReceipt.mockResolvedValueOnce({
296
+ transactionHash: MOCK_TX_HASH,
297
+ status: "success",
298
+ });
299
+ });
300
+ it("should execute swap successfully", async () => {
301
+ const args = {
302
+ sellToken: MOCK_SELL_TOKEN,
303
+ buyToken: MOCK_BUY_TOKEN,
304
+ sellAmount: MOCK_SELL_AMOUNT,
305
+ slippageBps: 50,
306
+ swapFeeBps: 100,
307
+ };
308
+ const response = await provider.executeSwap(mockWalletProvider, args);
309
+ const parsedResponse = JSON.parse(response);
310
+ // Verify API calls
311
+ expect(global.fetch).toHaveBeenCalledTimes(2);
312
+ expect(global.fetch.mock.calls[0][0]).toContain("api.0x.org/swap/permit2/price");
313
+ expect(global.fetch.mock.calls[1][0]).toContain("api.0x.org/swap/permit2/quote");
314
+ // Verify transaction was sent
315
+ expect(mockWalletProvider.sendTransaction).toHaveBeenCalledTimes(1);
316
+ expect(mockWalletProvider.waitForTransactionReceipt).toHaveBeenCalledWith(MOCK_TX_HASH);
317
+ // Verify response formatting
318
+ expect(parsedResponse.success).toBe(true);
319
+ expect(parsedResponse.sellToken).toBe(MOCK_SELL_TOKEN);
320
+ expect(parsedResponse.sellTokenName).toBe("TEST");
321
+ expect(parsedResponse.buyToken).toBe(MOCK_BUY_TOKEN);
322
+ expect(parsedResponse.buyTokenName).toBe("USDC");
323
+ expect(parsedResponse.transactionHash).toBe(MOCK_TX_HASH);
324
+ expect(parsedResponse.slippageBps).toBe(50);
325
+ expect(parsedResponse.network).toBe("ethereum-mainnet");
326
+ });
327
+ it("should handle price API errors", async () => {
328
+ global.fetch.mockReset();
329
+ global.fetch.mockResolvedValueOnce({
330
+ ok: false,
331
+ status: 400,
332
+ statusText: "Bad Request",
333
+ text: jest.fn().mockResolvedValueOnce("Invalid request parameters"),
334
+ });
335
+ const args = {
336
+ sellToken: MOCK_SELL_TOKEN,
337
+ buyToken: MOCK_BUY_TOKEN,
338
+ sellAmount: MOCK_SELL_AMOUNT,
339
+ slippageBps: 50,
340
+ swapFeeBps: 100,
341
+ };
342
+ const response = await provider.executeSwap(mockWalletProvider, args);
343
+ const parsedResponse = JSON.parse(response);
344
+ expect(parsedResponse.success).toBe(false);
345
+ expect(parsedResponse.error).toContain("Error fetching swap price");
346
+ });
347
+ it("should handle no liquidity available", async () => {
348
+ global.fetch.mockReset();
349
+ const mockPriceResponse = {
350
+ liquidityAvailable: false,
351
+ };
352
+ global.fetch.mockResolvedValueOnce({
353
+ ok: true,
354
+ json: jest.fn().mockResolvedValueOnce(mockPriceResponse),
355
+ });
356
+ const args = {
357
+ sellToken: MOCK_SELL_TOKEN,
358
+ buyToken: MOCK_BUY_TOKEN,
359
+ sellAmount: MOCK_SELL_AMOUNT,
360
+ slippageBps: 50,
361
+ swapFeeBps: 100,
362
+ };
363
+ const response = await provider.executeSwap(mockWalletProvider, args);
364
+ const parsedResponse = JSON.parse(response);
365
+ expect(parsedResponse.success).toBe(false);
366
+ expect(parsedResponse.error).toContain("No liquidity available");
367
+ });
368
+ it("should include swap fee parameters in both API calls when provided", async () => {
369
+ const args = {
370
+ sellToken: MOCK_SELL_TOKEN,
371
+ buyToken: MOCK_BUY_TOKEN,
372
+ sellAmount: MOCK_SELL_AMOUNT,
373
+ slippageBps: 50,
374
+ swapFeeRecipient: "0xabcdef1234567890abcdef1234567890abcdef12",
375
+ swapFeeBps: 100,
376
+ };
377
+ await provider.executeSwap(mockWalletProvider, args);
378
+ // Verify both API calls include swap fee parameters
379
+ expect(global.fetch).toHaveBeenCalledTimes(2);
380
+ // Check price API call
381
+ const priceUrl = global.fetch.mock.calls[0][0];
382
+ expect(priceUrl).toContain("swapFeeRecipient=0xabcdef1234567890abcdef1234567890abcdef12");
383
+ expect(priceUrl).toContain("swapFeeBps=100");
384
+ expect(priceUrl).toContain(`swapFeeToken=${MOCK_SELL_TOKEN}`);
385
+ // Check quote API call
386
+ const quoteUrl = global.fetch.mock.calls[1][0];
387
+ expect(quoteUrl).toContain("swapFeeRecipient=0xabcdef1234567890abcdef1234567890abcdef12");
388
+ expect(quoteUrl).toContain("swapFeeBps=100");
389
+ expect(quoteUrl).toContain(`swapFeeToken=${MOCK_SELL_TOKEN}`);
390
+ });
391
+ it("should not include swap fee parameters when not provided", async () => {
392
+ const args = {
393
+ sellToken: MOCK_SELL_TOKEN,
394
+ buyToken: MOCK_BUY_TOKEN,
395
+ sellAmount: MOCK_SELL_AMOUNT,
396
+ slippageBps: 50,
397
+ swapFeeBps: 100,
398
+ };
399
+ await provider.executeSwap(mockWalletProvider, args);
400
+ // Verify both API calls exclude swap fee parameters
401
+ expect(global.fetch).toHaveBeenCalledTimes(2);
402
+ // Check price API call
403
+ const priceUrl = global.fetch.mock.calls[0][0];
404
+ expect(priceUrl).not.toContain("swapFeeRecipient");
405
+ expect(priceUrl).not.toContain("swapFeeBps");
406
+ expect(priceUrl).not.toContain("swapFeeToken");
407
+ // Check quote API call
408
+ const quoteUrl = global.fetch.mock.calls[1][0];
409
+ expect(quoteUrl).not.toContain("swapFeeRecipient");
410
+ expect(quoteUrl).not.toContain("swapFeeBps");
411
+ expect(quoteUrl).not.toContain("swapFeeToken");
412
+ });
413
+ it("should include swap fee parameters with default swapFeeBps when only recipient provided", async () => {
414
+ const args = {
415
+ sellToken: MOCK_SELL_TOKEN,
416
+ buyToken: MOCK_BUY_TOKEN,
417
+ sellAmount: MOCK_SELL_AMOUNT,
418
+ slippageBps: 50,
419
+ swapFeeBps: 100,
420
+ swapFeeRecipient: "0xabcdef1234567890abcdef1234567890abcdef12",
421
+ };
422
+ await provider.executeSwap(mockWalletProvider, args);
423
+ // Verify both API calls include swap fee parameters with default swapFeeBps
424
+ expect(global.fetch).toHaveBeenCalledTimes(2);
425
+ // Check price API call
426
+ const priceUrl = global.fetch.mock.calls[0][0];
427
+ expect(priceUrl).toContain("swapFeeRecipient=0xabcdef1234567890abcdef1234567890abcdef12");
428
+ expect(priceUrl).toContain("swapFeeBps=100"); // Default value
429
+ expect(priceUrl).toContain(`swapFeeToken=${MOCK_SELL_TOKEN}`);
430
+ // Check quote API call
431
+ const quoteUrl = global.fetch.mock.calls[1][0];
432
+ expect(quoteUrl).toContain("swapFeeRecipient=0xabcdef1234567890abcdef1234567890abcdef12");
433
+ expect(quoteUrl).toContain("swapFeeBps=100"); // Default value
434
+ expect(quoteUrl).toContain(`swapFeeToken=${MOCK_SELL_TOKEN}`);
435
+ });
436
+ });
437
+ describe("supportsNetwork", () => {
438
+ it("should return true for evm networks", () => {
439
+ expect(provider.supportsNetwork({ protocolFamily: "evm" })).toBe(true);
440
+ });
441
+ it("should return false for non-evm networks", () => {
442
+ expect(provider.supportsNetwork({ protocolFamily: "solana" })).toBe(false);
443
+ });
444
+ });
445
+ });
@@ -1,8 +1,12 @@
1
1
  import { CdpClient } from "@coinbase/cdp-sdk";
2
- import { Abi, Address, ContractFunctionArgs, ContractFunctionName, Hex, ReadContractParameters, ReadContractReturnType, TransactionRequest } from "viem";
2
+ import { Abi, Address, ContractFunctionArgs, ContractFunctionName, Hex, PublicClient, ReadContractParameters, ReadContractReturnType, TransactionRequest } from "viem";
3
3
  import { Network } from "../network";
4
4
  import { EvmWalletProvider } from "./evmWalletProvider";
5
5
  import { WalletProviderWithClient, CdpWalletProviderConfig } from "./cdpShared";
6
+ /**
7
+ * Supported network types for CDP SDK EVM transactions
8
+ */
9
+ type CdpEvmNetwork = "base" | "base-sepolia" | "ethereum" | "ethereum-sepolia" | "polygon" | "arbitrum" | "optimism";
6
10
  /**
7
11
  * A wallet provider that uses the Coinbase SDK.
8
12
  */
@@ -83,6 +87,12 @@ export declare class CdpEvmWalletProvider extends EvmWalletProvider implements W
83
87
  * @returns The CDP client.
84
88
  */
85
89
  getClient(): CdpClient;
90
+ /**
91
+ * Gets the Viem PublicClient used for read-only operations.
92
+ *
93
+ * @returns The Viem PublicClient instance used for read-only operations.
94
+ */
95
+ getPublicClient(): PublicClient;
86
96
  /**
87
97
  * Gets the balance of the wallet.
88
98
  *
@@ -107,8 +117,16 @@ export declare class CdpEvmWalletProvider extends EvmWalletProvider implements W
107
117
  * Transfer the native asset of the network.
108
118
  *
109
119
  * @param to - The destination address.
110
- * @param value - The amount to transfer in Wei.
120
+ * @param value - The amount to transfer in atomic units (Wei).
111
121
  * @returns The transaction hash.
112
122
  */
113
123
  nativeTransfer(to: Address, value: string): Promise<Hex>;
124
+ /**
125
+ * Converts the internal network ID to the format expected by the CDP SDK.
126
+ *
127
+ * @returns The network ID in CDP SDK format
128
+ * @throws Error if the network is not supported
129
+ */
130
+ getCdpSdkNetwork(): CdpEvmNetwork;
114
131
  }
132
+ export {};
@@ -10,7 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
11
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
12
  };
13
- var _CdpEvmWalletProvider_instances, _CdpEvmWalletProvider_publicClient, _CdpEvmWalletProvider_serverAccount, _CdpEvmWalletProvider_cdp, _CdpEvmWalletProvider_network, _CdpEvmWalletProvider_getCdpSdkNetwork;
13
+ var _CdpEvmWalletProvider_publicClient, _CdpEvmWalletProvider_serverAccount, _CdpEvmWalletProvider_cdp, _CdpEvmWalletProvider_network;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.CdpEvmWalletProvider = void 0;
16
16
  const cdp_sdk_1 = require("@coinbase/cdp-sdk");
@@ -28,7 +28,6 @@ class CdpEvmWalletProvider extends evmWalletProvider_1.EvmWalletProvider {
28
28
  */
29
29
  constructor(config) {
30
30
  super();
31
- _CdpEvmWalletProvider_instances.add(this);
32
31
  _CdpEvmWalletProvider_publicClient.set(this, void 0);
33
32
  _CdpEvmWalletProvider_serverAccount.set(this, void 0);
34
33
  _CdpEvmWalletProvider_cdp.set(this, void 0);
@@ -67,9 +66,10 @@ class CdpEvmWalletProvider extends evmWalletProvider_1.EvmWalletProvider {
67
66
  const serverAccount = await (config.address
68
67
  ? cdpClient.evm.getAccount({ address: config.address })
69
68
  : cdpClient.evm.createAccount({ idempotencyKey }));
69
+ const rpcUrl = config.rpcUrl || process.env.RPC_URL;
70
70
  const publicClient = (0, viem_1.createPublicClient)({
71
71
  chain: network_1.NETWORK_ID_TO_VIEM_CHAIN[networkId],
72
- transport: (0, viem_1.http)(),
72
+ transport: rpcUrl ? (0, viem_1.http)(rpcUrl) : (0, viem_1.http)(),
73
73
  });
74
74
  return new CdpEvmWalletProvider({
75
75
  publicClient,
@@ -152,7 +152,7 @@ class CdpEvmWalletProvider extends evmWalletProvider_1.EvmWalletProvider {
152
152
  const result = await __classPrivateFieldGet(this, _CdpEvmWalletProvider_cdp, "f").evm.sendTransaction({
153
153
  address: __classPrivateFieldGet(this, _CdpEvmWalletProvider_serverAccount, "f").address,
154
154
  transaction: (0, viem_1.serializeTransaction)(txWithGasParams),
155
- network: __classPrivateFieldGet(this, _CdpEvmWalletProvider_instances, "m", _CdpEvmWalletProvider_getCdpSdkNetwork).call(this),
155
+ network: this.getCdpSdkNetwork(),
156
156
  });
157
157
  return result.transactionHash;
158
158
  }
@@ -188,6 +188,14 @@ class CdpEvmWalletProvider extends evmWalletProvider_1.EvmWalletProvider {
188
188
  getClient() {
189
189
  return __classPrivateFieldGet(this, _CdpEvmWalletProvider_cdp, "f");
190
190
  }
191
+ /**
192
+ * Gets the Viem PublicClient used for read-only operations.
193
+ *
194
+ * @returns The Viem PublicClient instance used for read-only operations.
195
+ */
196
+ getPublicClient() {
197
+ return __classPrivateFieldGet(this, _CdpEvmWalletProvider_publicClient, "f");
198
+ }
191
199
  /**
192
200
  * Gets the balance of the wallet.
193
201
  *
@@ -219,7 +227,7 @@ class CdpEvmWalletProvider extends evmWalletProvider_1.EvmWalletProvider {
219
227
  * Transfer the native asset of the network.
220
228
  *
221
229
  * @param to - The destination address.
222
- * @param value - The amount to transfer in Wei.
230
+ * @param value - The amount to transfer in atomic units (Wei).
223
231
  * @returns The transaction hash.
224
232
  */
225
233
  async nativeTransfer(to, value) {
@@ -229,15 +237,32 @@ class CdpEvmWalletProvider extends evmWalletProvider_1.EvmWalletProvider {
229
237
  data: "0x",
230
238
  });
231
239
  }
240
+ /**
241
+ * Converts the internal network ID to the format expected by the CDP SDK.
242
+ *
243
+ * @returns The network ID in CDP SDK format
244
+ * @throws Error if the network is not supported
245
+ */
246
+ getCdpSdkNetwork() {
247
+ switch (__classPrivateFieldGet(this, _CdpEvmWalletProvider_network, "f").networkId) {
248
+ case "base-sepolia":
249
+ return "base-sepolia";
250
+ case "base-mainnet":
251
+ return "base";
252
+ case "ethereum-mainnet":
253
+ return "ethereum";
254
+ case "ethereum-sepolia":
255
+ return "ethereum-sepolia";
256
+ case "polygon-mainnet":
257
+ return "polygon";
258
+ case "arbitrum-mainnet":
259
+ return "arbitrum";
260
+ case "optimism-mainnet":
261
+ return "optimism";
262
+ default:
263
+ throw new Error(`Unsupported network for CDP SDK: ${__classPrivateFieldGet(this, _CdpEvmWalletProvider_network, "f").networkId}`);
264
+ }
265
+ }
232
266
  }
233
267
  exports.CdpEvmWalletProvider = CdpEvmWalletProvider;
234
- _CdpEvmWalletProvider_publicClient = new WeakMap(), _CdpEvmWalletProvider_serverAccount = new WeakMap(), _CdpEvmWalletProvider_cdp = new WeakMap(), _CdpEvmWalletProvider_network = new WeakMap(), _CdpEvmWalletProvider_instances = new WeakSet(), _CdpEvmWalletProvider_getCdpSdkNetwork = function _CdpEvmWalletProvider_getCdpSdkNetwork() {
235
- switch (__classPrivateFieldGet(this, _CdpEvmWalletProvider_network, "f").networkId) {
236
- case "base-sepolia":
237
- return "base-sepolia";
238
- case "base-mainnet":
239
- return "base";
240
- default:
241
- throw new Error(`Unsupported network: ${__classPrivateFieldGet(this, _CdpEvmWalletProvider_network, "f").networkId}`);
242
- }
243
- };
268
+ _CdpEvmWalletProvider_publicClient = new WeakMap(), _CdpEvmWalletProvider_serverAccount = new WeakMap(), _CdpEvmWalletProvider_cdp = new WeakMap(), _CdpEvmWalletProvider_network = new WeakMap();
@@ -30,6 +30,11 @@ export interface CdpWalletProviderConfig extends CdpProviderConfig {
30
30
  * The idempotency key of the wallet. Only used when creating a new account.
31
31
  */
32
32
  idempotencyKey?: string;
33
+ /**
34
+ * Optional RPC URL for Viem public client HTTP transport.
35
+ * Falls back to process.env.RPC_URL when not provided.
36
+ */
37
+ rpcUrl?: string;
33
38
  }
34
39
  export interface CdpSmartWalletProviderConfig extends CdpWalletProviderConfig {
35
40
  /**
@@ -1,14 +1,19 @@
1
- import { CdpClient, EvmSmartAccount } from "@coinbase/cdp-sdk";
2
- import { Abi, Address, ContractFunctionArgs, ContractFunctionName, Hex, ReadContractParameters, ReadContractReturnType, TransactionRequest } from "viem";
1
+ import { CdpClient, EvmSmartAccount, EvmServerAccount } from "@coinbase/cdp-sdk";
2
+ import { Abi, Address, ContractFunctionArgs, ContractFunctionName, Hex, PublicClient, ReadContractParameters, ReadContractReturnType, TransactionRequest, LocalAccount } from "viem";
3
3
  import { Network } from "../network";
4
4
  import { EvmWalletProvider } from "./evmWalletProvider";
5
5
  import { WalletProviderWithClient, CdpSmartWalletProviderConfig } from "./cdpShared";
6
+ /**
7
+ * Supported network types for CDP SDK smart wallet operations
8
+ */
9
+ type CdpSmartWalletNetwork = "base" | "base-sepolia" | "ethereum" | "ethereum-sepolia" | "polygon" | "arbitrum" | "optimism";
6
10
  /**
7
11
  * A wallet provider that uses the Coinbase CDP SDK smart wallets.
8
12
  */
9
13
  export declare class CdpSmartWalletProvider extends EvmWalletProvider implements WalletProviderWithClient {
10
14
  #private;
11
15
  smartAccount: EvmSmartAccount;
16
+ ownerAccount: LocalAccount | EvmServerAccount;
12
17
  /**
13
18
  * Constructs a new CdpSmartWalletProvider.
14
19
  *
@@ -91,6 +96,12 @@ export declare class CdpSmartWalletProvider extends EvmWalletProvider implements
91
96
  * @returns The paymaster URL if configured, undefined otherwise.
92
97
  */
93
98
  getPaymasterUrl(): string | undefined;
99
+ /**
100
+ * Gets the Viem PublicClient used for read-only operations.
101
+ *
102
+ * @returns The Viem PublicClient instance used for read-only operations.
103
+ */
104
+ getPublicClient(): PublicClient;
94
105
  /**
95
106
  * Gets the balance of the smart wallet.
96
107
  *
@@ -115,8 +126,16 @@ export declare class CdpSmartWalletProvider extends EvmWalletProvider implements
115
126
  * Transfer the native asset of the network using smart wallet.
116
127
  *
117
128
  * @param to - The destination address.
118
- * @param value - The amount to transfer in Wei.
129
+ * @param value - The amount to transfer in atomic units (Wei).
119
130
  * @returns The user operation hash.
120
131
  */
121
132
  nativeTransfer(to: Address, value: string): Promise<Hex>;
133
+ /**
134
+ * Converts the internal network ID to the format expected by the CDP SDK.
135
+ *
136
+ * @returns The network ID in CDP SDK format
137
+ * @throws Error if the network is not supported
138
+ */
139
+ getCdpSdkNetwork(): CdpSmartWalletNetwork;
122
140
  }
141
+ export {};