@bitflowlabs/core-sdk 2.3.2 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -36
- package/dist/src/helpers/callReadOnlyHelper.js +68 -52
- package/dist/src/helpers/callReadOnlyHelper.js.map +1 -1
- package/dist/src/helpers/convertValuesHelper.js +24 -4
- package/dist/src/helpers/convertValuesHelper.js.map +1 -1
- package/dist/src/helpers/handleResultHelper.js +10 -10
- package/dist/src/helpers/handleResultHelper.js.map +1 -1
- package/dist/src/helpers/newPostConditionsHelper.js +6 -1
- package/dist/src/helpers/newPostConditionsHelper.js.map +1 -1
- package/dist/src/helpers/postConditionsHelper.js +6 -1
- package/dist/src/helpers/postConditionsHelper.js.map +1 -1
- package/dist/test/BitflowSDK.test.d.ts +1 -0
- package/dist/test/BitflowSDK.test.js +1143 -0
- package/dist/test/BitflowSDK.test.js.map +1 -0
- package/dist/test/config.test.d.ts +1 -0
- package/dist/test/config.test.js +89 -0
- package/dist/test/config.test.js.map +1 -0
- package/dist/test/helpers/callGetSwapParams.test.d.ts +1 -0
- package/dist/test/helpers/callGetSwapParams.test.js +85 -0
- package/dist/test/helpers/callGetSwapParams.test.js.map +1 -0
- package/dist/test/helpers/callReadOnlyHelper.test.d.ts +1 -0
- package/dist/test/helpers/callReadOnlyHelper.test.js +345 -0
- package/dist/test/helpers/callReadOnlyHelper.test.js.map +1 -0
- package/dist/test/helpers/callSwapHelper.test.d.ts +1 -0
- package/dist/test/helpers/callSwapHelper.test.js +209 -0
- package/dist/test/helpers/callSwapHelper.test.js.map +1 -0
- package/dist/test/helpers/constructFunctionArgs.test.d.ts +1 -0
- package/dist/test/helpers/constructFunctionArgs.test.js +63 -0
- package/dist/test/helpers/constructFunctionArgs.test.js.map +1 -0
- package/dist/test/helpers/convertValuesHelper.test.d.ts +1 -0
- package/dist/test/helpers/convertValuesHelper.test.js +207 -0
- package/dist/test/helpers/convertValuesHelper.test.js.map +1 -0
- package/dist/test/helpers/fetchContractInterfaceHelper.test.d.ts +1 -0
- package/dist/test/helpers/fetchContractInterfaceHelper.test.js +70 -0
- package/dist/test/helpers/fetchContractInterfaceHelper.test.js.map +1 -0
- package/dist/test/helpers/fetchDataHelper.test.d.ts +1 -0
- package/dist/test/helpers/fetchDataHelper.test.js +162 -0
- package/dist/test/helpers/fetchDataHelper.test.js.map +1 -0
- package/dist/test/helpers/fetchPossibleSwap.test.d.ts +1 -0
- package/dist/test/helpers/fetchPossibleSwap.test.js +154 -0
- package/dist/test/helpers/fetchPossibleSwap.test.js.map +1 -0
- package/dist/test/helpers/getContractInterfaceAndFunction.test.d.ts +1 -0
- package/dist/test/helpers/getContractInterfaceAndFunction.test.js +25 -0
- package/dist/test/helpers/getContractInterfaceAndFunction.test.js.map +1 -0
- package/dist/test/helpers/getFunctionArgs.test.d.ts +1 -0
- package/dist/test/helpers/getFunctionArgs.test.js +25 -0
- package/dist/test/helpers/getFunctionArgs.test.js.map +1 -0
- package/dist/test/helpers/getTokenDecimalsHelper.test.d.ts +1 -0
- package/dist/test/helpers/getTokenDecimalsHelper.test.js +229 -0
- package/dist/test/helpers/getTokenDecimalsHelper.test.js.map +1 -0
- package/dist/test/helpers/getTokenNameHelper.test.d.ts +1 -0
- package/dist/test/helpers/getTokenNameHelper.test.js +258 -0
- package/dist/test/helpers/getTokenNameHelper.test.js.map +1 -0
- package/dist/test/helpers/handleResultHelper.test.d.ts +1 -0
- package/dist/test/helpers/handleResultHelper.test.js +72 -0
- package/dist/test/helpers/handleResultHelper.test.js.map +1 -0
- package/dist/test/helpers/newPostConditionsHelper.test.d.ts +1 -0
- package/dist/test/helpers/newPostConditionsHelper.test.js +348 -0
- package/dist/test/helpers/newPostConditionsHelper.test.js.map +1 -0
- package/dist/test/helpers/postConditionsHelper.test.d.ts +1 -0
- package/dist/test/helpers/postConditionsHelper.test.js +262 -0
- package/dist/test/helpers/postConditionsHelper.test.js.map +1 -0
- package/dist/test/keeper/keeperAPI.test.d.ts +1 -0
- package/dist/test/keeper/keeperAPI.test.js +283 -0
- package/dist/test/keeper/keeperAPI.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,1143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const BitflowSDK_1 = require("../src/BitflowSDK");
|
|
5
|
+
const config_1 = require("../src/config");
|
|
6
|
+
const callReadOnlyHelper = tslib_1.__importStar(require("../src/helpers/callReadOnlyHelper"));
|
|
7
|
+
const fetchDataHelper = tslib_1.__importStar(require("../src/helpers/fetchDataHelper"));
|
|
8
|
+
const fetchPossibleSwap = tslib_1.__importStar(require("../src/helpers/fetchPossibleSwap"));
|
|
9
|
+
const getContractInterfaceAndFunctionHelper = tslib_1.__importStar(require("../src/helpers/getContractInterfaceAndFunction"));
|
|
10
|
+
const types_1 = require("../src/keeper/types");
|
|
11
|
+
const callSwapHelper = tslib_1.__importStar(require("../src/helpers/callSwapHelper"));
|
|
12
|
+
const keeperAPI = tslib_1.__importStar(require("../src/keeper/keeperAPI"));
|
|
13
|
+
const callGetSwapParams = tslib_1.__importStar(require("../src/helpers/callGetSwapParams"));
|
|
14
|
+
// Mock entire modules to control their behavior for our tests
|
|
15
|
+
jest.mock('../src/config');
|
|
16
|
+
jest.mock('../src/helpers/fetchDataHelper');
|
|
17
|
+
jest.mock('../src/helpers/fetchPossibleSwap');
|
|
18
|
+
jest.mock('../src/helpers/callReadOnlyHelper');
|
|
19
|
+
jest.mock('../src/helpers/getContractInterfaceAndFunction');
|
|
20
|
+
jest.mock('@stacks/transactions', () => ({
|
|
21
|
+
...jest.requireActual('@stacks/transactions'), // Keep original module behavior
|
|
22
|
+
validateStacksAddress: jest.fn(() => true), // but mock this one function
|
|
23
|
+
}));
|
|
24
|
+
jest.mock('../src/helpers/callSwapHelper');
|
|
25
|
+
jest.mock('../src/keeper/keeperAPI');
|
|
26
|
+
jest.mock('../src/helpers/callGetSwapParams');
|
|
27
|
+
const MOCK_PROVIDER_ADDRESS = 'SP2J6S063B42M61D5T1G295SA4238A7147A4N17X';
|
|
28
|
+
// This is a helper to create fake API route data for our tests.
|
|
29
|
+
// We can control exactly what the 'provider' field looks like.
|
|
30
|
+
const createMockRoute = (providerValue) => {
|
|
31
|
+
const route = {
|
|
32
|
+
dex_path: ['DEX1'],
|
|
33
|
+
token_path: ['token-x', 'token-y'],
|
|
34
|
+
quoteData: {
|
|
35
|
+
contract: 'SP...contract',
|
|
36
|
+
function: 'get-quote',
|
|
37
|
+
parameters: {
|
|
38
|
+
// This is the key part: we will test what happens when
|
|
39
|
+
// the provider field is null, undefined, or a real address.
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
swapData: { contract: 'SP...swap-contract', function: 'swap', parameters: {} },
|
|
43
|
+
postConditions: {},
|
|
44
|
+
tokenXDecimals: 6,
|
|
45
|
+
tokenYDecimals: 6,
|
|
46
|
+
};
|
|
47
|
+
// If we pass 'undefined' to this helper, the 'provider' key won't even exist.
|
|
48
|
+
// This simulates an API response where the key is missing.
|
|
49
|
+
if (providerValue !== undefined) {
|
|
50
|
+
route.quoteData.parameters.provider = providerValue;
|
|
51
|
+
}
|
|
52
|
+
return route;
|
|
53
|
+
};
|
|
54
|
+
describe('BitflowSDK - Provider Logic in getQuoteForRoute', () => {
|
|
55
|
+
let sdk;
|
|
56
|
+
// Create mock functions that we can spy on
|
|
57
|
+
const mockedFetchAllTokens = fetchDataHelper.fetchAllTokensFromAPI;
|
|
58
|
+
const mockedFetchPossibleSwaps = fetchPossibleSwap.fetchPossibleSwapsFromAPI;
|
|
59
|
+
const mockedCallReadOnly = callReadOnlyHelper.callReadOnlyFunctionHelper;
|
|
60
|
+
const mockedGetInterface = getContractInterfaceAndFunctionHelper.getContractInterfaceAndFunction;
|
|
61
|
+
beforeEach(() => {
|
|
62
|
+
// Reset mocks and configurations before each test to ensure a clean slate
|
|
63
|
+
jest.clearAllMocks();
|
|
64
|
+
// Mock functions that are called during SDK initialization or the test itself
|
|
65
|
+
mockedFetchAllTokens.mockResolvedValue([]);
|
|
66
|
+
// This is the key change: we now simulate a contract function that expects a 'provider'.
|
|
67
|
+
mockedGetInterface.mockResolvedValue({
|
|
68
|
+
contractInterface: {},
|
|
69
|
+
functionArgs: [{ name: 'provider', type: '{optional: principal}' }]
|
|
70
|
+
});
|
|
71
|
+
mockedCallReadOnly.mockResolvedValue({ convertedResult: 100, rawResult: 1000, tokenXDecimals: 6, tokenYDecimals: 6 });
|
|
72
|
+
// Set up the default provider address for the SDK instance
|
|
73
|
+
config_1.configs.BITFLOW_PROVIDER_ADDRESS = MOCK_PROVIDER_ADDRESS;
|
|
74
|
+
// Initialize the SDK for each test
|
|
75
|
+
sdk = new BitflowSDK_1.BitflowSDK();
|
|
76
|
+
});
|
|
77
|
+
it('Scenario 1: Should use default provider when the route provider is null', async () => {
|
|
78
|
+
// ARRANGE: Create a fake route where the provider is explicitly `null`
|
|
79
|
+
const mockRouteWithNullProvider = createMockRoute(null);
|
|
80
|
+
mockedFetchPossibleSwaps.mockResolvedValue({ 'token-y': [mockRouteWithNullProvider] });
|
|
81
|
+
// ACT: Run the function we want to test
|
|
82
|
+
await sdk.getQuoteForRoute('token-x', 'token-y', 100);
|
|
83
|
+
// ASSERT: Check if our logic worked correctly
|
|
84
|
+
expect(mockedCallReadOnly).toHaveBeenCalledTimes(1);
|
|
85
|
+
const actualParams = mockedCallReadOnly.mock.calls[0][3]; // Get the 'params' argument
|
|
86
|
+
expect(actualParams.provider).toBe(MOCK_PROVIDER_ADDRESS); // It should have been added
|
|
87
|
+
});
|
|
88
|
+
it('Scenario 2: Should use default provider when the route provider is missing (undefined)', async () => {
|
|
89
|
+
// ARRANGE: Create a fake route where the 'provider' key doesn't exist
|
|
90
|
+
const mockRouteWithUndefinedProvider = createMockRoute(undefined);
|
|
91
|
+
mockedFetchPossibleSwaps.mockResolvedValue({ 'token-y': [mockRouteWithUndefinedProvider] });
|
|
92
|
+
// ACT
|
|
93
|
+
await sdk.getQuoteForRoute('token-x', 'token-y', 100);
|
|
94
|
+
// ASSERT
|
|
95
|
+
expect(mockedCallReadOnly).toHaveBeenCalledTimes(1);
|
|
96
|
+
const actualParams = mockedCallReadOnly.mock.calls[0][3];
|
|
97
|
+
expect(actualParams.provider).toBe(MOCK_PROVIDER_ADDRESS); // It should have been added
|
|
98
|
+
});
|
|
99
|
+
it('Scenario 3: Should NOT override the provider if a valid one is already present', async () => {
|
|
100
|
+
// ARRANGE: Create a fake route that already has a valid provider address
|
|
101
|
+
const routeSpecificProvider = 'SP3B15B6STM80A752A80W3P7J53KSAQ7J01PJ80B9';
|
|
102
|
+
const mockRouteWithSpecificProvider = createMockRoute(routeSpecificProvider);
|
|
103
|
+
mockedFetchPossibleSwaps.mockResolvedValue({ 'token-y': [mockRouteWithSpecificProvider] });
|
|
104
|
+
// ACT
|
|
105
|
+
await sdk.getQuoteForRoute('token-x', 'token-y', 100);
|
|
106
|
+
// ASSERT
|
|
107
|
+
expect(mockedCallReadOnly).toHaveBeenCalledTimes(1);
|
|
108
|
+
const actualParams = mockedCallReadOnly.mock.calls[0][3];
|
|
109
|
+
expect(actualParams.provider).toBe(routeSpecificProvider); // Should be the one from the route
|
|
110
|
+
expect(actualParams.provider).not.toBe(MOCK_PROVIDER_ADDRESS); // And NOT our default
|
|
111
|
+
});
|
|
112
|
+
it('Scenario 4: Should NOT add a provider if the function does not expect one', async () => {
|
|
113
|
+
// ARRANGE: For this test only, override the mock to simulate a function WITHOUT a provider.
|
|
114
|
+
mockedGetInterface.mockResolvedValue({ contractInterface: {}, functionArgs: [{ name: 'amount', type: 'uint' }] });
|
|
115
|
+
const mockRouteWithoutProvider = createMockRoute(undefined); // Provider is missing
|
|
116
|
+
mockedFetchPossibleSwaps.mockResolvedValue({ 'token-y': [mockRouteWithoutProvider] });
|
|
117
|
+
// ACT
|
|
118
|
+
await sdk.getQuoteForRoute('token-x', 'token-y', 100);
|
|
119
|
+
// ASSERT
|
|
120
|
+
expect(mockedCallReadOnly).toHaveBeenCalledTimes(1);
|
|
121
|
+
const actualParams = mockedCallReadOnly.mock.calls[0][3];
|
|
122
|
+
expect(actualParams.provider).toBeUndefined(); // Provider should NOT have been added
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
describe('BitflowSDK - Token and Swap Retrieval Methods', () => {
|
|
126
|
+
let sdk;
|
|
127
|
+
const mockedFetchAllTokens = fetchDataHelper.fetchAllTokensFromAPI;
|
|
128
|
+
const mockedFetchPossibleSwaps = fetchPossibleSwap.fetchPossibleSwapsFromAPI;
|
|
129
|
+
beforeEach(() => {
|
|
130
|
+
jest.clearAllMocks();
|
|
131
|
+
mockedFetchAllTokens.mockResolvedValue([
|
|
132
|
+
{ tokenId: 'token-x', isKeeperToken: false },
|
|
133
|
+
{ tokenId: 'token-keeper', isKeeperToken: true },
|
|
134
|
+
]);
|
|
135
|
+
mockedFetchPossibleSwaps.mockResolvedValue({ 'token-keeper': ['swap1', 'swap2'] });
|
|
136
|
+
sdk = new BitflowSDK_1.BitflowSDK();
|
|
137
|
+
});
|
|
138
|
+
it('should return all available tokens', async () => {
|
|
139
|
+
const tokens = await sdk.getAvailableTokens();
|
|
140
|
+
expect(tokens).toEqual([
|
|
141
|
+
{ tokenId: 'token-x', isKeeperToken: false },
|
|
142
|
+
{ tokenId: 'token-keeper', isKeeperToken: true },
|
|
143
|
+
]);
|
|
144
|
+
expect(mockedFetchAllTokens).toHaveBeenCalled();
|
|
145
|
+
});
|
|
146
|
+
it('should return only keeper tokens', async () => {
|
|
147
|
+
const tokens = await sdk.getKeeperTokens();
|
|
148
|
+
expect(tokens).toEqual([
|
|
149
|
+
{ tokenId: 'token-keeper', isKeeperToken: true }
|
|
150
|
+
]);
|
|
151
|
+
});
|
|
152
|
+
it('should return possible swaps for a token', async () => {
|
|
153
|
+
const swaps = await sdk.getPossibleSwaps('token-keeper');
|
|
154
|
+
expect(swaps).toEqual({ 'token-keeper': ['swap1', 'swap2'] });
|
|
155
|
+
expect(mockedFetchPossibleSwaps).toHaveBeenCalledWith('token-keeper');
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
describe('BitflowSDK - Token Y and Route Methods', () => {
|
|
159
|
+
let sdk;
|
|
160
|
+
const mockedFetchAllTokens = fetchDataHelper.fetchAllTokensFromAPI;
|
|
161
|
+
const mockedFetchPossibleSwaps = fetchPossibleSwap.fetchPossibleSwapsFromAPI;
|
|
162
|
+
beforeEach(() => {
|
|
163
|
+
jest.clearAllMocks();
|
|
164
|
+
mockedFetchAllTokens.mockResolvedValue([
|
|
165
|
+
{ tokenId: 'token-x', isKeeperToken: false },
|
|
166
|
+
{ tokenId: 'token-y', isKeeperToken: true },
|
|
167
|
+
]);
|
|
168
|
+
mockedFetchPossibleSwaps.mockResolvedValue({ 'token-y': [{ foo: 'bar' }], 'token-z': [{ baz: 'qux' }] });
|
|
169
|
+
sdk = new BitflowSDK_1.BitflowSDK();
|
|
170
|
+
// Pre-populate swapOptions for keeper methods
|
|
171
|
+
sdk.context.swapOptions = {
|
|
172
|
+
'token-x': { 'token-y': [{ foo: 'bar' }], 'token-z': [{ baz: 'qux' }] },
|
|
173
|
+
};
|
|
174
|
+
});
|
|
175
|
+
it('should return all possible token Y for a given token X', async () => {
|
|
176
|
+
sdk.context.swapOptions['token-x'] = { 'token-y': [], 'token-z': [] };
|
|
177
|
+
const result = await sdk.getAllPossibleTokenY('token-x');
|
|
178
|
+
expect(result).toEqual(['token-y', 'token-z']);
|
|
179
|
+
});
|
|
180
|
+
it('should return all keeper possible token Y for a given token X', async () => {
|
|
181
|
+
// Simulate getKeeperPossibleSwaps returns a similar structure
|
|
182
|
+
sdk.getKeeperPossibleSwaps = jest.fn().mockResolvedValue({ 'token-y': [], 'token-z': [] });
|
|
183
|
+
const result = await sdk.getAllKeeperPossibleTokenY('token-x');
|
|
184
|
+
expect(result).toEqual(['token-y', 'token-z']);
|
|
185
|
+
});
|
|
186
|
+
it('should return all possible token Y routes for a given token X and Y', async () => {
|
|
187
|
+
sdk.context.swapOptions['token-x'] = { 'token-y': [{ foo: 'bar' }], 'token-z': [{ baz: 'qux' }] };
|
|
188
|
+
const result = await sdk.getAllPossibleTokenYRoutes('token-x', 'token-y');
|
|
189
|
+
expect(result).toEqual([{ foo: 'bar' }]);
|
|
190
|
+
});
|
|
191
|
+
it('should return all keeper possible token Y routes for a given token X and Y', async () => {
|
|
192
|
+
sdk.getKeeperPossibleSwaps = jest.fn().mockResolvedValue({ 'token-y': [{ foo: 'bar' }], 'token-z': [{ baz: 'qux' }] });
|
|
193
|
+
const result = await sdk.getAllKeeperPossibleTokenYRoutes('token-x', 'token-y');
|
|
194
|
+
expect(result).toEqual([{ foo: 'bar' }]);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
describe('BitflowSDK - Route Quote Methods', () => {
|
|
198
|
+
let sdk;
|
|
199
|
+
const mockedFetchAllTokens = fetchDataHelper.fetchAllTokensFromAPI;
|
|
200
|
+
const mockedFetchPossibleSwaps = fetchPossibleSwap.fetchPossibleSwapsFromAPI;
|
|
201
|
+
const mockedCallReadOnly = callReadOnlyHelper.callReadOnlyFunctionHelper;
|
|
202
|
+
const mockedCallReadOnlyNoScale = callReadOnlyHelper.callReadOnlyFunctionHelperWithoutScaling;
|
|
203
|
+
const mockedGetInterface = getContractInterfaceAndFunctionHelper.getContractInterfaceAndFunction;
|
|
204
|
+
beforeEach(() => {
|
|
205
|
+
jest.clearAllMocks();
|
|
206
|
+
mockedFetchAllTokens.mockResolvedValue([
|
|
207
|
+
{ tokenId: 'token-x', isKeeperToken: false },
|
|
208
|
+
{ tokenId: 'token-y', isKeeperToken: true },
|
|
209
|
+
]);
|
|
210
|
+
mockedFetchPossibleSwaps.mockResolvedValue({ 'token-y': [{
|
|
211
|
+
quoteData: {
|
|
212
|
+
contract: 'SP...contract',
|
|
213
|
+
function: 'get-quote',
|
|
214
|
+
parameters: { amount: null },
|
|
215
|
+
},
|
|
216
|
+
swapData: { contract: 'SP...swap-contract', function: 'swap', parameters: {} },
|
|
217
|
+
dex_path: ['BITFLOW_STABLE_XY_2'],
|
|
218
|
+
tokenPath: ['token-x', 'token-y'],
|
|
219
|
+
}] });
|
|
220
|
+
mockedGetInterface.mockResolvedValue({ contractInterface: {}, functionArgs: [{ name: 'amount', type: 'uint' }] });
|
|
221
|
+
mockedCallReadOnly.mockResolvedValue({ convertedResult: 100, rawResult: 1000, tokenXDecimals: 6, tokenYDecimals: 6, allRoutes: [], bestRoute: null });
|
|
222
|
+
mockedCallReadOnlyNoScale.mockResolvedValue({ convertedResult: 100, rawResult: 1000, tokenXDecimals: 6, tokenYDecimals: 6, allRoutes: [], bestRoute: null });
|
|
223
|
+
sdk = new BitflowSDK_1.BitflowSDK();
|
|
224
|
+
sdk.context.swapOptions = {
|
|
225
|
+
'token-x': { 'token-y': [{
|
|
226
|
+
quoteData: {
|
|
227
|
+
contract: 'SP...contract',
|
|
228
|
+
function: 'get-quote',
|
|
229
|
+
parameters: { amount: null },
|
|
230
|
+
},
|
|
231
|
+
swapData: { contract: 'SP...swap-contract', function: 'swap', parameters: {} },
|
|
232
|
+
dex_path: ['BITFLOW_STABLE_XY_2'],
|
|
233
|
+
tokenPath: ['token-x', 'token-y'],
|
|
234
|
+
}] },
|
|
235
|
+
};
|
|
236
|
+
});
|
|
237
|
+
it('should get a quote for a route', async () => {
|
|
238
|
+
const result = await sdk.getQuoteForRoute('token-x', 'token-y', 100);
|
|
239
|
+
expect(result.bestRoute).toBeDefined();
|
|
240
|
+
expect(result.allRoutes.length).toBeGreaterThan(0);
|
|
241
|
+
expect(result.inputData.tokenX).toBe('token-x');
|
|
242
|
+
expect(mockedCallReadOnly).toHaveBeenCalled();
|
|
243
|
+
});
|
|
244
|
+
it('should get a keeper quote for a route', async () => {
|
|
245
|
+
// The keeper method filters for compatible DEX paths
|
|
246
|
+
const result = await sdk.getKeeperQuoteForRoute('token-x', 'token-y', 100);
|
|
247
|
+
expect(result.bestRoute).toBeDefined();
|
|
248
|
+
expect(result.allRoutes.length).toBeGreaterThan(0);
|
|
249
|
+
expect(result.inputData.tokenX).toBe('token-x');
|
|
250
|
+
expect(mockedCallReadOnly).toHaveBeenCalled();
|
|
251
|
+
});
|
|
252
|
+
it('should get a keeper quote for a route without scaling', async () => {
|
|
253
|
+
const result = await sdk.getKeeperQuoteForRouteWithoutScaling('token-x', 'token-y', 100);
|
|
254
|
+
expect(result.bestRoute).toBeDefined();
|
|
255
|
+
expect(result.allRoutes.length).toBeGreaterThan(0);
|
|
256
|
+
expect(result.inputData.tokenX).toBe('token-x');
|
|
257
|
+
expect(mockedCallReadOnlyNoScale).toHaveBeenCalled();
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
describe('BitflowSDK - Execution and Keeper Methods', () => {
|
|
261
|
+
let sdk;
|
|
262
|
+
const mockedFetchAllTokens = fetchDataHelper.fetchAllTokensFromAPI;
|
|
263
|
+
const mockedExecuteSwapHelper = callSwapHelper.executeSwapHelper;
|
|
264
|
+
const mockedGetOrCreateKeeperContractAPI = keeperAPI.getOrCreateKeeperContractAPI;
|
|
265
|
+
const mockedGetUserAPI = keeperAPI.getUserAPI;
|
|
266
|
+
const mockedGetQuoteAPI = keeperAPI.getQuoteAPI;
|
|
267
|
+
beforeEach(() => {
|
|
268
|
+
jest.clearAllMocks();
|
|
269
|
+
mockedFetchAllTokens.mockResolvedValue([
|
|
270
|
+
{ tokenId: 'token-x', isKeeperToken: false },
|
|
271
|
+
{ tokenId: 'token-y', isKeeperToken: true },
|
|
272
|
+
]);
|
|
273
|
+
sdk = new BitflowSDK_1.BitflowSDK();
|
|
274
|
+
});
|
|
275
|
+
it('should call executeSwapHelper in executeSwap', async () => {
|
|
276
|
+
mockedExecuteSwapHelper.mockResolvedValue(undefined);
|
|
277
|
+
const swapExecutionData = {
|
|
278
|
+
route: {
|
|
279
|
+
dex_path: [],
|
|
280
|
+
postConditions: {},
|
|
281
|
+
quoteData: { contract: '', function: '', parameters: {} },
|
|
282
|
+
swapData: { contract: '', function: '', parameters: {} },
|
|
283
|
+
token_path: [],
|
|
284
|
+
tokenXDecimals: 6,
|
|
285
|
+
tokenYDecimals: 6,
|
|
286
|
+
},
|
|
287
|
+
amount: 1,
|
|
288
|
+
tokenXDecimals: 6,
|
|
289
|
+
tokenYDecimals: 6,
|
|
290
|
+
};
|
|
291
|
+
const senderAddress = 'SENDER';
|
|
292
|
+
sdk.getSwapParams = jest.fn().mockResolvedValue({});
|
|
293
|
+
sdk.loadConnectDependencies = jest.fn().mockResolvedValue({});
|
|
294
|
+
global.window = {};
|
|
295
|
+
await expect(sdk.executeSwap(swapExecutionData, senderAddress)).resolves.toBeUndefined();
|
|
296
|
+
expect(mockedExecuteSwapHelper).toHaveBeenCalled();
|
|
297
|
+
delete global.window;
|
|
298
|
+
});
|
|
299
|
+
it('should throw if executeSwap is called in Node.js', async () => {
|
|
300
|
+
const swapExecutionData = {
|
|
301
|
+
route: {
|
|
302
|
+
dex_path: [],
|
|
303
|
+
postConditions: {},
|
|
304
|
+
quoteData: { contract: '', function: '', parameters: {} },
|
|
305
|
+
swapData: { contract: '', function: '', parameters: {} },
|
|
306
|
+
token_path: [],
|
|
307
|
+
tokenXDecimals: 6,
|
|
308
|
+
tokenYDecimals: 6,
|
|
309
|
+
},
|
|
310
|
+
amount: 1,
|
|
311
|
+
tokenXDecimals: 6,
|
|
312
|
+
tokenYDecimals: 6,
|
|
313
|
+
};
|
|
314
|
+
const senderAddress = 'SENDER';
|
|
315
|
+
sdk.getSwapParams = jest.fn().mockResolvedValue({});
|
|
316
|
+
sdk.loadConnectDependencies = undefined; // Remove the mock to trigger the Node.js error path
|
|
317
|
+
delete global.window;
|
|
318
|
+
await expect(sdk.executeSwap(swapExecutionData, senderAddress)).rejects.toThrow('only available in browser environments');
|
|
319
|
+
});
|
|
320
|
+
it('should get or create keeper contract', async () => {
|
|
321
|
+
mockedGetOrCreateKeeperContractAPI.mockResolvedValue({ contract: 'keeper-contract' });
|
|
322
|
+
const params = { stacksAddress: 'SOMEADDR', keeperType: types_1.KeeperType.SWAP_BTC_TO_STX };
|
|
323
|
+
const result = await sdk.getOrCreateKeeperContract(params);
|
|
324
|
+
expect(result).toEqual({ contract: 'keeper-contract' });
|
|
325
|
+
expect(mockedGetOrCreateKeeperContractAPI).toHaveBeenCalled();
|
|
326
|
+
});
|
|
327
|
+
it('should get user', async () => {
|
|
328
|
+
mockedGetUserAPI.mockResolvedValue({ user: 'user-data' });
|
|
329
|
+
const result = await sdk.getUser('SOMEADDR');
|
|
330
|
+
expect(result).toEqual({ user: 'user-data' });
|
|
331
|
+
expect(mockedGetUserAPI).toHaveBeenCalled();
|
|
332
|
+
});
|
|
333
|
+
it('should get quote', async () => {
|
|
334
|
+
mockedGetQuoteAPI.mockResolvedValue({ quote: 'quote-data' });
|
|
335
|
+
const params = { stacksAddress: 'SOMEADDR', actionAmount: '1', keeperType: types_1.KeeperType.SWAP_BTC_TO_STX };
|
|
336
|
+
const result = await sdk.getQuote(params);
|
|
337
|
+
expect(result).toEqual({ quote: 'quote-data' });
|
|
338
|
+
expect(mockedGetQuoteAPI).toHaveBeenCalled();
|
|
339
|
+
});
|
|
340
|
+
it('should handle errors in getOrCreateKeeperContract', async () => {
|
|
341
|
+
mockedGetOrCreateKeeperContractAPI.mockRejectedValue(new Error('fail'));
|
|
342
|
+
const params = { stacksAddress: 'SOMEADDR', keeperType: types_1.KeeperType.SWAP_BTC_TO_STX };
|
|
343
|
+
await expect(sdk.getOrCreateKeeperContract(params)).rejects.toThrow('fail');
|
|
344
|
+
});
|
|
345
|
+
it('should handle errors in getUser', async () => {
|
|
346
|
+
mockedGetUserAPI.mockRejectedValue(new Error('fail'));
|
|
347
|
+
await expect(sdk.getUser('SOMEADDR')).rejects.toThrow('fail');
|
|
348
|
+
});
|
|
349
|
+
it('should handle errors in getQuote', async () => {
|
|
350
|
+
mockedGetQuoteAPI.mockRejectedValue(new Error('fail'));
|
|
351
|
+
const params = { stacksAddress: 'SOMEADDR', actionAmount: '1', keeperType: types_1.KeeperType.SWAP_BTC_TO_STX };
|
|
352
|
+
await expect(sdk.getQuote(params)).rejects.toThrow('fail');
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
describe('BitflowSDK - Additional Keeper Methods', () => {
|
|
356
|
+
let sdk;
|
|
357
|
+
const mockedGetOrderAPI = keeperAPI.getOrderAPI;
|
|
358
|
+
const mockedCreateOrderAPI = keeperAPI.createOrderAPI;
|
|
359
|
+
const mockedCreateGroupOrderAPI = keeperAPI.createGroupOrderAPI;
|
|
360
|
+
const mockedGetGroupOrderAPI = keeperAPI.getGroupOrderAPI;
|
|
361
|
+
const mockedCancelOrderAPI = keeperAPI.cancelOrderAPI;
|
|
362
|
+
const mockedCancelGroupOrderAPI = keeperAPI.cancelGroupOrderAPI;
|
|
363
|
+
beforeEach(() => {
|
|
364
|
+
jest.clearAllMocks();
|
|
365
|
+
sdk = new BitflowSDK_1.BitflowSDK();
|
|
366
|
+
});
|
|
367
|
+
it('should get order', async () => {
|
|
368
|
+
mockedGetOrderAPI.mockResolvedValue({ order: 'order-data' });
|
|
369
|
+
const result = await sdk.getOrder('order123');
|
|
370
|
+
expect(result).toEqual({ order: 'order-data' });
|
|
371
|
+
expect(mockedGetOrderAPI).toHaveBeenCalledWith('order123');
|
|
372
|
+
});
|
|
373
|
+
it('should handle errors in getOrder', async () => {
|
|
374
|
+
mockedGetOrderAPI.mockRejectedValue(new Error('fail'));
|
|
375
|
+
await expect(sdk.getOrder('order123')).rejects.toThrow('fail');
|
|
376
|
+
});
|
|
377
|
+
it('should create order', async () => {
|
|
378
|
+
mockedCreateOrderAPI.mockResolvedValue({ order: 'created' });
|
|
379
|
+
const params = {
|
|
380
|
+
stacksAddress: 'ST123',
|
|
381
|
+
keeperType: types_1.KeeperType.SWAP_BTC_TO_STX,
|
|
382
|
+
contractIdentifier: 'contract',
|
|
383
|
+
bitcoinAddress: 'btc123',
|
|
384
|
+
actionAmount: '100',
|
|
385
|
+
minReceived: { amount: '50', autoAdjust: true },
|
|
386
|
+
feeRecipient: 'fee',
|
|
387
|
+
tokenOrder: ['token1', 'token2'],
|
|
388
|
+
actionType: 'swap',
|
|
389
|
+
bitcoinTxId: 'txid',
|
|
390
|
+
fundingTokens: { token1: '10' },
|
|
391
|
+
actionAggregatorTokens: { tokenXId: 'token1', tokenYId: 'token2' },
|
|
392
|
+
};
|
|
393
|
+
const result = await sdk.createOrder(params);
|
|
394
|
+
expect(result).toEqual({ order: 'created' });
|
|
395
|
+
expect(mockedCreateOrderAPI).toHaveBeenCalledWith(params);
|
|
396
|
+
});
|
|
397
|
+
it('should handle errors in createOrder', async () => {
|
|
398
|
+
mockedCreateOrderAPI.mockRejectedValue(new Error('fail'));
|
|
399
|
+
const params = {
|
|
400
|
+
stacksAddress: 'ST123',
|
|
401
|
+
keeperType: types_1.KeeperType.SWAP_BTC_TO_STX,
|
|
402
|
+
contractIdentifier: 'contract',
|
|
403
|
+
bitcoinAddress: 'btc123',
|
|
404
|
+
actionAmount: '100',
|
|
405
|
+
minReceived: { amount: '50', autoAdjust: true },
|
|
406
|
+
feeRecipient: 'fee',
|
|
407
|
+
tokenOrder: ['token1', 'token2'],
|
|
408
|
+
actionType: 'swap',
|
|
409
|
+
bitcoinTxId: 'txid',
|
|
410
|
+
fundingTokens: { token1: '10' },
|
|
411
|
+
actionAggregatorTokens: { tokenXId: 'token1', tokenYId: 'token2' },
|
|
412
|
+
};
|
|
413
|
+
await expect(sdk.createOrder(params)).rejects.toThrow('fail');
|
|
414
|
+
});
|
|
415
|
+
it('should create group order', async () => {
|
|
416
|
+
mockedCreateGroupOrderAPI.mockResolvedValue({ groupOrder: 'created' });
|
|
417
|
+
const params = {
|
|
418
|
+
stacksAddress: 'ST123',
|
|
419
|
+
amountPerOrder: 10,
|
|
420
|
+
numberOfOrders: 2,
|
|
421
|
+
executionFrequency: 60,
|
|
422
|
+
feeRecipient: 'fee',
|
|
423
|
+
fundingTokens: { token1: '10' },
|
|
424
|
+
keeperType: types_1.KeeperType.SWAP_BTC_TO_STX,
|
|
425
|
+
minReceived: { amount: '50', autoAdjust: true },
|
|
426
|
+
groupId: 'group1',
|
|
427
|
+
orders: [],
|
|
428
|
+
};
|
|
429
|
+
const result = await sdk.createGroupOrder(params);
|
|
430
|
+
expect(result).toEqual({ groupOrder: 'created' });
|
|
431
|
+
expect(mockedCreateGroupOrderAPI).toHaveBeenCalledWith(params);
|
|
432
|
+
});
|
|
433
|
+
it('should handle errors in createGroupOrder', async () => {
|
|
434
|
+
mockedCreateGroupOrderAPI.mockRejectedValue(new Error('fail'));
|
|
435
|
+
const params = {
|
|
436
|
+
stacksAddress: 'ST123',
|
|
437
|
+
amountPerOrder: 10,
|
|
438
|
+
numberOfOrders: 2,
|
|
439
|
+
executionFrequency: 60,
|
|
440
|
+
feeRecipient: 'fee',
|
|
441
|
+
fundingTokens: { token1: '10' },
|
|
442
|
+
keeperType: types_1.KeeperType.SWAP_BTC_TO_STX,
|
|
443
|
+
minReceived: { amount: '50', autoAdjust: true },
|
|
444
|
+
groupId: 'group1',
|
|
445
|
+
orders: [],
|
|
446
|
+
};
|
|
447
|
+
await expect(sdk.createGroupOrder(params)).rejects.toThrow('fail');
|
|
448
|
+
});
|
|
449
|
+
it('should get group order', async () => {
|
|
450
|
+
mockedGetGroupOrderAPI.mockResolvedValue({ groupOrder: 'data' });
|
|
451
|
+
const result = await sdk.getGroupOrder('group1', true);
|
|
452
|
+
expect(result).toEqual({ groupOrder: 'data' });
|
|
453
|
+
expect(mockedGetGroupOrderAPI).toHaveBeenCalledWith('group1', true);
|
|
454
|
+
});
|
|
455
|
+
it('should handle errors in getGroupOrder', async () => {
|
|
456
|
+
mockedGetGroupOrderAPI.mockRejectedValue(new Error('fail'));
|
|
457
|
+
await expect(sdk.getGroupOrder('group1', true)).rejects.toThrow('fail');
|
|
458
|
+
});
|
|
459
|
+
it('should cancel order', async () => {
|
|
460
|
+
mockedCancelOrderAPI.mockResolvedValue({ cancel: 'ok' });
|
|
461
|
+
const result = await sdk.cancelOrder('order123');
|
|
462
|
+
expect(result).toEqual({ cancel: 'ok' });
|
|
463
|
+
expect(mockedCancelOrderAPI).toHaveBeenCalledWith('order123');
|
|
464
|
+
});
|
|
465
|
+
it('should handle errors in cancelOrder', async () => {
|
|
466
|
+
mockedCancelOrderAPI.mockRejectedValue(new Error('fail'));
|
|
467
|
+
await expect(sdk.cancelOrder('order123')).rejects.toThrow('fail');
|
|
468
|
+
});
|
|
469
|
+
it('should cancel group order', async () => {
|
|
470
|
+
mockedCancelGroupOrderAPI.mockResolvedValue({ cancel: 'ok' });
|
|
471
|
+
const result = await sdk.cancelGroupOrder('group1');
|
|
472
|
+
expect(result).toEqual({ cancel: 'ok' });
|
|
473
|
+
expect(mockedCancelGroupOrderAPI).toHaveBeenCalledWith('group1');
|
|
474
|
+
});
|
|
475
|
+
it('should handle errors in cancelGroupOrder', async () => {
|
|
476
|
+
mockedCancelGroupOrderAPI.mockRejectedValue(new Error('fail'));
|
|
477
|
+
await expect(sdk.cancelGroupOrder('group1')).rejects.toThrow('fail');
|
|
478
|
+
});
|
|
479
|
+
});
|
|
480
|
+
describe('BitflowSDK - Swap Parameter and Preparation Methods', () => {
|
|
481
|
+
let sdk;
|
|
482
|
+
const mockedCallGetSwapParams = callGetSwapParams.executeGetParams;
|
|
483
|
+
const mockedCallReadOnlyNoScale = callReadOnlyHelper.callReadOnlyFunctionHelperWithoutScaling;
|
|
484
|
+
beforeEach(() => {
|
|
485
|
+
jest.clearAllMocks();
|
|
486
|
+
mockedCallGetSwapParams.mockResolvedValue({
|
|
487
|
+
swapData: { data: 'swap-data' },
|
|
488
|
+
parameters: { params: 'params' },
|
|
489
|
+
postConditions: { conditions: 'conditions' }
|
|
490
|
+
});
|
|
491
|
+
// Mock the getKeeperQuoteForRouteWithoutScaling method
|
|
492
|
+
jest.spyOn(BitflowSDK_1.BitflowSDK.prototype, 'getKeeperQuoteForRouteWithoutScaling').mockResolvedValue({
|
|
493
|
+
bestRoute: {
|
|
494
|
+
route: {
|
|
495
|
+
dex_path: ['BITFLOW_XY_2_xyk'],
|
|
496
|
+
token_path: ['token-x', 'token-y'],
|
|
497
|
+
postConditions: {},
|
|
498
|
+
tokenXDecimals: 6,
|
|
499
|
+
tokenYDecimals: 6,
|
|
500
|
+
quoteData: {
|
|
501
|
+
contract: 'SP...contract',
|
|
502
|
+
function: 'get-quote',
|
|
503
|
+
parameters: { amount: 100 },
|
|
504
|
+
},
|
|
505
|
+
swapData: {
|
|
506
|
+
contract: 'SP...swap-contract',
|
|
507
|
+
function: 'swap',
|
|
508
|
+
parameters: {
|
|
509
|
+
'pool-trait': 'SP1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.xyk-pool-v-1-2',
|
|
510
|
+
},
|
|
511
|
+
},
|
|
512
|
+
},
|
|
513
|
+
quote: 100,
|
|
514
|
+
params: {},
|
|
515
|
+
quoteData: {
|
|
516
|
+
contract: 'SP...contract',
|
|
517
|
+
function: 'get-quote',
|
|
518
|
+
parameters: { amount: 100 },
|
|
519
|
+
},
|
|
520
|
+
swapData: {
|
|
521
|
+
contract: 'SP...swap-contract',
|
|
522
|
+
function: 'swap',
|
|
523
|
+
parameters: {
|
|
524
|
+
'pool-trait': 'SP1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.xyk-pool-v-1-2',
|
|
525
|
+
},
|
|
526
|
+
},
|
|
527
|
+
dexPath: ['BITFLOW_XY_2_xyk'],
|
|
528
|
+
tokenPath: ['token-x', 'token-y'],
|
|
529
|
+
tokenXDecimals: 6,
|
|
530
|
+
tokenYDecimals: 6,
|
|
531
|
+
},
|
|
532
|
+
allRoutes: [{
|
|
533
|
+
route: {
|
|
534
|
+
dex_path: ['BITFLOW_XY_2_xyk'],
|
|
535
|
+
token_path: ['token-x', 'token-y'],
|
|
536
|
+
postConditions: {},
|
|
537
|
+
tokenXDecimals: 6,
|
|
538
|
+
tokenYDecimals: 6,
|
|
539
|
+
quoteData: {
|
|
540
|
+
contract: 'SP...contract',
|
|
541
|
+
function: 'get-quote',
|
|
542
|
+
parameters: { amount: 100 },
|
|
543
|
+
},
|
|
544
|
+
swapData: {
|
|
545
|
+
contract: 'SP...swap-contract',
|
|
546
|
+
function: 'swap',
|
|
547
|
+
parameters: {
|
|
548
|
+
'pool-trait': 'SP1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.xyk-pool-v-1-2',
|
|
549
|
+
},
|
|
550
|
+
},
|
|
551
|
+
},
|
|
552
|
+
quote: 100,
|
|
553
|
+
params: {},
|
|
554
|
+
quoteData: {
|
|
555
|
+
contract: 'SP...contract',
|
|
556
|
+
function: 'get-quote',
|
|
557
|
+
parameters: { amount: 100 },
|
|
558
|
+
},
|
|
559
|
+
swapData: {
|
|
560
|
+
contract: 'SP...swap-contract',
|
|
561
|
+
function: 'swap',
|
|
562
|
+
parameters: {
|
|
563
|
+
'pool-trait': 'SP1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.xyk-pool-v-1-2',
|
|
564
|
+
},
|
|
565
|
+
},
|
|
566
|
+
dexPath: ['BITFLOW_XY_2_xyk'],
|
|
567
|
+
tokenPath: ['token-x', 'token-y'],
|
|
568
|
+
tokenXDecimals: 6,
|
|
569
|
+
tokenYDecimals: 6,
|
|
570
|
+
}],
|
|
571
|
+
inputData: {
|
|
572
|
+
tokenX: 'token-x',
|
|
573
|
+
tokenY: 'token-y',
|
|
574
|
+
amountInput: 100,
|
|
575
|
+
},
|
|
576
|
+
});
|
|
577
|
+
sdk = new BitflowSDK_1.BitflowSDK();
|
|
578
|
+
});
|
|
579
|
+
it('should get swap params', async () => {
|
|
580
|
+
const swapExecutionData = {
|
|
581
|
+
route: {
|
|
582
|
+
dex_path: ['BITFLOW_XY_2'],
|
|
583
|
+
postConditions: {},
|
|
584
|
+
quoteData: { contract: 'SP...contract', function: 'get-quote', parameters: { amount: null } },
|
|
585
|
+
swapData: {
|
|
586
|
+
contract: 'SP...swap-contract',
|
|
587
|
+
function: 'swap',
|
|
588
|
+
parameters: {
|
|
589
|
+
'pool-trait': 'SP1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.xyk-pool-v-1-2'
|
|
590
|
+
}
|
|
591
|
+
},
|
|
592
|
+
token_path: ['token-x', 'token-y'],
|
|
593
|
+
tokenXDecimals: 6,
|
|
594
|
+
tokenYDecimals: 6,
|
|
595
|
+
},
|
|
596
|
+
amount: 100,
|
|
597
|
+
tokenXDecimals: 6,
|
|
598
|
+
tokenYDecimals: 6,
|
|
599
|
+
};
|
|
600
|
+
const senderAddress = 'SENDER';
|
|
601
|
+
const result = await sdk.getSwapParams(swapExecutionData, senderAddress, 0.015);
|
|
602
|
+
expect(result).toEqual({
|
|
603
|
+
swapData: { data: 'swap-data' },
|
|
604
|
+
parameters: { params: 'params' },
|
|
605
|
+
postConditions: { conditions: 'conditions' }
|
|
606
|
+
});
|
|
607
|
+
expect(mockedCallGetSwapParams).toHaveBeenCalled();
|
|
608
|
+
});
|
|
609
|
+
it('should prepare swap', async () => {
|
|
610
|
+
const swapExecutionData = {
|
|
611
|
+
route: {
|
|
612
|
+
dex_path: ['BITFLOW_XY_2'],
|
|
613
|
+
postConditions: {},
|
|
614
|
+
quoteData: { contract: 'SP...contract', function: 'get-quote', parameters: { amount: null } },
|
|
615
|
+
swapData: {
|
|
616
|
+
contract: 'SP...swap-contract',
|
|
617
|
+
function: 'swap',
|
|
618
|
+
parameters: {
|
|
619
|
+
'pool-trait': 'SP1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.xyk-pool-v-1-2'
|
|
620
|
+
}
|
|
621
|
+
},
|
|
622
|
+
token_path: ['token-x', 'token-y'],
|
|
623
|
+
tokenXDecimals: 6,
|
|
624
|
+
tokenYDecimals: 6,
|
|
625
|
+
},
|
|
626
|
+
amount: 100,
|
|
627
|
+
tokenXDecimals: 6,
|
|
628
|
+
tokenYDecimals: 6,
|
|
629
|
+
};
|
|
630
|
+
const senderAddress = 'SENDER';
|
|
631
|
+
const result = await sdk.prepareSwap(swapExecutionData, senderAddress, 0.015);
|
|
632
|
+
expect(result).toEqual({
|
|
633
|
+
swapData: { data: 'swap-data' },
|
|
634
|
+
parameters: { params: 'params' },
|
|
635
|
+
postConditions: { conditions: 'conditions' }
|
|
636
|
+
});
|
|
637
|
+
expect(mockedCallGetSwapParams).toHaveBeenCalled();
|
|
638
|
+
});
|
|
639
|
+
it('should get keeper aggregator route data', async () => {
|
|
640
|
+
sdk["context"].availableTokens = [
|
|
641
|
+
{
|
|
642
|
+
base: 'base-x',
|
|
643
|
+
type: 'type-x',
|
|
644
|
+
icon: '',
|
|
645
|
+
name: 'Token X',
|
|
646
|
+
status: 'active',
|
|
647
|
+
symbol: 'TKX',
|
|
648
|
+
tokenId: 'token-x',
|
|
649
|
+
"token-id": 'token-x',
|
|
650
|
+
tokenContract: 'contract-x',
|
|
651
|
+
tokenDecimals: 6,
|
|
652
|
+
tokenName: 'Token X',
|
|
653
|
+
wrapTokens: null,
|
|
654
|
+
isKeeperToken: false,
|
|
655
|
+
bridge: 'FALSE',
|
|
656
|
+
layerOneAsset: null,
|
|
657
|
+
priceData: {
|
|
658
|
+
"1h_change": null,
|
|
659
|
+
"1yr_change": null,
|
|
660
|
+
"24h_change": null,
|
|
661
|
+
"30d_change": null,
|
|
662
|
+
"7d_change": null,
|
|
663
|
+
last_price: null,
|
|
664
|
+
last_updated: null,
|
|
665
|
+
},
|
|
666
|
+
},
|
|
667
|
+
{
|
|
668
|
+
base: 'base-y',
|
|
669
|
+
type: 'type-y',
|
|
670
|
+
icon: '',
|
|
671
|
+
name: 'Token Y',
|
|
672
|
+
status: 'active',
|
|
673
|
+
symbol: 'TKY',
|
|
674
|
+
tokenId: 'token-y',
|
|
675
|
+
"token-id": 'token-y',
|
|
676
|
+
tokenContract: 'contract-y',
|
|
677
|
+
tokenDecimals: 8,
|
|
678
|
+
tokenName: 'Token Y',
|
|
679
|
+
wrapTokens: null,
|
|
680
|
+
isKeeperToken: false,
|
|
681
|
+
bridge: 'FALSE',
|
|
682
|
+
layerOneAsset: null,
|
|
683
|
+
priceData: {
|
|
684
|
+
"1h_change": null,
|
|
685
|
+
"1yr_change": null,
|
|
686
|
+
"24h_change": null,
|
|
687
|
+
"30d_change": null,
|
|
688
|
+
"7d_change": null,
|
|
689
|
+
last_price: null,
|
|
690
|
+
last_updated: null,
|
|
691
|
+
},
|
|
692
|
+
},
|
|
693
|
+
];
|
|
694
|
+
const result = await sdk.getKeeperAggregatorRouteData('token-x', 'token-y', 100);
|
|
695
|
+
expect(result.xykPoolList).toBeDefined();
|
|
696
|
+
expect(result.actionTrait).toBeDefined();
|
|
697
|
+
});
|
|
698
|
+
it('should handle mixed XYK and stableswap route', async () => {
|
|
699
|
+
sdk["context"].availableTokens = [
|
|
700
|
+
{
|
|
701
|
+
base: 'base-x',
|
|
702
|
+
type: 'type-x',
|
|
703
|
+
icon: '',
|
|
704
|
+
name: 'Token X',
|
|
705
|
+
status: 'active',
|
|
706
|
+
symbol: 'TKX',
|
|
707
|
+
tokenId: 'token-x',
|
|
708
|
+
"token-id": 'token-x',
|
|
709
|
+
tokenContract: 'contract-x',
|
|
710
|
+
tokenDecimals: 6,
|
|
711
|
+
tokenName: 'Token X',
|
|
712
|
+
wrapTokens: null,
|
|
713
|
+
isKeeperToken: false,
|
|
714
|
+
bridge: 'FALSE',
|
|
715
|
+
layerOneAsset: null,
|
|
716
|
+
priceData: {
|
|
717
|
+
"1h_change": null,
|
|
718
|
+
"1yr_change": null,
|
|
719
|
+
"24h_change": null,
|
|
720
|
+
"30d_change": null,
|
|
721
|
+
"7d_change": null,
|
|
722
|
+
last_price: null,
|
|
723
|
+
last_updated: null,
|
|
724
|
+
},
|
|
725
|
+
},
|
|
726
|
+
{
|
|
727
|
+
base: 'base-y',
|
|
728
|
+
type: 'type-y',
|
|
729
|
+
icon: '',
|
|
730
|
+
name: 'Token Y',
|
|
731
|
+
status: 'active',
|
|
732
|
+
symbol: 'TKY',
|
|
733
|
+
tokenId: 'token-y',
|
|
734
|
+
"token-id": 'token-y',
|
|
735
|
+
tokenContract: 'contract-y',
|
|
736
|
+
tokenDecimals: 8,
|
|
737
|
+
tokenName: 'Token Y',
|
|
738
|
+
wrapTokens: null,
|
|
739
|
+
isKeeperToken: false,
|
|
740
|
+
bridge: 'FALSE',
|
|
741
|
+
layerOneAsset: null,
|
|
742
|
+
priceData: {
|
|
743
|
+
"1h_change": null,
|
|
744
|
+
"1yr_change": null,
|
|
745
|
+
"24h_change": null,
|
|
746
|
+
"30d_change": null,
|
|
747
|
+
"7d_change": null,
|
|
748
|
+
last_price: null,
|
|
749
|
+
last_updated: null,
|
|
750
|
+
},
|
|
751
|
+
},
|
|
752
|
+
];
|
|
753
|
+
// Override the mock for this specific test
|
|
754
|
+
jest.spyOn(BitflowSDK_1.BitflowSDK.prototype, 'getKeeperQuoteForRouteWithoutScaling').mockResolvedValue({
|
|
755
|
+
bestRoute: {
|
|
756
|
+
route: {
|
|
757
|
+
dex_path: ['BITFLOW_XY_2_xyk', 'BITFLOW_STABLE_XY_2_stable'],
|
|
758
|
+
token_path: ['token-x', 'token-y'],
|
|
759
|
+
postConditions: {},
|
|
760
|
+
tokenXDecimals: 6,
|
|
761
|
+
tokenYDecimals: 6,
|
|
762
|
+
quoteData: {
|
|
763
|
+
contract: 'SP...contract',
|
|
764
|
+
function: 'get-quote',
|
|
765
|
+
parameters: { amount: 100 },
|
|
766
|
+
},
|
|
767
|
+
swapData: {
|
|
768
|
+
contract: 'SP...swap-contract',
|
|
769
|
+
function: 'swap',
|
|
770
|
+
parameters: {
|
|
771
|
+
'xyk-pools': ['pool1', 'pool2'],
|
|
772
|
+
'stableswap-pools': ['stable-pool1'],
|
|
773
|
+
},
|
|
774
|
+
},
|
|
775
|
+
},
|
|
776
|
+
quote: 100,
|
|
777
|
+
params: {},
|
|
778
|
+
quoteData: {
|
|
779
|
+
contract: 'SP...contract',
|
|
780
|
+
function: 'get-quote',
|
|
781
|
+
parameters: { amount: 100 },
|
|
782
|
+
},
|
|
783
|
+
swapData: {
|
|
784
|
+
contract: 'SP...swap-contract',
|
|
785
|
+
function: 'swap',
|
|
786
|
+
parameters: {
|
|
787
|
+
'xyk-pools': ['pool1', 'pool2'],
|
|
788
|
+
'stableswap-pools': ['stable-pool1'],
|
|
789
|
+
},
|
|
790
|
+
},
|
|
791
|
+
dexPath: ['BITFLOW_XY_2_xyk', 'BITFLOW_STABLE_XY_2_stable'],
|
|
792
|
+
tokenPath: ['token-x', 'token-y'],
|
|
793
|
+
tokenXDecimals: 6,
|
|
794
|
+
tokenYDecimals: 6,
|
|
795
|
+
},
|
|
796
|
+
allRoutes: [{
|
|
797
|
+
route: {
|
|
798
|
+
dex_path: ['BITFLOW_XY_2_xyk', 'BITFLOW_STABLE_XY_2_stable'],
|
|
799
|
+
token_path: ['token-x', 'token-y'],
|
|
800
|
+
postConditions: {},
|
|
801
|
+
tokenXDecimals: 6,
|
|
802
|
+
tokenYDecimals: 6,
|
|
803
|
+
quoteData: {
|
|
804
|
+
contract: 'SP...contract',
|
|
805
|
+
function: 'get-quote',
|
|
806
|
+
parameters: { amount: 100 },
|
|
807
|
+
},
|
|
808
|
+
swapData: {
|
|
809
|
+
contract: 'SP...swap-contract',
|
|
810
|
+
function: 'swap',
|
|
811
|
+
parameters: {
|
|
812
|
+
'xyk-pools': ['pool1', 'pool2'],
|
|
813
|
+
'stableswap-pools': ['stable-pool1'],
|
|
814
|
+
},
|
|
815
|
+
},
|
|
816
|
+
},
|
|
817
|
+
quote: 100,
|
|
818
|
+
params: {},
|
|
819
|
+
quoteData: {
|
|
820
|
+
contract: 'SP...contract',
|
|
821
|
+
function: 'get-quote',
|
|
822
|
+
parameters: { amount: 100 },
|
|
823
|
+
},
|
|
824
|
+
swapData: {
|
|
825
|
+
contract: 'SP...swap-contract',
|
|
826
|
+
function: 'swap',
|
|
827
|
+
parameters: {
|
|
828
|
+
'xyk-pools': ['pool1', 'pool2'],
|
|
829
|
+
'stableswap-pools': ['stable-pool1'],
|
|
830
|
+
},
|
|
831
|
+
},
|
|
832
|
+
dexPath: ['BITFLOW_XY_2_xyk', 'BITFLOW_STABLE_XY_2_stable'],
|
|
833
|
+
tokenPath: ['token-x', 'token-y'],
|
|
834
|
+
tokenXDecimals: 6,
|
|
835
|
+
tokenYDecimals: 6,
|
|
836
|
+
}],
|
|
837
|
+
inputData: {
|
|
838
|
+
tokenX: 'token-x',
|
|
839
|
+
tokenY: 'token-y',
|
|
840
|
+
amountInput: 100,
|
|
841
|
+
},
|
|
842
|
+
});
|
|
843
|
+
const result = await sdk.getKeeperAggregatorRouteData('token-x', 'token-y', 100);
|
|
844
|
+
expect(result.xykPoolList).toBeDefined();
|
|
845
|
+
expect(result.stableswapPoolList).toBeDefined();
|
|
846
|
+
});
|
|
847
|
+
it('should handle swaps-reversed parameter', async () => {
|
|
848
|
+
sdk["context"].availableTokens = [
|
|
849
|
+
{
|
|
850
|
+
base: 'base-x',
|
|
851
|
+
type: 'type-x',
|
|
852
|
+
icon: '',
|
|
853
|
+
name: 'Token X',
|
|
854
|
+
status: 'active',
|
|
855
|
+
symbol: 'TKX',
|
|
856
|
+
tokenId: 'token-x',
|
|
857
|
+
"token-id": 'token-x',
|
|
858
|
+
tokenContract: 'contract-x',
|
|
859
|
+
tokenDecimals: 6,
|
|
860
|
+
tokenName: 'Token X',
|
|
861
|
+
wrapTokens: null,
|
|
862
|
+
isKeeperToken: false,
|
|
863
|
+
bridge: 'FALSE',
|
|
864
|
+
layerOneAsset: null,
|
|
865
|
+
priceData: {
|
|
866
|
+
"1h_change": null,
|
|
867
|
+
"1yr_change": null,
|
|
868
|
+
"24h_change": null,
|
|
869
|
+
"30d_change": null,
|
|
870
|
+
"7d_change": null,
|
|
871
|
+
last_price: null,
|
|
872
|
+
last_updated: null,
|
|
873
|
+
},
|
|
874
|
+
},
|
|
875
|
+
{
|
|
876
|
+
base: 'base-y',
|
|
877
|
+
type: 'type-y',
|
|
878
|
+
icon: '',
|
|
879
|
+
name: 'Token Y',
|
|
880
|
+
status: 'active',
|
|
881
|
+
symbol: 'TKY',
|
|
882
|
+
tokenId: 'token-y',
|
|
883
|
+
"token-id": 'token-y',
|
|
884
|
+
tokenContract: 'contract-y',
|
|
885
|
+
tokenDecimals: 8,
|
|
886
|
+
tokenName: 'Token Y',
|
|
887
|
+
wrapTokens: null,
|
|
888
|
+
isKeeperToken: false,
|
|
889
|
+
bridge: 'FALSE',
|
|
890
|
+
layerOneAsset: null,
|
|
891
|
+
priceData: {
|
|
892
|
+
"1h_change": null,
|
|
893
|
+
"1yr_change": null,
|
|
894
|
+
"24h_change": null,
|
|
895
|
+
"30d_change": null,
|
|
896
|
+
"7d_change": null,
|
|
897
|
+
last_price: null,
|
|
898
|
+
last_updated: null,
|
|
899
|
+
},
|
|
900
|
+
},
|
|
901
|
+
];
|
|
902
|
+
// Override the mock for this specific test
|
|
903
|
+
jest.spyOn(BitflowSDK_1.BitflowSDK.prototype, 'getKeeperQuoteForRouteWithoutScaling').mockResolvedValue({
|
|
904
|
+
bestRoute: {
|
|
905
|
+
route: {
|
|
906
|
+
dex_path: ['BITFLOW_XY_2_xyk'],
|
|
907
|
+
token_path: ['token-x', 'token-y'],
|
|
908
|
+
postConditions: {},
|
|
909
|
+
tokenXDecimals: 6,
|
|
910
|
+
tokenYDecimals: 6,
|
|
911
|
+
quoteData: {
|
|
912
|
+
contract: 'SP...contract',
|
|
913
|
+
function: 'get-quote',
|
|
914
|
+
parameters: { amount: 100 },
|
|
915
|
+
},
|
|
916
|
+
swapData: {
|
|
917
|
+
contract: 'SP...swap-contract',
|
|
918
|
+
function: 'swap',
|
|
919
|
+
parameters: {
|
|
920
|
+
'pool-trait': 'SP1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.xyk-pool-v-1-2',
|
|
921
|
+
'swaps-reversed': true,
|
|
922
|
+
},
|
|
923
|
+
},
|
|
924
|
+
},
|
|
925
|
+
quote: 100,
|
|
926
|
+
params: {},
|
|
927
|
+
quoteData: {
|
|
928
|
+
contract: 'SP...contract',
|
|
929
|
+
function: 'get-quote',
|
|
930
|
+
parameters: { amount: 100 },
|
|
931
|
+
},
|
|
932
|
+
swapData: {
|
|
933
|
+
contract: 'SP...swap-contract',
|
|
934
|
+
function: 'swap',
|
|
935
|
+
parameters: {
|
|
936
|
+
'pool-trait': 'SP1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.xyk-pool-v-1-2',
|
|
937
|
+
'swaps-reversed': true,
|
|
938
|
+
},
|
|
939
|
+
},
|
|
940
|
+
dexPath: ['BITFLOW_XY_2_xyk'],
|
|
941
|
+
tokenPath: ['token-x', 'token-y'],
|
|
942
|
+
tokenXDecimals: 6,
|
|
943
|
+
tokenYDecimals: 6,
|
|
944
|
+
},
|
|
945
|
+
allRoutes: [{
|
|
946
|
+
route: {
|
|
947
|
+
dex_path: ['BITFLOW_XY_2_xyk'],
|
|
948
|
+
token_path: ['token-x', 'token-y'],
|
|
949
|
+
postConditions: {},
|
|
950
|
+
tokenXDecimals: 6,
|
|
951
|
+
tokenYDecimals: 6,
|
|
952
|
+
quoteData: {
|
|
953
|
+
contract: 'SP...contract',
|
|
954
|
+
function: 'get-quote',
|
|
955
|
+
parameters: { amount: 100 },
|
|
956
|
+
},
|
|
957
|
+
swapData: {
|
|
958
|
+
contract: 'SP...swap-contract',
|
|
959
|
+
function: 'swap',
|
|
960
|
+
parameters: {
|
|
961
|
+
'pool-trait': 'SP1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.xyk-pool-v-1-2',
|
|
962
|
+
'swaps-reversed': true,
|
|
963
|
+
},
|
|
964
|
+
},
|
|
965
|
+
},
|
|
966
|
+
quote: 100,
|
|
967
|
+
params: {},
|
|
968
|
+
quoteData: {
|
|
969
|
+
contract: 'SP...contract',
|
|
970
|
+
function: 'get-quote',
|
|
971
|
+
parameters: { amount: 100 },
|
|
972
|
+
},
|
|
973
|
+
swapData: {
|
|
974
|
+
contract: 'SP...swap-contract',
|
|
975
|
+
function: 'swap',
|
|
976
|
+
parameters: {
|
|
977
|
+
'pool-trait': 'SP1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR.xyk-pool-v-1-2',
|
|
978
|
+
'swaps-reversed': true,
|
|
979
|
+
},
|
|
980
|
+
},
|
|
981
|
+
dexPath: ['BITFLOW_XY_2_xyk'],
|
|
982
|
+
tokenPath: ['token-x', 'token-y'],
|
|
983
|
+
tokenXDecimals: 6,
|
|
984
|
+
tokenYDecimals: 6,
|
|
985
|
+
}],
|
|
986
|
+
inputData: {
|
|
987
|
+
tokenX: 'token-x',
|
|
988
|
+
tokenY: 'token-y',
|
|
989
|
+
amountInput: 100,
|
|
990
|
+
},
|
|
991
|
+
});
|
|
992
|
+
const result = await sdk.getKeeperAggregatorRouteData('token-x', 'token-y', 100);
|
|
993
|
+
expect(result.xykPoolList).toBeDefined();
|
|
994
|
+
expect(result.actionTrait).toBeDefined();
|
|
995
|
+
expect(result.boolList).toBeDefined();
|
|
996
|
+
});
|
|
997
|
+
it('should handle unsupported DEX path in mapDexPathToActionTrait', async () => {
|
|
998
|
+
// Patch availableTokens so contract identifier lookup does not fail
|
|
999
|
+
sdk["context"].availableTokens = [
|
|
1000
|
+
{
|
|
1001
|
+
base: 'base-x',
|
|
1002
|
+
type: 'type-x',
|
|
1003
|
+
icon: '',
|
|
1004
|
+
name: 'Token X',
|
|
1005
|
+
status: 'active',
|
|
1006
|
+
symbol: 'TKX',
|
|
1007
|
+
tokenId: 'token-x',
|
|
1008
|
+
"token-id": 'token-x',
|
|
1009
|
+
tokenContract: 'contract-x',
|
|
1010
|
+
tokenDecimals: 6,
|
|
1011
|
+
tokenName: 'Token X',
|
|
1012
|
+
wrapTokens: null,
|
|
1013
|
+
isKeeperToken: false,
|
|
1014
|
+
bridge: 'FALSE',
|
|
1015
|
+
layerOneAsset: null,
|
|
1016
|
+
priceData: {
|
|
1017
|
+
"1h_change": null,
|
|
1018
|
+
"1yr_change": null,
|
|
1019
|
+
"24h_change": null,
|
|
1020
|
+
"30d_change": null,
|
|
1021
|
+
"7d_change": null,
|
|
1022
|
+
last_price: null,
|
|
1023
|
+
last_updated: null,
|
|
1024
|
+
},
|
|
1025
|
+
},
|
|
1026
|
+
{
|
|
1027
|
+
base: 'base-y',
|
|
1028
|
+
type: 'type-y',
|
|
1029
|
+
icon: '',
|
|
1030
|
+
name: 'Token Y',
|
|
1031
|
+
status: 'active',
|
|
1032
|
+
symbol: 'TKY',
|
|
1033
|
+
tokenId: 'token-y',
|
|
1034
|
+
"token-id": 'token-y',
|
|
1035
|
+
tokenContract: 'contract-y',
|
|
1036
|
+
tokenDecimals: 8,
|
|
1037
|
+
tokenName: 'Token Y',
|
|
1038
|
+
wrapTokens: null,
|
|
1039
|
+
isKeeperToken: false,
|
|
1040
|
+
bridge: 'FALSE',
|
|
1041
|
+
layerOneAsset: null,
|
|
1042
|
+
priceData: {
|
|
1043
|
+
"1h_change": null,
|
|
1044
|
+
"1yr_change": null,
|
|
1045
|
+
"24h_change": null,
|
|
1046
|
+
"30d_change": null,
|
|
1047
|
+
"7d_change": null,
|
|
1048
|
+
last_price: null,
|
|
1049
|
+
last_updated: null,
|
|
1050
|
+
},
|
|
1051
|
+
},
|
|
1052
|
+
];
|
|
1053
|
+
// Mock getKeeperQuoteForRouteWithoutScaling to return a route with unsupported DEX path
|
|
1054
|
+
jest.spyOn(sdk, 'getKeeperQuoteForRouteWithoutScaling').mockResolvedValue({
|
|
1055
|
+
bestRoute: {
|
|
1056
|
+
route: {
|
|
1057
|
+
dex_path: ['unsupported-dex'],
|
|
1058
|
+
token_path: ['token-x', 'token-y'],
|
|
1059
|
+
postConditions: {},
|
|
1060
|
+
quoteData: { contract: 'test', function: 'test', parameters: {} },
|
|
1061
|
+
swapData: { contract: 'test', function: 'test', parameters: {} },
|
|
1062
|
+
tokenXDecimals: 6,
|
|
1063
|
+
tokenYDecimals: 8,
|
|
1064
|
+
},
|
|
1065
|
+
quote: 100,
|
|
1066
|
+
params: {},
|
|
1067
|
+
quoteData: { contract: 'test', function: 'test', parameters: {} },
|
|
1068
|
+
swapData: { contract: 'test', function: 'test', parameters: {} },
|
|
1069
|
+
dexPath: ['unsupported-dex'],
|
|
1070
|
+
tokenPath: ['token-x', 'token-y'],
|
|
1071
|
+
tokenXDecimals: 6,
|
|
1072
|
+
tokenYDecimals: 8,
|
|
1073
|
+
},
|
|
1074
|
+
allRoutes: [
|
|
1075
|
+
{
|
|
1076
|
+
route: {
|
|
1077
|
+
dex_path: ['unsupported-dex'],
|
|
1078
|
+
token_path: ['token-x', 'token-y'],
|
|
1079
|
+
postConditions: {},
|
|
1080
|
+
quoteData: { contract: 'test', function: 'test', parameters: {} },
|
|
1081
|
+
swapData: { contract: 'test', function: 'test', parameters: {} },
|
|
1082
|
+
tokenXDecimals: 6,
|
|
1083
|
+
tokenYDecimals: 8,
|
|
1084
|
+
},
|
|
1085
|
+
quote: 100,
|
|
1086
|
+
params: {},
|
|
1087
|
+
quoteData: { contract: 'test', function: 'test', parameters: {} },
|
|
1088
|
+
swapData: { contract: 'test', function: 'test', parameters: {} },
|
|
1089
|
+
dexPath: ['unsupported-dex'],
|
|
1090
|
+
tokenPath: ['token-x', 'token-y'],
|
|
1091
|
+
tokenXDecimals: 6,
|
|
1092
|
+
tokenYDecimals: 8,
|
|
1093
|
+
},
|
|
1094
|
+
],
|
|
1095
|
+
inputData: { tokenX: 'token-x', tokenY: 'token-y', amountInput: 100 },
|
|
1096
|
+
});
|
|
1097
|
+
await expect(sdk.getKeeperAggregatorRouteData('token-x', 'token-y', 100)).rejects.toThrow('Unsupported DEX path: unsupported-dex');
|
|
1098
|
+
});
|
|
1099
|
+
it('should handle no routes found in getKeeperAggregatorRouteData', async () => {
|
|
1100
|
+
// Mock getKeeperQuoteForRouteWithoutScaling to return no routes
|
|
1101
|
+
jest.spyOn(sdk, 'getKeeperQuoteForRouteWithoutScaling').mockResolvedValue({
|
|
1102
|
+
bestRoute: null,
|
|
1103
|
+
allRoutes: [],
|
|
1104
|
+
inputData: { tokenX: 'token-x', tokenY: 'token-y', amountInput: 100 },
|
|
1105
|
+
});
|
|
1106
|
+
await expect(sdk.getKeeperAggregatorRouteData('token-x', 'token-y', 100)).rejects.toThrow('No routes found');
|
|
1107
|
+
});
|
|
1108
|
+
it('should handle no best route found in getKeeperAggregatorRouteData', async () => {
|
|
1109
|
+
// Mock getKeeperQuoteForRouteWithoutScaling to return routes but no best route
|
|
1110
|
+
jest.spyOn(sdk, 'getKeeperQuoteForRouteWithoutScaling').mockResolvedValue({
|
|
1111
|
+
bestRoute: null,
|
|
1112
|
+
allRoutes: [
|
|
1113
|
+
{
|
|
1114
|
+
route: {
|
|
1115
|
+
dex_path: ['xyk'],
|
|
1116
|
+
token_path: ['token-x', 'token-y'],
|
|
1117
|
+
postConditions: {},
|
|
1118
|
+
quoteData: { contract: 'test', function: 'test', parameters: {} },
|
|
1119
|
+
swapData: { contract: 'test', function: 'test', parameters: {} },
|
|
1120
|
+
tokenXDecimals: 6,
|
|
1121
|
+
tokenYDecimals: 8,
|
|
1122
|
+
},
|
|
1123
|
+
quote: 100,
|
|
1124
|
+
params: {},
|
|
1125
|
+
quoteData: { contract: 'test', function: 'test', parameters: {} },
|
|
1126
|
+
swapData: { contract: 'test', function: 'test', parameters: {} },
|
|
1127
|
+
dexPath: ['xyk'],
|
|
1128
|
+
tokenPath: ['token-x', 'token-y'],
|
|
1129
|
+
tokenXDecimals: 6,
|
|
1130
|
+
tokenYDecimals: 8,
|
|
1131
|
+
},
|
|
1132
|
+
],
|
|
1133
|
+
inputData: { tokenX: 'token-x', tokenY: 'token-y', amountInput: 100 },
|
|
1134
|
+
});
|
|
1135
|
+
await expect(sdk.getKeeperAggregatorRouteData('token-x', 'token-y', 100)).rejects.toThrow('No best route found for keeper-compatible DEX paths');
|
|
1136
|
+
});
|
|
1137
|
+
it('should handle error in getKeeperAggregatorRouteData', async () => {
|
|
1138
|
+
// Mock getKeeperQuoteForRouteWithoutScaling to throw an error
|
|
1139
|
+
jest.spyOn(sdk, 'getKeeperQuoteForRouteWithoutScaling').mockRejectedValue(new Error('API Error'));
|
|
1140
|
+
await expect(sdk.getKeeperAggregatorRouteData('token-x', 'token-y', 100)).rejects.toThrow('API Error');
|
|
1141
|
+
});
|
|
1142
|
+
});
|
|
1143
|
+
//# sourceMappingURL=BitflowSDK.test.js.map
|