@coinbase/agentkit 0.10.0 → 0.10.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.
Files changed (169) hide show
  1. package/README.md +195 -23
  2. package/dist/action-providers/across/acrossActionProvider.js +3 -3
  3. package/dist/action-providers/across/schemas.d.ts +1 -1
  4. package/dist/action-providers/baseAccount/baseAccountActionProvider.d.ts +46 -0
  5. package/dist/action-providers/baseAccount/baseAccountActionProvider.js +404 -0
  6. package/dist/action-providers/baseAccount/baseAccountActionProvider.test.d.ts +1 -0
  7. package/dist/action-providers/baseAccount/baseAccountActionProvider.test.js +325 -0
  8. package/dist/action-providers/baseAccount/index.d.ts +2 -0
  9. package/dist/action-providers/baseAccount/index.js +18 -0
  10. package/dist/action-providers/baseAccount/schemas.d.ts +43 -0
  11. package/dist/action-providers/baseAccount/schemas.js +62 -0
  12. package/dist/action-providers/baseAccount/types.d.ts +17 -0
  13. package/dist/action-providers/baseAccount/types.js +2 -0
  14. package/dist/action-providers/baseAccount/utils.d.ts +14 -0
  15. package/dist/action-providers/baseAccount/utils.js +57 -0
  16. package/dist/action-providers/cdp/cdpApiActionProvider.d.ts +3 -12
  17. package/dist/action-providers/cdp/cdpApiActionProvider.js +2 -81
  18. package/dist/action-providers/cdp/cdpApiActionProvider.test.js +0 -125
  19. package/dist/action-providers/cdp/cdpEvmWalletActionProvider.d.ts +18 -3
  20. package/dist/action-providers/cdp/cdpEvmWalletActionProvider.js +224 -23
  21. package/dist/action-providers/cdp/cdpEvmWalletActionProvider.test.js +280 -0
  22. package/dist/action-providers/cdp/cdpSmartWalletActionProvider.d.ts +17 -2
  23. package/dist/action-providers/cdp/cdpSmartWalletActionProvider.js +224 -18
  24. package/dist/action-providers/cdp/cdpSmartWalletActionProvider.test.js +267 -1
  25. package/dist/action-providers/cdp/schemas.d.ts +12 -12
  26. package/dist/action-providers/cdp/schemas.js +17 -5
  27. package/dist/action-providers/cdp/swapUtils.d.ts +23 -0
  28. package/dist/action-providers/cdp/swapUtils.js +106 -0
  29. package/dist/action-providers/clanker/clankerActionProvider.d.ts +43 -0
  30. package/dist/action-providers/clanker/clankerActionProvider.js +130 -0
  31. package/dist/action-providers/clanker/clankerActionProvider.test.d.ts +4 -0
  32. package/dist/action-providers/clanker/clankerActionProvider.test.js +119 -0
  33. package/dist/action-providers/clanker/index.d.ts +2 -0
  34. package/dist/action-providers/clanker/index.js +18 -0
  35. package/dist/action-providers/clanker/schemas.d.ts +56 -0
  36. package/dist/action-providers/clanker/schemas.js +47 -0
  37. package/dist/action-providers/clanker/utils.d.ts +9 -0
  38. package/dist/action-providers/clanker/utils.js +23 -0
  39. package/dist/action-providers/compound/constants.d.ts +1 -1
  40. package/dist/action-providers/compound/constants.js +2 -2
  41. package/dist/action-providers/erc20/constants.d.ts +35 -135
  42. package/dist/action-providers/erc20/constants.js +37 -189
  43. package/dist/action-providers/erc20/erc20ActionProvider.d.ts +9 -1
  44. package/dist/action-providers/erc20/erc20ActionProvider.js +87 -35
  45. package/dist/action-providers/erc20/erc20ActionProvider.test.js +115 -52
  46. package/dist/action-providers/erc20/schemas.d.ts +25 -12
  47. package/dist/action-providers/erc20/schemas.js +34 -6
  48. package/dist/action-providers/erc20/utils.d.ts +19 -0
  49. package/dist/action-providers/erc20/utils.js +54 -0
  50. package/dist/action-providers/flaunch/client_utils.d.ts +25 -0
  51. package/dist/action-providers/flaunch/client_utils.js +62 -0
  52. package/dist/action-providers/flaunch/constants.d.ts +42 -21
  53. package/dist/action-providers/flaunch/constants.js +113 -38
  54. package/dist/action-providers/flaunch/flaunchActionProvider.d.ts +4 -43
  55. package/dist/action-providers/flaunch/flaunchActionProvider.js +133 -209
  56. package/dist/action-providers/flaunch/flaunchActionProvider.test.js +113 -13
  57. package/dist/action-providers/flaunch/metadata_utils.d.ts +12 -0
  58. package/dist/action-providers/flaunch/metadata_utils.js +216 -0
  59. package/dist/action-providers/flaunch/schemas.d.ts +39 -3
  60. package/dist/action-providers/flaunch/schemas.js +62 -10
  61. package/dist/action-providers/flaunch/{utils.d.ts → swap_utils.d.ts} +17 -19
  62. package/dist/action-providers/flaunch/{utils.js → swap_utils.js} +137 -172
  63. package/dist/action-providers/index.d.ts +4 -0
  64. package/dist/action-providers/index.js +4 -0
  65. package/dist/action-providers/jupiter/schemas.d.ts +1 -1
  66. package/dist/action-providers/moonwell/schemas.d.ts +2 -2
  67. package/dist/action-providers/morpho/morphoActionProvider.js +5 -5
  68. package/dist/action-providers/morpho/schemas.d.ts +2 -2
  69. package/dist/action-providers/pyth/pythActionProvider.d.ts +2 -2
  70. package/dist/action-providers/pyth/pythActionProvider.js +83 -26
  71. package/dist/action-providers/pyth/pythActionProvider.test.js +179 -23
  72. package/dist/action-providers/pyth/schemas.d.ts +6 -0
  73. package/dist/action-providers/pyth/schemas.js +9 -1
  74. package/dist/action-providers/superfluid/constants.d.ts +814 -0
  75. package/dist/action-providers/superfluid/constants.js +2826 -0
  76. package/dist/action-providers/superfluid/graphQueries/endpoints.d.ts +2 -0
  77. package/dist/action-providers/superfluid/graphQueries/endpoints.js +5 -0
  78. package/dist/action-providers/superfluid/graphQueries/queries.d.ts +1 -0
  79. package/dist/action-providers/superfluid/graphQueries/queries.js +35 -0
  80. package/dist/action-providers/superfluid/graphQueries/superfluidGraphQueries.d.ts +8 -0
  81. package/dist/action-providers/superfluid/graphQueries/superfluidGraphQueries.js +24 -0
  82. package/dist/action-providers/superfluid/graphQueries/types.d.ts +27 -0
  83. package/dist/action-providers/superfluid/graphQueries/types.js +2 -0
  84. package/dist/action-providers/superfluid/index.d.ts +7 -0
  85. package/dist/action-providers/superfluid/index.js +23 -0
  86. package/dist/action-providers/superfluid/schemas.d.ts +86 -0
  87. package/dist/action-providers/superfluid/schemas.js +103 -0
  88. package/dist/action-providers/superfluid/superfluidActionProvider.d.ts +20 -0
  89. package/dist/action-providers/superfluid/superfluidActionProvider.js +36 -0
  90. package/dist/action-providers/superfluid/superfluidPoolActionProvider.d.ts +46 -0
  91. package/dist/action-providers/superfluid/superfluidPoolActionProvider.js +143 -0
  92. package/dist/action-providers/superfluid/superfluidPoolActionProvider.test.d.ts +1 -0
  93. package/dist/action-providers/superfluid/superfluidPoolActionProvider.test.js +92 -0
  94. package/dist/action-providers/superfluid/superfluidQueryActionProvider.d.ts +27 -0
  95. package/dist/action-providers/superfluid/superfluidQueryActionProvider.js +71 -0
  96. package/dist/action-providers/superfluid/superfluidQueryActionProvider.test.d.ts +1 -0
  97. package/dist/action-providers/superfluid/superfluidQueryActionProvider.test.js +57 -0
  98. package/dist/action-providers/superfluid/superfluidStreamActionProvider.d.ts +56 -0
  99. package/dist/action-providers/superfluid/superfluidStreamActionProvider.js +191 -0
  100. package/dist/action-providers/superfluid/superfluidStreamActionProvider.test.d.ts +1 -0
  101. package/dist/action-providers/superfluid/superfluidStreamActionProvider.test.js +80 -0
  102. package/dist/action-providers/superfluid/superfluidSuperTokenCreatorActionProvider.d.ts +30 -0
  103. package/dist/action-providers/superfluid/superfluidSuperTokenCreatorActionProvider.js +109 -0
  104. package/dist/action-providers/superfluid/superfluidSuperTokenCreatorActionProvider.test.d.ts +1 -0
  105. package/dist/action-providers/superfluid/superfluidSuperTokenCreatorActionProvider.test.js +75 -0
  106. package/dist/action-providers/superfluid/superfluidWrapperActionProvider.d.ts +32 -0
  107. package/dist/action-providers/superfluid/superfluidWrapperActionProvider.js +101 -0
  108. package/dist/action-providers/superfluid/superfluidWrapperActionProvider.test.d.ts +1 -0
  109. package/dist/action-providers/superfluid/superfluidWrapperActionProvider.test.js +85 -0
  110. package/dist/action-providers/superfluid/utils/parseLogs.d.ts +19 -0
  111. package/dist/action-providers/superfluid/utils/parseLogs.js +81 -0
  112. package/dist/action-providers/truemarkets/truemarketsActionProvider.d.ts +4 -16
  113. package/dist/action-providers/truemarkets/truemarketsActionProvider.js +20 -41
  114. package/dist/action-providers/truemarkets/truemarketsActionProvider.test.js +11 -33
  115. package/dist/action-providers/wallet/walletActionProvider.js +24 -10
  116. package/dist/action-providers/wallet/walletActionProvider.test.js +6 -2
  117. package/dist/action-providers/x402/schemas.d.ts +7 -0
  118. package/dist/action-providers/x402/schemas.js +11 -1
  119. package/dist/action-providers/x402/utils.d.ts +55 -0
  120. package/dist/action-providers/x402/utils.js +160 -0
  121. package/dist/action-providers/x402/x402ActionProvider.d.ts +9 -9
  122. package/dist/action-providers/x402/x402ActionProvider.js +158 -39
  123. package/dist/action-providers/x402/x402ActionProvider.test.js +116 -10
  124. package/dist/action-providers/zeroX/index.d.ts +1 -0
  125. package/dist/action-providers/zeroX/index.js +17 -0
  126. package/dist/action-providers/zeroX/schemas.d.ts +51 -0
  127. package/dist/action-providers/zeroX/schemas.js +82 -0
  128. package/dist/action-providers/zeroX/utils.d.ts +23 -0
  129. package/dist/action-providers/zeroX/utils.js +106 -0
  130. package/dist/action-providers/zeroX/zeroXActionProvider.d.ts +57 -0
  131. package/dist/action-providers/zeroX/zeroXActionProvider.js +407 -0
  132. package/dist/action-providers/zeroX/zeroXActionProvider.test.d.ts +1 -0
  133. package/dist/action-providers/zeroX/zeroXActionProvider.test.js +445 -0
  134. package/dist/utils.d.ts +10 -0
  135. package/dist/utils.js +43 -13
  136. package/dist/wallet-providers/cdpEvmWalletProvider.d.ts +27 -2
  137. package/dist/wallet-providers/cdpEvmWalletProvider.js +54 -36
  138. package/dist/wallet-providers/cdpEvmWalletProvider.test.js +7 -0
  139. package/dist/wallet-providers/cdpShared.d.ts +5 -0
  140. package/dist/wallet-providers/cdpSmartWalletProvider.d.ts +29 -3
  141. package/dist/wallet-providers/cdpSmartWalletProvider.js +66 -25
  142. package/dist/wallet-providers/cdpSmartWalletProvider.test.js +6 -10
  143. package/dist/wallet-providers/cdpSolanaWalletProvider.d.ts +1 -1
  144. package/dist/wallet-providers/cdpSolanaWalletProvider.js +7 -7
  145. package/dist/wallet-providers/cdpSolanaWalletProvider.test.js +15 -12
  146. package/dist/wallet-providers/evmWalletProvider.d.ts +13 -2
  147. package/dist/wallet-providers/evmWalletProvider.js +4 -0
  148. package/dist/wallet-providers/legacyCdpSmartWalletProvider.d.ts +18 -2
  149. package/dist/wallet-providers/legacyCdpSmartWalletProvider.js +23 -2
  150. package/dist/wallet-providers/legacyCdpWalletProvider.d.ts +19 -2
  151. package/dist/wallet-providers/legacyCdpWalletProvider.js +27 -2
  152. package/dist/wallet-providers/legacyCdpWalletProvider.test.js +6 -0
  153. package/dist/wallet-providers/privyEvmDelegatedEmbeddedWalletProvider.d.ts +17 -2
  154. package/dist/wallet-providers/privyEvmDelegatedEmbeddedWalletProvider.js +39 -3
  155. package/dist/wallet-providers/privyEvmDelegatedEmbeddedWalletProvider.test.js +1 -1
  156. package/dist/wallet-providers/privyEvmWalletProvider.d.ts +2 -0
  157. package/dist/wallet-providers/privyEvmWalletProvider.js +2 -1
  158. package/dist/wallet-providers/privyEvmWalletProvider.test.js +12 -1
  159. package/dist/wallet-providers/solanaKeypairWalletProvider.d.ts +1 -1
  160. package/dist/wallet-providers/solanaKeypairWalletProvider.js +3 -4
  161. package/dist/wallet-providers/solanaKeypairWalletProvider.test.js +4 -2
  162. package/dist/wallet-providers/viemWalletProvider.d.ts +20 -3
  163. package/dist/wallet-providers/viemWalletProvider.js +33 -4
  164. package/dist/wallet-providers/viemWalletProvider.test.js +27 -6
  165. package/dist/wallet-providers/walletProvider.d.ts +1 -1
  166. package/dist/wallet-providers/zeroDevWalletProvider.d.ts +17 -2
  167. package/dist/wallet-providers/zeroDevWalletProvider.js +26 -5
  168. package/dist/wallet-providers/zeroDevWalletProvider.test.js +12 -2
  169. package/package.json +8 -4
@@ -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
+ });
package/dist/utils.d.ts CHANGED
@@ -20,3 +20,13 @@ export declare function approve(wallet: EvmWalletProvider, tokenAddress: string,
20
20
  * @returns The adjusted gas estimate as a bigint.
21
21
  */
22
22
  export declare function applyGasMultiplier(gas: bigint, multiplier: number): bigint;
23
+ /**
24
+ * Retry function with exponential backoff
25
+ *
26
+ * @param fn - The function to retry
27
+ * @param maxRetries - Maximum number of retries (default: 3)
28
+ * @param baseDelay - Base delay in milliseconds for retries (default: 1000)
29
+ * @param initialDelay - Initial delay before the first attempt in milliseconds (default: 0)
30
+ * @returns Promise that resolves with the function result or rejects with the last error
31
+ */
32
+ export declare function retryWithExponentialBackoff<T>(fn: () => Promise<T>, maxRetries?: number, baseDelay?: number, initialDelay?: number): Promise<T>;
package/dist/utils.js CHANGED
@@ -2,19 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.approve = approve;
4
4
  exports.applyGasMultiplier = applyGasMultiplier;
5
+ exports.retryWithExponentialBackoff = retryWithExponentialBackoff;
5
6
  const viem_1 = require("viem");
6
- const ERC20_ABI = [
7
- {
8
- inputs: [
9
- { name: "spender", type: "address" },
10
- { name: "amount", type: "uint256" },
11
- ],
12
- name: "approve",
13
- outputs: [{ name: "", type: "bool" }],
14
- stateMutability: "nonpayable",
15
- type: "function",
16
- },
17
- ];
7
+ const viem_2 = require("viem");
18
8
  /**
19
9
  * Approves a spender to spend tokens on behalf of the owner
20
10
  *
@@ -27,7 +17,7 @@ const ERC20_ABI = [
27
17
  async function approve(wallet, tokenAddress, spenderAddress, amount) {
28
18
  try {
29
19
  const data = (0, viem_1.encodeFunctionData)({
30
- abi: ERC20_ABI,
20
+ abi: viem_2.erc20Abi,
31
21
  functionName: "approve",
32
22
  args: [spenderAddress, amount],
33
23
  });
@@ -55,3 +45,43 @@ async function approve(wallet, tokenAddress, spenderAddress, amount) {
55
45
  function applyGasMultiplier(gas, multiplier) {
56
46
  return BigInt(Math.round(Number(gas) * multiplier));
57
47
  }
48
+ /**
49
+ * Utility function to sleep for a given number of milliseconds
50
+ *
51
+ * @param ms - Number of milliseconds to sleep
52
+ * @returns Promise that resolves after the specified delay
53
+ */
54
+ const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
55
+ /**
56
+ * Retry function with exponential backoff
57
+ *
58
+ * @param fn - The function to retry
59
+ * @param maxRetries - Maximum number of retries (default: 3)
60
+ * @param baseDelay - Base delay in milliseconds for retries (default: 1000)
61
+ * @param initialDelay - Initial delay before the first attempt in milliseconds (default: 0)
62
+ * @returns Promise that resolves with the function result or rejects with the last error
63
+ */
64
+ async function retryWithExponentialBackoff(fn, maxRetries = 3, baseDelay = 1000, initialDelay = 0) {
65
+ let lastError;
66
+ // Wait before the first attempt if initialDelay is specified
67
+ if (initialDelay > 0) {
68
+ await sleep(initialDelay);
69
+ }
70
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
71
+ try {
72
+ return await fn();
73
+ }
74
+ catch (error) {
75
+ lastError = error;
76
+ // If this was the last attempt, throw the error
77
+ if (attempt === maxRetries) {
78
+ throw lastError;
79
+ }
80
+ // Wait after failed attempt with exponential backoff
81
+ // Calculate delay with exponential backoff: baseDelay * 2^attempt
82
+ const delay = baseDelay * Math.pow(2, attempt);
83
+ await sleep(delay);
84
+ }
85
+ }
86
+ throw lastError;
87
+ }
@@ -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
  */
@@ -31,6 +35,13 @@ export declare class CdpEvmWalletProvider extends EvmWalletProvider implements W
31
35
  name: string | undefined;
32
36
  address: `0x${string}`;
33
37
  }>;
38
+ /**
39
+ * Signs a raw hash.
40
+ *
41
+ * @param hash - The hash to sign.
42
+ * @returns The signed hash.
43
+ */
44
+ sign(hash: `0x${string}`): Promise<Hex>;
34
45
  /**
35
46
  * Signs a message.
36
47
  *
@@ -83,6 +94,12 @@ export declare class CdpEvmWalletProvider extends EvmWalletProvider implements W
83
94
  * @returns The CDP client.
84
95
  */
85
96
  getClient(): CdpClient;
97
+ /**
98
+ * Gets the Viem PublicClient used for read-only operations.
99
+ *
100
+ * @returns The Viem PublicClient instance used for read-only operations.
101
+ */
102
+ getPublicClient(): PublicClient;
86
103
  /**
87
104
  * Gets the balance of the wallet.
88
105
  *
@@ -107,8 +124,16 @@ export declare class CdpEvmWalletProvider extends EvmWalletProvider implements W
107
124
  * Transfer the native asset of the network.
108
125
  *
109
126
  * @param to - The destination address.
110
- * @param value - The amount to transfer in Wei.
127
+ * @param value - The amount to transfer in atomic units (Wei).
111
128
  * @returns The transaction hash.
112
129
  */
113
130
  nativeTransfer(to: Address, value: string): Promise<Hex>;
131
+ /**
132
+ * Converts the internal network ID to the format expected by the CDP SDK.
133
+ *
134
+ * @returns The network ID in CDP SDK format
135
+ * @throws Error if the network is not supported
136
+ */
137
+ getCdpSdkNetwork(): CdpEvmNetwork;
114
138
  }
139
+ export {};