@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
@@ -32,124 +32,133 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
35
  Object.defineProperty(exports, "__esModule", { value: true });
39
36
  const x402ActionProvider_1 = require("./x402ActionProvider");
40
- const axios_1 = __importDefault(require("axios"));
41
- const x402axios = __importStar(require("x402-axios"));
42
- const x402Verify = __importStar(require("x402/verify"));
43
- // Mock external facilitator dependency
44
- jest.mock("@coinbase/x402", () => ({
45
- facilitator: {},
37
+ const wallet_providers_1 = require("../../wallet-providers");
38
+ const fetch_1 = require("@x402/fetch");
39
+ const client_1 = require("@x402/evm/exact/client");
40
+ const client_2 = require("@x402/svm/exact/client");
41
+ const utils = __importStar(require("./utils"));
42
+ const schemas_1 = require("./schemas");
43
+ // Mock external modules
44
+ jest.mock("@x402/fetch");
45
+ jest.mock("@x402/evm/exact/client");
46
+ jest.mock("@x402/svm/exact/client");
47
+ jest.mock("./utils");
48
+ jest.mock("./schemas", () => ({
49
+ ...jest.requireActual("./schemas"),
50
+ resolveFacilitatorUrl: jest.fn(),
46
51
  }));
47
- // Mock modules
48
- jest.mock("axios");
49
- jest.mock("x402-axios");
50
- jest.mock("x402/verify");
51
52
  // Create mock functions
52
- const mockRequest = jest.fn();
53
- // Create a complete mock axios instance
54
- const mockAxiosInstance = {
55
- request: mockRequest,
56
- get: jest.fn(),
57
- delete: jest.fn(),
58
- head: jest.fn(),
59
- options: jest.fn(),
60
- post: jest.fn(),
61
- put: jest.fn(),
62
- patch: jest.fn(),
63
- getUri: jest.fn(),
64
- defaults: {},
65
- interceptors: {
66
- request: { use: jest.fn(), eject: jest.fn(), clear: jest.fn() },
67
- response: { use: jest.fn(), eject: jest.fn(), clear: jest.fn() },
68
- },
69
- };
70
- // Create a complete mock axios static
71
- const mockAxios = {
72
- create: jest.fn().mockReturnValue(mockAxiosInstance),
73
- request: mockRequest,
74
- get: jest.fn(),
75
- delete: jest.fn(),
76
- head: jest.fn(),
77
- options: jest.fn(),
78
- post: jest.fn(),
79
- put: jest.fn(),
80
- patch: jest.fn(),
81
- all: jest.fn(),
82
- spread: jest.fn(),
83
- isAxiosError: jest.fn(),
84
- isCancel: jest.fn(),
85
- CancelToken: {
86
- source: jest.fn(),
87
- },
88
- VERSION: "1.x",
53
+ const mockFetch = jest.fn();
54
+ const mockFetchWithPayment = jest.fn();
55
+ // Mock x402 client
56
+ const mockX402Client = {
57
+ registerScheme: jest.fn(),
89
58
  };
90
- const mockWithPaymentInterceptor = jest.fn().mockReturnValue(mockAxiosInstance);
91
- const mockDecodeXPaymentResponse = jest.fn();
92
- const mockUseFacilitator = jest.fn();
93
- // Override the mocked modules
94
- axios_1.default.create = mockAxios.create;
95
- axios_1.default.request = mockRequest;
96
- axios_1.default.isAxiosError = mockAxios.isAxiosError;
97
- // Mock x402-axios functions
98
- jest.mocked(x402axios.withPaymentInterceptor).mockImplementation(mockWithPaymentInterceptor);
99
- jest.mocked(x402axios.decodeXPaymentResponse).mockImplementation(mockDecodeXPaymentResponse);
100
- jest.mocked(x402Verify.useFacilitator).mockImplementation(mockUseFacilitator);
59
+ // Mock utils functions
60
+ const mockGetX402Networks = jest.fn();
61
+ const mockHandleHttpError = jest.fn();
62
+ const mockFormatPaymentOption = jest.fn();
63
+ const mockFetchAllDiscoveryResources = jest.fn();
64
+ const mockFilterByNetwork = jest.fn();
65
+ const mockFilterByDescription = jest.fn();
66
+ const mockFilterByX402Version = jest.fn();
67
+ const mockFilterByKeyword = jest.fn();
68
+ const mockFilterByMaxPrice = jest.fn();
69
+ const mockFormatSimplifiedResources = jest.fn();
70
+ const mockBuildUrlWithParams = jest.fn();
71
+ const mockResolveFacilitatorUrl = jest.fn();
72
+ // Setup mocks
73
+ jest
74
+ .mocked(fetch_1.x402Client)
75
+ .mockImplementation(() => mockX402Client);
76
+ jest.mocked(fetch_1.wrapFetchWithPayment).mockReturnValue(mockFetchWithPayment);
77
+ jest
78
+ .mocked(client_1.registerExactEvmScheme)
79
+ .mockImplementation(() => mockX402Client);
80
+ jest
81
+ .mocked(client_2.registerExactSvmScheme)
82
+ .mockImplementation(() => mockX402Client);
83
+ jest.mocked(utils.getX402Networks).mockImplementation(mockGetX402Networks);
84
+ jest.mocked(utils.handleHttpError).mockImplementation(mockHandleHttpError);
85
+ jest.mocked(utils.formatPaymentOption).mockImplementation(mockFormatPaymentOption);
86
+ jest.mocked(utils.fetchAllDiscoveryResources).mockImplementation(mockFetchAllDiscoveryResources);
87
+ jest.mocked(utils.filterByNetwork).mockImplementation(mockFilterByNetwork);
88
+ jest.mocked(utils.filterByDescription).mockImplementation(mockFilterByDescription);
89
+ jest.mocked(utils.filterByX402Version).mockImplementation(mockFilterByX402Version);
90
+ jest.mocked(utils.filterByKeyword).mockImplementation(mockFilterByKeyword);
91
+ jest.mocked(utils.filterByMaxPrice).mockImplementation(mockFilterByMaxPrice);
92
+ jest.mocked(utils.formatSimplifiedResources).mockImplementation(mockFormatSimplifiedResources);
93
+ jest.mocked(utils.buildUrlWithParams).mockImplementation(mockBuildUrlWithParams);
94
+ jest.mocked(schemas_1.resolveFacilitatorUrl).mockImplementation(mockResolveFacilitatorUrl);
95
+ // Mock global fetch
96
+ global.fetch = mockFetch;
101
97
  // Mock wallet provider
102
- const makeMockWalletProvider = (networkId) => ({
103
- toSigner: jest.fn().mockReturnValue("mock-signer"),
104
- getNetwork: jest.fn().mockReturnValue({ protocolFamily: "evm", networkId }),
105
- });
98
+ const makeMockWalletProvider = (networkId) => {
99
+ const mockProvider = Object.create(wallet_providers_1.EvmWalletProvider.prototype);
100
+ mockProvider.toSigner = jest.fn().mockReturnValue("mock-signer");
101
+ mockProvider.getNetwork = jest.fn().mockReturnValue({ protocolFamily: "evm", networkId });
102
+ return mockProvider;
103
+ };
106
104
  // Sample responses based on real examples
107
105
  const MOCK_PAYMENT_INFO_RESPONSE = {
108
- paymentRequired: true,
109
- url: "https://www.x402.org/protected",
110
- status: 402,
111
- data: {
112
- x402Version: 1,
113
- error: "X-PAYMENT header is required",
114
- accepts: [
115
- {
116
- scheme: "exact",
117
- network: "base-sepolia",
118
- maxAmountRequired: "10000",
119
- resource: "https://www.x402.org/protected",
120
- description: "Access to protected content",
121
- mimeType: "application/json",
122
- payTo: "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
123
- maxTimeoutSeconds: 300,
124
- asset: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
125
- extra: {
126
- name: "USDC",
127
- version: "2",
128
- },
106
+ x402Version: 1,
107
+ error: "X-PAYMENT header is required",
108
+ accepts: [
109
+ {
110
+ scheme: "exact",
111
+ network: "base-sepolia",
112
+ maxAmountRequired: "10000",
113
+ resource: "https://www.x402.org/protected",
114
+ description: "Access to protected content",
115
+ mimeType: "application/json",
116
+ payTo: "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
117
+ maxTimeoutSeconds: 300,
118
+ asset: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
119
+ extra: {
120
+ name: "USDC",
121
+ version: "2",
129
122
  },
130
- ],
131
- },
123
+ },
124
+ ],
132
125
  };
133
- const MOCK_PAYMENT_RESPONSE = {
134
- success: true,
126
+ const MOCK_PAYMENT_PROOF = {
135
127
  transaction: "0xcbc385789d3744b52af5106c32809534f64adcbe097e050ec03d6b53fed5d305",
136
128
  network: "base-sepolia",
137
129
  payer: "0xa8c1a5D3C372C65c04f91f87a43F549619A9483f",
138
130
  };
131
+ // Helper to create mock Response
132
+ const createMockResponse = (options) => {
133
+ const headersMap = new Map(Object.entries(options.headers ?? {}));
134
+ return {
135
+ status: options.status,
136
+ statusText: options.statusText ?? "OK",
137
+ ok: options.status >= 200 && options.status < 300,
138
+ headers: {
139
+ get: (name) => headersMap.get(name.toLowerCase()) ?? null,
140
+ },
141
+ json: jest.fn().mockResolvedValue(options.data),
142
+ text: jest.fn().mockResolvedValue(JSON.stringify(options.data)),
143
+ };
144
+ };
139
145
  describe("X402ActionProvider", () => {
140
146
  let provider;
141
147
  beforeEach(() => {
142
148
  provider = new x402ActionProvider_1.X402ActionProvider();
143
149
  jest.clearAllMocks();
144
- // Setup mocks
145
- mockAxios.create.mockReturnValue(mockAxiosInstance);
146
- mockWithPaymentInterceptor.mockReturnValue(mockAxiosInstance);
147
- // Setup axios.isAxiosError mock
148
- jest
149
- .mocked(axios_1.default.isAxiosError)
150
- .mockImplementation((error) => Boolean(error &&
151
- typeof error === "object" &&
152
- ("isAxiosError" in error || "response" in error || "request" in error)));
150
+ // Setup default mock behaviors
151
+ mockGetX402Networks.mockImplementation(network => [network.networkId]);
152
+ mockBuildUrlWithParams.mockImplementation(url => url);
153
+ mockHandleHttpError.mockImplementation((error, url) => {
154
+ return JSON.stringify({
155
+ error: true,
156
+ message: error instanceof Error ? error.message : "Network error",
157
+ url: url,
158
+ });
159
+ });
160
+ mockFormatPaymentOption.mockResolvedValue("mocked payment option");
161
+ mockResolveFacilitatorUrl.mockReturnValue("https://api.cdp.coinbase.com/platform/v2/x402");
153
162
  });
154
163
  afterEach(() => {
155
164
  jest.clearAllMocks();
@@ -167,19 +176,22 @@ describe("X402ActionProvider", () => {
167
176
  const network = { protocolFamily: "evm", networkId: "ethereum" };
168
177
  expect(provider.supportsNetwork(network)).toBe(false);
169
178
  });
170
- it("should not support non-EVM networks", () => {
171
- const network = { protocolFamily: "solana", networkId: "mainnet" };
179
+ it("should support SVM networks", () => {
180
+ const network = { protocolFamily: "svm", networkId: "solana-mainnet" };
181
+ expect(provider.supportsNetwork(network)).toBe(true);
182
+ });
183
+ it("should not support non-EVM/SVM networks", () => {
184
+ const network = { protocolFamily: "bitcoin", networkId: "mainnet" };
172
185
  expect(provider.supportsNetwork(network)).toBe(false);
173
186
  });
174
187
  });
175
188
  describe("makeHttpRequest", () => {
176
189
  it("should handle successful non-payment requests", async () => {
177
- mockRequest.mockResolvedValue({
190
+ mockFetch.mockResolvedValue(createMockResponse({
178
191
  status: 200,
179
192
  data: { message: "Success" },
180
- headers: {},
181
- config: {},
182
- });
193
+ headers: { "content-type": "application/json" },
194
+ }));
183
195
  const result = await provider.makeHttpRequest(makeMockWalletProvider("base-sepolia"), {
184
196
  url: "https://api.example.com/free",
185
197
  method: "GET",
@@ -190,144 +202,152 @@ describe("X402ActionProvider", () => {
190
202
  expect(parsedResult.data).toEqual({ message: "Success" });
191
203
  });
192
204
  it("should handle 402 responses with payment options", async () => {
193
- mockRequest.mockResolvedValue({
205
+ mockGetX402Networks.mockReturnValue(["base-sepolia"]);
206
+ mockFormatPaymentOption.mockResolvedValue("10000 USDC on base-sepolia network");
207
+ mockFetch.mockResolvedValue(createMockResponse({
194
208
  status: 402,
195
- data: MOCK_PAYMENT_INFO_RESPONSE.data,
196
- headers: {},
197
- config: {},
198
- });
209
+ data: MOCK_PAYMENT_INFO_RESPONSE,
210
+ headers: { "content-type": "application/json" },
211
+ }));
199
212
  const result = await provider.makeHttpRequest(makeMockWalletProvider("base-sepolia"), {
200
213
  url: "https://www.x402.org/protected",
201
214
  method: "GET",
202
215
  });
203
216
  const parsedResult = JSON.parse(result);
204
217
  expect(parsedResult.status).toBe("error_402_payment_required");
205
- expect(parsedResult.acceptablePaymentOptions).toEqual(MOCK_PAYMENT_INFO_RESPONSE.data.accepts);
218
+ expect(parsedResult.acceptablePaymentOptions).toEqual(MOCK_PAYMENT_INFO_RESPONSE.accepts);
206
219
  expect(parsedResult.nextSteps).toBeDefined();
207
220
  });
208
221
  it("should handle network errors", async () => {
209
- const error = new Error("Network error");
210
- error.isAxiosError = true;
211
- error.request = {};
212
- mockRequest.mockRejectedValue(error);
222
+ const error = new TypeError("fetch failed");
223
+ mockFetch.mockRejectedValue(error);
213
224
  const result = await provider.makeHttpRequest(makeMockWalletProvider("base-sepolia"), {
214
225
  url: "https://api.example.com/endpoint",
215
226
  method: "GET",
216
227
  });
217
228
  const parsedResult = JSON.parse(result);
218
229
  expect(parsedResult.error).toBe(true);
219
- expect(parsedResult.message).toContain("Network error");
230
+ expect(parsedResult.message).toBeDefined();
220
231
  });
221
232
  });
222
- describe("listX402Services", () => {
233
+ describe("discoverX402Services", () => {
223
234
  it("should list services without filters", async () => {
224
- const mockList = jest.fn().mockResolvedValue({
225
- items: [
226
- {
227
- resource: "https://example.com/service1",
228
- metadata: { category: "test" },
229
- accepts: [
230
- {
231
- asset: "0xUSDC",
232
- maxAmountRequired: "90000",
233
- network: "base-sepolia",
234
- scheme: "exact",
235
- description: "Test service 1",
236
- outputSchema: { type: "object" },
237
- extra: { name: "USDC" },
238
- },
239
- ],
240
- },
241
- ],
235
+ const mockResources = [
236
+ {
237
+ resource: "https://example.com/service1",
238
+ x402Version: 1,
239
+ accepts: [
240
+ {
241
+ asset: "0xUSDC",
242
+ maxAmountRequired: "90000",
243
+ network: "base-sepolia",
244
+ scheme: "exact",
245
+ description: "Test service 1",
246
+ },
247
+ ],
248
+ },
249
+ ];
250
+ const mockSimplified = [
251
+ {
252
+ url: "https://example.com/service1",
253
+ price: "0.09 USDC on base-sepolia",
254
+ description: "Test service 1",
255
+ },
256
+ ];
257
+ mockFetchAllDiscoveryResources.mockResolvedValue(mockResources);
258
+ mockFilterByNetwork.mockReturnValue(mockResources);
259
+ mockFilterByDescription.mockReturnValue(mockResources);
260
+ mockFilterByX402Version.mockReturnValue(mockResources);
261
+ mockFormatSimplifiedResources.mockResolvedValue(mockSimplified);
262
+ mockGetX402Networks.mockReturnValue(["base-sepolia"]);
263
+ const result = await provider.discoverX402Services(makeMockWalletProvider("base-sepolia"), {
264
+ facilitator: "cdp",
265
+ x402Versions: [1, 2],
242
266
  });
243
- mockUseFacilitator.mockReturnValue({ list: mockList });
244
- const result = await provider.discoverX402Services(makeMockWalletProvider("base-sepolia"), {});
245
267
  const parsed = JSON.parse(result);
246
268
  expect(parsed.success).toBe(true);
247
269
  expect(parsed.total).toBe(1);
248
270
  expect(parsed.returned).toBe(1);
249
- expect(parsed.items.length).toBe(1);
271
+ expect(parsed.services.length).toBe(1);
250
272
  });
251
- it("should filter services by asset and maxPrice", async () => {
252
- const mockList = jest.fn().mockResolvedValue({
253
- items: [
254
- {
255
- resource: "https://example.com/service1",
256
- metadata: { category: "test" },
257
- accepts: [
258
- {
259
- asset: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", // Real USDC address for base-sepolia
260
- maxAmountRequired: "90000", // 0.09 USDC (should pass 0.1 filter)
261
- network: "base-sepolia",
262
- scheme: "exact",
263
- description: "Test service 1",
264
- outputSchema: { type: "object" },
265
- extra: { name: "USDC" },
266
- },
267
- ],
268
- },
269
- {
270
- resource: "https://example.com/service2",
271
- metadata: { category: "test" },
272
- accepts: [
273
- {
274
- asset: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", // Real USDC address for base-sepolia
275
- maxAmountRequired: "150000", // 0.15 USDC (should fail 0.1 filter)
276
- network: "base-sepolia",
277
- scheme: "exact",
278
- description: "Test service 2",
279
- outputSchema: { type: "object" },
280
- extra: { name: "USDC" },
281
- },
282
- ],
283
- },
284
- {
285
- resource: "https://example.com/service3",
286
- metadata: { category: "test" },
287
- accepts: [
288
- {
289
- asset: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", // Real USDC address for base-sepolia
290
- maxAmountRequired: "50000", // 0.05 USDC (should pass 0.1 filter)
291
- network: "base-sepolia",
292
- scheme: "exact",
293
- description: "Test service 3",
294
- outputSchema: { type: "object" },
295
- extra: { name: "USDC" },
296
- },
297
- ],
298
- },
299
- ],
300
- });
301
- mockUseFacilitator.mockReturnValue({ list: mockList });
273
+ it("should filter services by maxPrice", async () => {
274
+ const mockResources = [
275
+ {
276
+ resource: "https://example.com/service1",
277
+ x402Version: 1,
278
+ accepts: [
279
+ {
280
+ asset: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
281
+ maxAmountRequired: "90000",
282
+ network: "base-sepolia",
283
+ scheme: "exact",
284
+ description: "Test service 1",
285
+ },
286
+ ],
287
+ },
288
+ {
289
+ resource: "https://example.com/service2",
290
+ x402Version: 1,
291
+ accepts: [
292
+ {
293
+ asset: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
294
+ maxAmountRequired: "150000",
295
+ network: "base-sepolia",
296
+ scheme: "exact",
297
+ description: "Test service 2",
298
+ },
299
+ ],
300
+ },
301
+ ];
302
+ const filteredResources = [mockResources[0]];
303
+ const mockSimplified = [
304
+ {
305
+ url: "https://example.com/service1",
306
+ price: "0.09 USDC on base-sepolia",
307
+ description: "Test service 1",
308
+ },
309
+ ];
310
+ mockFetchAllDiscoveryResources.mockResolvedValue(mockResources);
311
+ mockFilterByNetwork.mockReturnValue(mockResources);
312
+ mockFilterByDescription.mockReturnValue(mockResources);
313
+ mockFilterByX402Version.mockReturnValue(mockResources);
314
+ mockFilterByMaxPrice.mockResolvedValue(filteredResources);
315
+ mockFormatSimplifiedResources.mockResolvedValue(mockSimplified);
316
+ mockGetX402Networks.mockReturnValue(["base-sepolia"]);
302
317
  const result = await provider.discoverX402Services(makeMockWalletProvider("base-sepolia"), {
318
+ facilitator: "cdp",
303
319
  maxUsdcPrice: 0.1,
320
+ x402Versions: [1, 2],
304
321
  });
305
322
  const parsed = JSON.parse(result);
306
323
  expect(parsed.success).toBe(true);
307
- expect(parsed.returned).toBe(2);
308
- expect(parsed.items.map(item => item.resource)).toEqual(expect.arrayContaining(["https://example.com/service1", "https://example.com/service3"]));
324
+ expect(parsed.returned).toBe(1);
325
+ expect(parsed.services[0].url).toBe("https://example.com/service1");
309
326
  });
310
- it("should handle errors from facilitator", async () => {
311
- const mockList = jest.fn().mockRejectedValue(new Error("boom"));
312
- mockUseFacilitator.mockReturnValue({ list: mockList });
313
- const result = await provider.discoverX402Services(makeMockWalletProvider("base-sepolia"), {});
327
+ it("should handle errors from discovery", async () => {
328
+ mockFetchAllDiscoveryResources.mockRejectedValue(new Error("boom"));
329
+ const result = await provider.discoverX402Services(makeMockWalletProvider("base-sepolia"), {
330
+ facilitator: "cdp",
331
+ x402Versions: [1, 2],
332
+ });
314
333
  const parsed = JSON.parse(result);
315
334
  expect(parsed.error).toBe(true);
316
335
  expect(parsed.message).toContain("Failed to list x402 services");
317
336
  });
318
337
  });
319
- describe("retryHttpRequestWithX402", () => {
338
+ describe("retryWithX402", () => {
320
339
  it("should successfully retry with payment", async () => {
321
- mockDecodeXPaymentResponse.mockReturnValue(MOCK_PAYMENT_RESPONSE);
322
- mockRequest.mockResolvedValue({
340
+ mockGetX402Networks.mockReturnValue(["base-sepolia"]);
341
+ // Encode the payment proof as base64
342
+ const encodedPaymentProof = btoa(JSON.stringify(MOCK_PAYMENT_PROOF));
343
+ mockFetchWithPayment.mockResolvedValue(createMockResponse({
323
344
  status: 200,
324
- statusText: "OK",
325
345
  data: { message: "Paid content" },
326
346
  headers: {
327
- "x-payment-response": "encoded-payment-data",
347
+ "content-type": "application/json",
348
+ "x-payment-response": encodedPaymentProof,
328
349
  },
329
- config: {},
330
- });
350
+ }));
331
351
  const result = await provider.retryWithX402(makeMockWalletProvider("base-sepolia"), {
332
352
  url: "https://www.x402.org/protected",
333
353
  method: "GET",
@@ -338,21 +358,15 @@ describe("X402ActionProvider", () => {
338
358
  asset: "0x456",
339
359
  },
340
360
  });
341
- // Update expectation to accept the payment selector function
342
- expect(mockWithPaymentInterceptor).toHaveBeenCalledWith(mockAxiosInstance, "mock-signer", expect.any(Function));
361
+ expect(fetch_1.wrapFetchWithPayment).toHaveBeenCalledWith(fetch, mockX402Client);
343
362
  const parsedResult = JSON.parse(result);
344
363
  expect(parsedResult.status).toBe("success");
345
- expect(parsedResult.details.paymentProof).toEqual({
346
- transaction: MOCK_PAYMENT_RESPONSE.transaction,
347
- network: MOCK_PAYMENT_RESPONSE.network,
348
- payer: MOCK_PAYMENT_RESPONSE.payer,
349
- });
364
+ expect(parsedResult.details.paymentProof).toEqual(MOCK_PAYMENT_PROOF);
350
365
  });
351
366
  it("should handle network errors during payment", async () => {
352
- const error = new Error("Network error");
353
- error.isAxiosError = true;
354
- error.request = {};
355
- mockRequest.mockRejectedValue(error);
367
+ const error = new TypeError("fetch failed");
368
+ mockGetX402Networks.mockReturnValue(["base-sepolia"]);
369
+ mockFetchWithPayment.mockRejectedValue(error);
356
370
  const result = await provider.retryWithX402(makeMockWalletProvider("base-sepolia"), {
357
371
  url: "https://www.x402.org/protected",
358
372
  method: "GET",
@@ -365,43 +379,36 @@ describe("X402ActionProvider", () => {
365
379
  });
366
380
  const parsedResult = JSON.parse(result);
367
381
  expect(parsedResult.error).toBe(true);
368
- expect(parsedResult.message).toContain("Network error");
369
382
  });
370
383
  });
371
384
  describe("makeHttpRequestWithX402", () => {
372
385
  it("should handle successful direct payment requests", async () => {
373
- mockDecodeXPaymentResponse.mockReturnValue(MOCK_PAYMENT_RESPONSE);
374
- mockRequest.mockResolvedValue({
386
+ // Encode the payment proof as base64
387
+ const encodedPaymentProof = btoa(JSON.stringify(MOCK_PAYMENT_PROOF));
388
+ mockFetchWithPayment.mockResolvedValue(createMockResponse({
375
389
  status: 200,
376
- statusText: "OK",
377
390
  data: { message: "Paid content" },
378
391
  headers: {
379
- "x-payment-response": "encoded-payment-data",
392
+ "content-type": "application/json",
393
+ "x-payment-response": encodedPaymentProof,
380
394
  },
381
- config: {},
382
- });
395
+ }));
383
396
  const result = await provider.makeHttpRequestWithX402(makeMockWalletProvider("base-sepolia"), {
384
397
  url: "https://www.x402.org/protected",
385
398
  method: "GET",
386
399
  });
387
- expect(mockWithPaymentInterceptor).toHaveBeenCalledWith(mockAxiosInstance, "mock-signer");
400
+ expect(fetch_1.wrapFetchWithPayment).toHaveBeenCalledWith(fetch, mockX402Client);
388
401
  const parsedResult = JSON.parse(result);
389
402
  expect(parsedResult.success).toBe(true);
390
403
  expect(parsedResult.data).toEqual({ message: "Paid content" });
391
- expect(parsedResult.paymentProof).toEqual({
392
- transaction: MOCK_PAYMENT_RESPONSE.transaction,
393
- network: MOCK_PAYMENT_RESPONSE.network,
394
- payer: MOCK_PAYMENT_RESPONSE.payer,
395
- });
404
+ expect(parsedResult.paymentProof).toEqual(MOCK_PAYMENT_PROOF);
396
405
  });
397
406
  it("should handle successful non-payment requests", async () => {
398
- mockRequest.mockResolvedValue({
407
+ mockFetchWithPayment.mockResolvedValue(createMockResponse({
399
408
  status: 200,
400
- statusText: "OK",
401
409
  data: { message: "Free content" },
402
- headers: {},
403
- config: {},
404
- });
410
+ headers: { "content-type": "application/json" },
411
+ }));
405
412
  const result = await provider.makeHttpRequestWithX402(makeMockWalletProvider("base-sepolia"), {
406
413
  url: "https://api.example.com/free",
407
414
  method: "GET",
@@ -412,17 +419,14 @@ describe("X402ActionProvider", () => {
412
419
  expect(parsedResult.paymentProof).toBeNull();
413
420
  });
414
421
  it("should handle network errors", async () => {
415
- const error = new Error("Network error");
416
- error.isAxiosError = true;
417
- error.request = {};
418
- mockRequest.mockRejectedValue(error);
422
+ const error = new TypeError("fetch failed");
423
+ mockFetchWithPayment.mockRejectedValue(error);
419
424
  const result = await provider.makeHttpRequestWithX402(makeMockWalletProvider("base-sepolia"), {
420
425
  url: "https://api.example.com/endpoint",
421
426
  method: "GET",
422
427
  });
423
428
  const parsedResult = JSON.parse(result);
424
429
  expect(parsedResult.error).toBe(true);
425
- expect(parsedResult.message).toContain("Network error");
426
430
  });
427
431
  });
428
432
  });