@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.
- package/README.md +89 -10
- package/dist/action-providers/across/acrossActionProvider.js +2 -4
- package/dist/action-providers/across/acrossActionProvider.test.js +10 -5
- package/dist/action-providers/baseAccount/baseAccountActionProvider.js +5 -7
- package/dist/action-providers/cdp/cdpApiActionProvider.js +7 -30
- package/dist/action-providers/cdp/cdpApiActionProvider.test.js +2 -8
- package/dist/action-providers/cdp/faucetUtils.d.ts +38 -0
- package/dist/action-providers/cdp/faucetUtils.js +81 -0
- package/dist/action-providers/clanker/schemas.d.ts +4 -4
- package/dist/action-providers/clanker/utils.d.ts +2 -1
- package/dist/action-providers/clanker/utils.js +2 -2
- package/dist/action-providers/enso/constants.d.ts +4 -0
- package/dist/action-providers/enso/constants.js +10 -0
- package/dist/action-providers/enso/ensoActionProvider.d.ts +34 -0
- package/dist/action-providers/enso/ensoActionProvider.js +125 -0
- package/dist/action-providers/enso/ensoActionProvider.test.d.ts +1 -0
- package/dist/action-providers/enso/ensoActionProvider.test.js +141 -0
- package/dist/action-providers/enso/index.d.ts +1 -0
- package/dist/action-providers/enso/index.js +17 -0
- package/dist/action-providers/enso/schemas.d.ts +23 -0
- package/dist/action-providers/enso/schemas.js +22 -0
- package/dist/action-providers/erc20/constants.d.ts +2 -0
- package/dist/action-providers/erc20/constants.js +2 -0
- package/dist/action-providers/erc20/erc20ActionProvider.d.ts +17 -1
- package/dist/action-providers/erc20/erc20ActionProvider.js +103 -1
- package/dist/action-providers/erc20/erc20ActionProvider.test.js +201 -0
- package/dist/action-providers/erc20/schemas.d.ts +29 -0
- package/dist/action-providers/erc20/schemas.js +34 -1
- package/dist/action-providers/index.d.ts +4 -1
- package/dist/action-providers/index.js +4 -1
- package/dist/action-providers/jupiter/jupiterActionProvider.js +2 -2
- package/dist/action-providers/spl/splActionProvider.js +12 -13
- package/dist/action-providers/superfluid/graphQueries/superfluidGraphQueries.js +2 -2
- package/dist/action-providers/sushi/constants.d.ts +35 -0
- package/dist/action-providers/sushi/constants.js +7 -0
- package/dist/action-providers/sushi/index.d.ts +4 -0
- package/dist/action-providers/sushi/index.js +20 -0
- package/dist/action-providers/sushi/sushiDataActionProvider.d.ts +32 -0
- package/dist/action-providers/sushi/sushiDataActionProvider.js +113 -0
- package/dist/action-providers/sushi/sushiDataSchemas.d.ts +11 -0
- package/dist/action-providers/sushi/sushiDataSchemas.js +16 -0
- package/dist/action-providers/sushi/sushiRouterActionProvider.d.ts +40 -0
- package/dist/action-providers/sushi/sushiRouterActionProvider.js +386 -0
- package/dist/action-providers/sushi/sushiRouterActionProvider.test.d.ts +1 -0
- package/dist/action-providers/sushi/sushiRouterActionProvider.test.js +392 -0
- package/dist/action-providers/sushi/sushiRouterSchemas.d.ts +36 -0
- package/dist/action-providers/sushi/sushiRouterSchemas.js +55 -0
- package/dist/action-providers/vaultsfyi/constants.d.ts +8 -12
- package/dist/action-providers/vaultsfyi/constants.js +47 -13
- package/dist/action-providers/vaultsfyi/schemas.d.ts +120 -65
- package/dist/action-providers/vaultsfyi/schemas.js +72 -38
- package/dist/action-providers/vaultsfyi/sdk.d.ts +8 -0
- package/dist/action-providers/vaultsfyi/sdk.js +15 -0
- package/dist/action-providers/vaultsfyi/utils.d.ts +151 -55
- package/dist/action-providers/vaultsfyi/utils.js +29 -75
- package/dist/action-providers/vaultsfyi/vaultsfyiActionProvider.d.ts +55 -16
- package/dist/action-providers/vaultsfyi/vaultsfyiActionProvider.js +413 -217
- package/dist/action-providers/vaultsfyi/vaultsfyiActionProvider.test.js +509 -316
- package/dist/action-providers/wallet/walletActionProvider.js +1 -1
- package/dist/action-providers/weth/constants.d.ts +0 -1
- package/dist/action-providers/weth/constants.js +1 -2
- package/dist/action-providers/weth/schemas.js +6 -2
- package/dist/action-providers/weth/wethActionProvider.d.ts +7 -0
- package/dist/action-providers/weth/wethActionProvider.js +57 -32
- package/dist/action-providers/weth/wethActionProvider.test.js +60 -11
- package/dist/action-providers/x402/constants.d.ts +67 -0
- package/dist/action-providers/x402/constants.js +37 -0
- package/dist/action-providers/x402/schemas.d.ts +45 -5
- package/dist/action-providers/x402/schemas.js +81 -11
- package/dist/action-providers/x402/utils.d.ts +89 -14
- package/dist/action-providers/x402/utils.js +335 -31
- package/dist/action-providers/x402/x402ActionProvider.d.ts +21 -7
- package/dist/action-providers/x402/x402ActionProvider.js +250 -184
- package/dist/action-providers/x402/x402ActionProvider.test.js +240 -236
- package/dist/action-providers/yelay/constants.d.ts +64 -0
- package/dist/action-providers/yelay/constants.js +137 -0
- package/dist/action-providers/yelay/index.d.ts +2 -0
- package/dist/action-providers/yelay/index.js +18 -0
- package/dist/action-providers/yelay/schemas.d.ts +47 -0
- package/dist/action-providers/yelay/schemas.js +59 -0
- package/dist/action-providers/yelay/types.d.ts +24 -0
- package/dist/action-providers/yelay/yelayActionProvider.d.ts +70 -0
- package/dist/action-providers/yelay/yelayActionProvider.js +329 -0
- package/dist/action-providers/yelay/yelayActionProvider.test.d.ts +1 -0
- package/dist/action-providers/yelay/yelayActionProvider.test.js +302 -0
- package/dist/action-providers/zora/zoraActionProvider.js +4 -5
- package/dist/wallet-providers/cdpSmartWalletProvider.js +1 -3
- package/dist/wallet-providers/cdpSolanaWalletProvider.d.ts +14 -0
- package/dist/wallet-providers/cdpSolanaWalletProvider.js +39 -3
- package/dist/wallet-providers/cdpSolanaWalletProvider.test.js +16 -0
- package/dist/wallet-providers/privySvmWalletProvider.d.ts +14 -0
- package/dist/wallet-providers/privySvmWalletProvider.js +17 -0
- package/dist/wallet-providers/privySvmWalletProvider.test.js +10 -0
- package/dist/wallet-providers/solanaKeypairWalletProvider.d.ts +14 -0
- package/dist/wallet-providers/solanaKeypairWalletProvider.js +17 -0
- package/dist/wallet-providers/svmWalletProvider.d.ts +34 -0
- package/dist/wallet-providers/svmWalletProvider.js +43 -0
- package/dist/wallet-providers/svmWalletProvider.test.js +10 -0
- package/package.json +11 -6
- package/dist/action-providers/vaultsfyi/api/actions.d.ts +0 -41
- package/dist/action-providers/vaultsfyi/api/actions.js +0 -28
- package/dist/action-providers/vaultsfyi/api/historicalData.d.ts +0 -31
- package/dist/action-providers/vaultsfyi/api/historicalData.js +0 -44
- package/dist/action-providers/vaultsfyi/api/types.d.ts +0 -34
- package/dist/action-providers/vaultsfyi/api/vaults.d.ts +0 -66
- package/dist/action-providers/vaultsfyi/api/vaults.js +0 -57
- /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
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
91
|
-
const
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
jest.
|
|
99
|
-
jest.
|
|
100
|
-
jest.
|
|
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
|
-
|
|
104
|
-
|
|
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
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
|
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
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
|
171
|
-
const network = { protocolFamily: "
|
|
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
|
-
|
|
190
|
+
mockFetch.mockResolvedValue(createMockResponse({
|
|
178
191
|
status: 200,
|
|
179
192
|
data: { message: "Success" },
|
|
180
|
-
headers: {},
|
|
181
|
-
|
|
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
|
-
|
|
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
|
|
196
|
-
headers: {},
|
|
197
|
-
|
|
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.
|
|
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
|
|
210
|
-
error
|
|
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).
|
|
230
|
+
expect(parsedResult.message).toBeDefined();
|
|
220
231
|
});
|
|
221
232
|
});
|
|
222
|
-
describe("
|
|
233
|
+
describe("discoverX402Services", () => {
|
|
223
234
|
it("should list services without filters", async () => {
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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.
|
|
271
|
+
expect(parsed.services.length).toBe(1);
|
|
250
272
|
});
|
|
251
|
-
it("should filter services by
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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(
|
|
308
|
-
expect(parsed.
|
|
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
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
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("
|
|
338
|
+
describe("retryWithX402", () => {
|
|
320
339
|
it("should successfully retry with payment", async () => {
|
|
321
|
-
|
|
322
|
-
|
|
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
|
-
"
|
|
347
|
+
"content-type": "application/json",
|
|
348
|
+
"x-payment-response": encodedPaymentProof,
|
|
328
349
|
},
|
|
329
|
-
|
|
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
|
-
|
|
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
|
|
353
|
-
|
|
354
|
-
error
|
|
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
|
-
|
|
374
|
-
|
|
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
|
-
"
|
|
392
|
+
"content-type": "application/json",
|
|
393
|
+
"x-payment-response": encodedPaymentProof,
|
|
380
394
|
},
|
|
381
|
-
|
|
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(
|
|
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
|
-
|
|
407
|
+
mockFetchWithPayment.mockResolvedValue(createMockResponse({
|
|
399
408
|
status: 200,
|
|
400
|
-
statusText: "OK",
|
|
401
409
|
data: { message: "Free content" },
|
|
402
|
-
headers: {},
|
|
403
|
-
|
|
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
|
|
416
|
-
error
|
|
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
|
});
|