@paraswap/dex-lib 2.14.1 → 2.14.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  2. package/.idea/misc.xml +6 -0
  3. package/.idea/modules.xml +8 -0
  4. package/.idea/vcs.xml +6 -0
  5. package/.vscode/launch.json +21 -0
  6. package/build/dex/aave-v3/tokens/arbitrum.json +50 -0
  7. package/build/dex/aave-v3/tokens/avalanche.json +50 -0
  8. package/build/dex/aave-v3/tokens/fantom.json +62 -0
  9. package/build/dex/aave-v3/tokens/mainnet.json +44 -0
  10. package/build/dex/aave-v3/tokens/optimism.json +50 -0
  11. package/build/dex/aave-v3/tokens/polygon.json +98 -0
  12. package/build/dex/balancer-v2/VirtualBoostedPool.d.ts +79 -0
  13. package/build/dex/balancer-v2/VirtualBoostedPool.js +382 -0
  14. package/build/dex/balancer-v2/VirtualBoostedPool.js.map +1 -0
  15. package/build/dex/generic-rfq/e2e-test-config.d.ts +9 -0
  16. package/build/dex/generic-rfq/e2e-test-config.js +33 -0
  17. package/build/dex/generic-rfq/e2e-test-config.js.map +1 -0
  18. package/build/dex/generic-rfq/rate-fetcher.js +2 -0
  19. package/build/dex/generic-rfq/rate-fetcher.js.map +1 -1
  20. package/build/dex/generic-rfq/validators.d.ts +1 -1
  21. package/build/dex/generic-rfq/validators.js +36 -26
  22. package/build/dex/generic-rfq/validators.js.map +1 -1
  23. package/build/dex/test-aave-v3/config.d.ts +4 -0
  24. package/build/dex/test-aave-v3/config.js +15 -0
  25. package/build/dex/test-aave-v3/config.js.map +1 -0
  26. package/build/dex/test-aave-v3/test-aave-v3-pool.d.ts +39 -0
  27. package/build/dex/test-aave-v3/test-aave-v3-pool.js +63 -0
  28. package/build/dex/test-aave-v3/test-aave-v3-pool.js.map +1 -0
  29. package/build/dex/test-aave-v3/test-aave-v3.d.ts +37 -0
  30. package/build/dex/test-aave-v3/test-aave-v3.js +126 -0
  31. package/build/dex/test-aave-v3/test-aave-v3.js.map +1 -0
  32. package/build/dex/test-aave-v3/types.d.ts +6 -0
  33. package/build/dex/test-aave-v3/types.js +3 -0
  34. package/build/dex/test-aave-v3/types.js.map +1 -0
  35. package/build/lib/fetcher/fetcher.js +3 -0
  36. package/build/lib/fetcher/fetcher.js.map +1 -1
  37. package/package.json +1 -1
  38. package/src/dex/generic-rfq/e2e-test-config.ts +37 -0
  39. package/src/dex/generic-rfq/generic-rfq-e2e.test.ts +63 -258
  40. package/src/dex/generic-rfq/generic-rfq-local-e2e.test.ts +121 -0
  41. package/src/dex/generic-rfq/rate-fetcher.ts +2 -0
  42. package/src/dex/generic-rfq/validators.test.ts +6 -32
  43. package/src/dex/generic-rfq/validators.ts +57 -32
  44. package/src/lib/fetcher/fetcher.ts +6 -0
  45. package/tests/constants-e2e.ts +2 -0
  46. package/tests/utils-e2e.ts +59 -48
@@ -6,8 +6,8 @@ import { Network, ContractMethod, SwapSide, MAX_UINT } from '../../constants';
6
6
  import { generateConfig } from '../../config';
7
7
  import { newTestE2E, getEnv } from '../../../tests/utils-e2e';
8
8
  import { SmartTokens, GENERIC_ADDR1 } from '../../../tests/constants-e2e';
9
- import { startTestServer } from './example-api.test';
10
9
  import { RFQConfig } from './types';
10
+ import { testConfig } from './e2e-test-config';
11
11
 
12
12
  const PK_KEY = process.env.TEST_PK_KEY;
13
13
 
@@ -19,113 +19,13 @@ const testAccount = new ethers.Wallet(PK_KEY!);
19
19
 
20
20
  jest.setTimeout(1000 * 60 * 3);
21
21
 
22
- describe('GenericRFQ E2E Mainnet', () => {
23
- let stopServer: undefined | Function = undefined;
24
-
25
- beforeAll(() => {
26
- stopServer = startTestServer(testAccount);
27
- });
28
-
29
- const network = Network.MAINNET;
30
- const smartTokens = SmartTokens[network];
31
-
32
- const srcToken = smartTokens.WETH;
33
- const destToken = smartTokens.DAI;
34
-
35
- const config = generateConfig(network);
36
-
37
- describe('GenericRFQ', () => {
38
- const dexKey = 'DummyParaSwapPool';
39
-
40
- srcToken.addBalance(testAccount.address, MAX_UINT);
41
- srcToken.addAllowance(
42
- testAccount.address,
43
- config.augustusRFQAddress,
44
- MAX_UINT,
45
- );
46
-
47
- destToken.addBalance(testAccount.address, MAX_UINT);
48
- destToken.addAllowance(
49
- testAccount.address,
50
- config.augustusRFQAddress,
51
- MAX_UINT,
52
- );
53
-
54
- describe('Simpleswap', () => {
55
- it('SELL WETH -> DAI', async () => {
56
- await newTestE2E({
57
- config,
58
- srcToken,
59
- destToken,
60
- senderAddress: GENERIC_ADDR1,
61
- thirdPartyAddress: testAccount.address,
62
- _amount: '1000000000000000000',
63
- swapSide: SwapSide.SELL,
64
- dexKey: dexKey,
65
- contractMethod: ContractMethod.simpleSwap,
66
- network: network,
67
- });
68
- });
69
-
70
- it('SELL DAI -> WETH', async () => {
71
- await newTestE2E({
72
- config,
73
- destToken,
74
- srcToken,
75
- senderAddress: GENERIC_ADDR1,
76
- thirdPartyAddress: testAccount.address,
77
- _amount: '1000000000000000000',
78
- swapSide: SwapSide.SELL,
79
- dexKey: dexKey,
80
- contractMethod: ContractMethod.simpleSwap,
81
- network: network,
82
- });
83
- });
84
-
85
- it('BUY WETH -> DAI', async () => {
86
- await newTestE2E({
87
- config,
88
- srcToken,
89
- destToken,
90
- senderAddress: GENERIC_ADDR1,
91
- thirdPartyAddress: testAccount.address,
92
- _amount: '1000000000000000000',
93
- swapSide: SwapSide.BUY,
94
- dexKey: dexKey,
95
- contractMethod: ContractMethod.simpleBuy,
96
- network: network,
97
- });
98
- });
99
-
100
- it('BUY DAI -> WETH', async () => {
101
- await newTestE2E({
102
- config,
103
- destToken,
104
- srcToken,
105
- senderAddress: GENERIC_ADDR1,
106
- thirdPartyAddress: testAccount.address,
107
- _amount: '1000000000000000000',
108
- swapSide: SwapSide.BUY,
109
- dexKey: dexKey,
110
- contractMethod: ContractMethod.simpleBuy,
111
- network: network,
112
- });
113
- });
114
- });
115
- });
116
-
117
- afterAll(() => {
118
- if (stopServer) {
119
- stopServer();
120
- }
121
- });
122
- });
123
-
124
22
  const buildConfigForGenericRFQ = (): RFQConfig => {
125
23
  const url = getEnv('GENERIC_RFQ_URL');
126
24
 
127
25
  const secret = {
128
- secretKey: atob(getEnv('GENERIC_RFQ_SECRET_KEY')),
26
+ secretKey: Buffer.from(getEnv('GENERIC_RFQ_SECRET_KEY'), 'base64').toString(
27
+ 'binary',
28
+ ),
129
29
  accessKey: getEnv('GENERIC_RFQ_ACCESS_KEY'),
130
30
  domain: 'paraswap',
131
31
  };
@@ -179,160 +79,65 @@ const buildConfigForGenericRFQ = (): RFQConfig => {
179
79
  };
180
80
  };
181
81
 
182
- describe('GenericRFQ YOUR_NAME E2E Mainnet', () => {
183
- const dexKey = 'YOUR_NAME';
184
-
185
- const network = Network.MAINNET;
186
- const smartTokens = SmartTokens[network];
187
- const config = generateConfig(network);
188
-
189
- config.rfqConfigs[dexKey] = buildConfigForGenericRFQ();
190
-
191
- describe('GenericRFQ B/Q BUY', () => {
192
- const srcToken = smartTokens.USDC;
193
- const destToken = smartTokens.WBTC;
194
-
195
- srcToken.addBalance(testAccount.address, MAX_UINT);
196
- srcToken.addAllowance(
197
- testAccount.address,
198
- config.augustusRFQAddress,
199
- MAX_UINT,
200
- );
201
-
202
- destToken.addBalance(testAccount.address, MAX_UINT);
203
- destToken.addAllowance(
204
- testAccount.address,
205
- config.augustusRFQAddress,
206
- MAX_UINT,
207
- );
208
-
209
- describe('Simpleswap', () => {
210
- it('BUY USDC -> WBTC', async () => {
211
- await newTestE2E({
212
- config,
213
- srcToken,
214
- destToken,
215
- senderAddress: GENERIC_ADDR1,
216
- thirdPartyAddress: testAccount.address,
217
- _amount: '1000000',
218
- swapSide: SwapSide.BUY,
219
- dexKey: dexKey,
220
- contractMethod: ContractMethod.simpleBuy,
221
- network: network,
222
- sleepMs: 5000,
223
- });
224
- });
225
- });
226
- });
227
-
228
- describe('GenericRFQ Q/B BUY', () => {
229
- const srcToken = smartTokens.WBTC;
230
- const destToken = smartTokens.USDC;
231
-
232
- srcToken.addBalance(testAccount.address, MAX_UINT);
233
- srcToken.addAllowance(
234
- testAccount.address,
235
- config.augustusRFQAddress,
236
- MAX_UINT,
237
- );
238
-
239
- destToken.addBalance(testAccount.address, MAX_UINT);
240
- destToken.addAllowance(
241
- testAccount.address,
242
- config.augustusRFQAddress,
243
- MAX_UINT,
244
- );
245
-
246
- describe('Simpleswap', () => {
247
- it('BUY WBTC -> USDC', async () => {
248
- await newTestE2E({
249
- config,
250
- srcToken,
251
- destToken,
252
- senderAddress: GENERIC_ADDR1,
253
- thirdPartyAddress: testAccount.address,
254
- _amount: '1000000',
255
- swapSide: SwapSide.BUY,
256
- dexKey: dexKey,
257
- contractMethod: ContractMethod.simpleBuy,
258
- network: network,
259
- sleepMs: 5000,
260
- });
261
- });
262
- });
263
- });
264
-
265
- describe('GenericRFQ B/Q SELL', () => {
266
- const srcToken = smartTokens.USDC;
267
- const destToken = smartTokens.WBTC;
268
-
269
- srcToken.addBalance(testAccount.address, MAX_UINT);
270
- srcToken.addAllowance(
271
- testAccount.address,
272
- config.augustusRFQAddress,
273
- MAX_UINT,
274
- );
275
-
276
- destToken.addBalance(testAccount.address, MAX_UINT);
277
- destToken.addAllowance(
278
- testAccount.address,
279
- config.augustusRFQAddress,
280
- MAX_UINT,
281
- );
282
-
283
- describe('Simpleswap', () => {
284
- it('SELL USDC -> WBTC', async () => {
285
- await newTestE2E({
286
- config,
287
- srcToken,
288
- destToken,
289
- senderAddress: GENERIC_ADDR1,
290
- thirdPartyAddress: testAccount.address,
291
- _amount: '1000000',
292
- swapSide: SwapSide.SELL,
293
- dexKey: dexKey,
294
- contractMethod: ContractMethod.simpleSwap,
295
- network: network,
296
- sleepMs: 5000,
297
- });
298
- });
299
- });
300
- });
301
-
302
- describe('GenericRFQ Q/B SELL', () => {
303
- const srcToken = smartTokens.WBTC;
304
- const destToken = smartTokens.USDC;
305
-
306
- srcToken.addBalance(testAccount.address, MAX_UINT);
307
- srcToken.addAllowance(
308
- testAccount.address,
309
- config.augustusRFQAddress,
310
- MAX_UINT,
311
- );
312
-
313
- destToken.addBalance(testAccount.address, MAX_UINT);
314
- destToken.addAllowance(
315
- testAccount.address,
316
- config.augustusRFQAddress,
317
- MAX_UINT,
318
- );
319
-
320
- describe('Simpleswap', () => {
321
- it('SELL WBTC -> USDC', async () => {
322
- await newTestE2E({
323
- config,
324
- srcToken,
325
- destToken,
326
- senderAddress: GENERIC_ADDR1,
327
- thirdPartyAddress: testAccount.address,
328
- _amount: '10000',
329
- swapSide: SwapSide.SELL,
330
- dexKey: dexKey,
331
- contractMethod: ContractMethod.simpleSwap,
332
- network: network,
333
- sleepMs: 5000,
82
+ const SKIP_TENDERLY = !!getEnv('GENERIC_RFQ_SKIP_TENDERLY', true);
83
+ const dexKey = 'YOUR_NAME';
84
+
85
+ describe(`GenericRFQ ${dexKey} E2E`, () => {
86
+ for (const [_network, testCases] of Object.entries(testConfig)) {
87
+ const network = parseInt(_network, 10);
88
+ const smartTokens = SmartTokens[network];
89
+ const config = generateConfig(network);
90
+
91
+ config.rfqConfigs[dexKey] = buildConfigForGenericRFQ();
92
+ describe(`${Network[network]}`, () => {
93
+ for (const testCase of testCases) {
94
+ if (!smartTokens.hasOwnProperty(testCase.srcToken)) {
95
+ throw new Error(`Please add "addBalance" and "addAllowance" functions for ${testCase.srcToken} on ${Network[network]} (in constants-e2e.ts).`);
96
+ }
97
+ if (!smartTokens.hasOwnProperty(testCase.destToken)){
98
+ throw new Error(`Please add "addBalance" and "addAllowance" functions for ${testCase.destToken} on ${Network[network]} (in constants-e2e.ts).`);
99
+ }
100
+ const srcToken = smartTokens[testCase.srcToken];
101
+ const destToken = smartTokens[testCase.destToken];
102
+
103
+ if (!SKIP_TENDERLY) {
104
+ srcToken.addBalance(testAccount.address, MAX_UINT);
105
+ srcToken.addAllowance(
106
+ testAccount.address,
107
+ config.augustusRFQAddress,
108
+ MAX_UINT,
109
+ );
110
+
111
+ destToken.addBalance(testAccount.address, MAX_UINT);
112
+ destToken.addAllowance(
113
+ testAccount.address,
114
+ config.augustusRFQAddress,
115
+ MAX_UINT,
116
+ );
117
+ }
118
+ const contractMethod =
119
+ testCase.swapSide === SwapSide.BUY
120
+ ? ContractMethod.simpleBuy
121
+ : ContractMethod.simpleSwap;
122
+ describe(`${contractMethod}`, () => {
123
+ it(`${testCase.swapSide} ${testCase.srcToken} -> ${testCase.destToken}`, async () => {
124
+ await newTestE2E({
125
+ config,
126
+ srcToken,
127
+ destToken,
128
+ senderAddress: GENERIC_ADDR1,
129
+ thirdPartyAddress: testAccount.address,
130
+ _amount: testCase.amount,
131
+ swapSide: testCase.swapSide as SwapSide,
132
+ dexKey: dexKey,
133
+ contractMethod,
134
+ network,
135
+ sleepMs: 5000,
136
+ skipTenderly: SKIP_TENDERLY,
137
+ });
138
+ });
334
139
  });
335
- });
140
+ }
336
141
  });
337
- });
142
+ }
338
143
  });
@@ -0,0 +1,121 @@
1
+ import dotenv from 'dotenv';
2
+ dotenv.config();
3
+
4
+ import { ethers } from 'ethers';
5
+ import { Network, ContractMethod, SwapSide, MAX_UINT } from '../../constants';
6
+ import { generateConfig } from '../../config';
7
+ import { newTestE2E } from '../../../tests/utils-e2e';
8
+ import { SmartTokens, GENERIC_ADDR1 } from '../../../tests/constants-e2e';
9
+ import { startTestServer } from './example-api.test';
10
+
11
+ const PK_KEY = process.env.TEST_PK_KEY;
12
+
13
+ if (!PK_KEY) {
14
+ throw new Error('Missing TEST_PK_KEY');
15
+ }
16
+
17
+ const testAccount = new ethers.Wallet(PK_KEY!);
18
+
19
+ jest.setTimeout(1000 * 60 * 3);
20
+
21
+ describe('GenericRFQ E2E Mainnet', () => {
22
+ let stopServer: undefined | Function = undefined;
23
+
24
+ beforeAll(() => {
25
+ stopServer = startTestServer(testAccount);
26
+ });
27
+
28
+ const network = Network.MAINNET;
29
+ const smartTokens = SmartTokens[network];
30
+
31
+ const srcToken = smartTokens.WETH;
32
+ const destToken = smartTokens.DAI;
33
+
34
+ const config = generateConfig(network);
35
+
36
+ describe('GenericRFQ', () => {
37
+ const dexKey = 'DummyParaSwapPool';
38
+
39
+ srcToken.addBalance(testAccount.address, MAX_UINT);
40
+ srcToken.addAllowance(
41
+ testAccount.address,
42
+ config.augustusRFQAddress,
43
+ MAX_UINT,
44
+ );
45
+
46
+ destToken.addBalance(testAccount.address, MAX_UINT);
47
+ destToken.addAllowance(
48
+ testAccount.address,
49
+ config.augustusRFQAddress,
50
+ MAX_UINT,
51
+ );
52
+
53
+ describe('Simpleswap', () => {
54
+ it('SELL WETH -> DAI', async () => {
55
+ await newTestE2E({
56
+ config,
57
+ srcToken,
58
+ destToken,
59
+ senderAddress: GENERIC_ADDR1,
60
+ thirdPartyAddress: testAccount.address,
61
+ _amount: '1000000000000000000',
62
+ swapSide: SwapSide.SELL,
63
+ dexKey: dexKey,
64
+ contractMethod: ContractMethod.simpleSwap,
65
+ network: network,
66
+ });
67
+ });
68
+
69
+ it('SELL DAI -> WETH', async () => {
70
+ await newTestE2E({
71
+ config,
72
+ destToken,
73
+ srcToken,
74
+ senderAddress: GENERIC_ADDR1,
75
+ thirdPartyAddress: testAccount.address,
76
+ _amount: '1000000000000000000',
77
+ swapSide: SwapSide.SELL,
78
+ dexKey: dexKey,
79
+ contractMethod: ContractMethod.simpleSwap,
80
+ network: network,
81
+ });
82
+ });
83
+
84
+ it('BUY WETH -> DAI', async () => {
85
+ await newTestE2E({
86
+ config,
87
+ srcToken,
88
+ destToken,
89
+ senderAddress: GENERIC_ADDR1,
90
+ thirdPartyAddress: testAccount.address,
91
+ _amount: '1000000000000000000',
92
+ swapSide: SwapSide.BUY,
93
+ dexKey: dexKey,
94
+ contractMethod: ContractMethod.simpleBuy,
95
+ network: network,
96
+ });
97
+ });
98
+
99
+ it('BUY DAI -> WETH', async () => {
100
+ await newTestE2E({
101
+ config,
102
+ destToken,
103
+ srcToken,
104
+ senderAddress: GENERIC_ADDR1,
105
+ thirdPartyAddress: testAccount.address,
106
+ _amount: '1000000000000000000',
107
+ swapSide: SwapSide.BUY,
108
+ dexKey: dexKey,
109
+ contractMethod: ContractMethod.simpleBuy,
110
+ network: network,
111
+ });
112
+ });
113
+ });
114
+ });
115
+
116
+ afterAll(() => {
117
+ if (stopServer) {
118
+ stopServer();
119
+ }
120
+ });
121
+ });
@@ -403,9 +403,11 @@ export class RateFetcher {
403
403
  delete payload.secret;
404
404
  }
405
405
 
406
+ this.logger.info('FirmRate Request:', payload);
406
407
  const { data } = await this.dexHelper.httpRequest.request<unknown>(
407
408
  payload,
408
409
  );
410
+ this.logger.info('FirmRate Response: ', data);
409
411
 
410
412
  const firmRateResp = validateAndCast<RFQFirmRateResponse>(
411
413
  data,
@@ -112,10 +112,11 @@ describe('GenericRFQ Validator test', () => {
112
112
  },
113
113
  };
114
114
 
115
- const pricesInvalidBidsNotSortedDesc = {
115
+ const pricesNegativeSpread = {
116
116
  prices: {
117
117
  'WETH/DAI': {
118
118
  bids: [
119
+ ['1337.425240000000000000', '1.166200000000000000'],
119
120
  ['1333.024812000000000000', '1.166200000000000000'],
120
121
  ['1333.425240000000000000', '1.166200000000000000'],
121
122
  ['1332.624384000000000000', '1.166200000000000000'],
@@ -135,29 +136,6 @@ describe('GenericRFQ Validator test', () => {
135
136
  },
136
137
  };
137
138
 
138
- const pricesInvalidAskNotSortedAsc = {
139
- prices: {
140
- 'WETH/DAI': {
141
- bids: [
142
- ['1333.425240000000000000', '1.166200000000000000'],
143
- ['1333.024812000000000000', '1.166200000000000000'],
144
- ['1332.624384000000000000', '1.166200000000000000'],
145
- ['1332.223956000000000000', '1.166200000000000000'],
146
- ['1331.823528000000000000', '1.166200000000000000'],
147
- ['1331.423100000000000000', '1.169000000000000000'],
148
- ],
149
- asks: [
150
- ['1337.146033000000000000', '1.166200000000000000'],
151
- ['1336.745410000000000000', '1.166200000000000000'],
152
- ['1337.546656000000000000', '1.166200000000000000'],
153
- ['1337.947279000000000000', '1.166200000000000000'],
154
- ['1338.347902000000000000', '1.166200000000000000'],
155
- ['1338.748525000000000000', '1.169000000000000000'],
156
- ],
157
- },
158
- },
159
- };
160
-
161
139
  const noPrices = {
162
140
  prices: {
163
141
  'WETH/DAI': {},
@@ -200,12 +178,6 @@ describe('GenericRFQ Validator test', () => {
200
178
 
201
179
  it('Price test', () => {
202
180
  expect(() => validateAndCast(prices, pricesResponse)).not.toThrowError();
203
- expect(() =>
204
- validateAndCast(pricesInvalidBidsNotSortedDesc, pricesResponse),
205
- ).toThrowError();
206
- expect(() =>
207
- validateAndCast(pricesInvalidAskNotSortedAsc, pricesResponse),
208
- ).toThrowError();
209
181
  expect(() =>
210
182
  validateAndCast(noPrices, pricesResponse),
211
183
  ).not.toThrowError();
@@ -218,6 +190,9 @@ describe('GenericRFQ Validator test', () => {
218
190
  expect(() =>
219
191
  validateAndCast(onlyAsks, pricesResponse),
220
192
  ).not.toThrowError();
193
+ expect(() =>
194
+ validateAndCast(pricesNegativeSpread, pricesResponse),
195
+ ).toThrowError('the maximum bid is higher than minimum ask');
221
196
  });
222
197
  });
223
198
 
@@ -261,11 +236,10 @@ describe('GenericRFQ Validator test', () => {
261
236
  },
262
237
  };
263
238
 
264
- it('Blacklist test', () => {
239
+ it('Order test', () => {
265
240
  expect(() =>
266
241
  validateAndCast(order, firmRateResponseValidator),
267
242
  ).not.toThrowError();
268
- // expect(() => validateAndCast(invalidBlacklist, blacklistResponseValidator)).toThrowError();
269
243
  });
270
244
  });
271
245
  });
@@ -56,7 +56,7 @@ const stringNumberValidator = (
56
56
  return value;
57
57
  };
58
58
 
59
- const pricesValidatorWithoutSorting = joi
59
+ const pricesValidator = joi
60
60
  .array()
61
61
  .items(
62
62
  joi
@@ -66,47 +66,58 @@ const pricesValidatorWithoutSorting = joi
66
66
  );
67
67
 
68
68
  const ext: joi.Extension = {
69
- type: 'sortedArray',
70
- base: pricesValidatorWithoutSorting,
69
+ type: 'validatedPrices',
70
+ base: joi.object({
71
+ bids: pricesValidator,
72
+ asks: pricesValidator,
73
+ }),
71
74
  rules: {
72
- asc: {
73
- validate: (values: string[], helpers: CustomHelpers) => {
74
- const prices = values.map(numbers => new BigNumber(numbers[0]));
75
- const isAscOrder = prices.every(
76
- (x, i) => i === 0 || x.gte(prices[i - 1]),
77
- );
78
- return isAscOrder
75
+ bidsLowerThanAsks: {
76
+ validate: (
77
+ values: { bids: string[]; asks: string[] },
78
+ helpers: CustomHelpers,
79
+ ) => {
80
+ if (
81
+ !values.bids ||
82
+ !values.asks ||
83
+ values.bids.length === 0 ||
84
+ values.asks.length === 0
85
+ ) {
86
+ return values;
87
+ }
88
+ const maxBid = values.bids
89
+ .map(numbers => new BigNumber(numbers[0]))
90
+ .reduce(
91
+ (previousValue, currentValue) =>
92
+ currentValue.gte(previousValue) ? currentValue : previousValue,
93
+ new BigNumber(0),
94
+ );
95
+ const minAsk = values.asks
96
+ .map(numbers => new BigNumber(numbers[0]))
97
+ .reduce(
98
+ (previousValue, currentValue) =>
99
+ currentValue.lte(previousValue) ? currentValue : previousValue,
100
+ new BigNumber('123456789012345678901234567890'),
101
+ );
102
+ return maxBid < minAsk
79
103
  ? values
80
104
  : helpers.message({
81
- custom: `array is not asc sorted ${JSON.stringify(values)}`,
82
- });
83
- },
84
- },
85
- desc: {
86
- validate: (values: string[][], helpers: CustomHelpers) => {
87
- const prices = values.map(numbers => new BigNumber(numbers[0]));
88
- const isAscOrder = prices.every(
89
- (x, i) => i === 0 || x.lte(prices[i - 1]),
90
- );
91
- return isAscOrder
92
- ? values
93
- : helpers.message({
94
- custom: `array is not desc sorted ${JSON.stringify(values)}`,
105
+ custom: 'the maximum bid is higher than minimum ask',
95
106
  });
96
107
  },
97
108
  },
98
109
  },
99
110
  };
100
111
 
101
- const pricesArrayValidator = joi.extend(ext);
102
-
103
- export const priceValidator = joi.object({
104
- bids: pricesArrayValidator.sortedArray().desc(),
105
- asks: pricesArrayValidator.sortedArray().asc(),
106
- });
112
+ export const priceValidator = joi.extend(ext);
107
113
 
108
114
  export const pricesResponse = joi.object({
109
- prices: joi.object().pattern(joi.string().min(1), priceValidator),
115
+ prices: joi
116
+ .object()
117
+ .pattern(
118
+ joi.string().min(1),
119
+ priceValidator.validatedPrices().bidsLowerThanAsks(),
120
+ ),
110
121
  });
111
122
 
112
123
  export const validateAndCast = <T>(
@@ -171,12 +182,26 @@ const stringStartWithHex0x = (
171
182
  return value;
172
183
  };
173
184
 
185
+ const mustBeAugustusSwapper = (
186
+ value: string,
187
+ helpers: CustomHelpers,
188
+ ): string | ErrorReport => {
189
+ const allowedTakers = [
190
+ '0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57'.toLowerCase(),
191
+ ];
192
+ return allowedTakers.includes(value.toLowerCase())
193
+ ? value
194
+ : helpers.message({
195
+ custom: `"order.taker" must be any of ${JSON.stringify(allowedTakers)}`,
196
+ });
197
+ };
198
+
174
199
  export const orderWithSignatureValidator = joi
175
200
  .object({
176
201
  nonceAndMeta: joi.string().custom(stringPositiveBigIntValidator),
177
202
  expiry: joi.number().min(0),
178
203
  maker: addressSchema.required(),
179
- taker: addressSchema.required(),
204
+ taker: addressSchema.required().custom(mustBeAugustusSwapper),
180
205
  makerAsset: addressSchema.required(),
181
206
  takerAsset: addressSchema.required(),
182
207
  makerAmount: joi
@@ -76,6 +76,12 @@ export default class Fetcher<T> {
76
76
  .map((_, i) => i)
77
77
  .filter(i => results[i] instanceof Error);
78
78
 
79
+ results.map(result => {
80
+ this.logger.info(
81
+ 'Results Data:',
82
+ JSON.stringify((result as any).data, null, 4).substring(0, 500),
83
+ );
84
+ });
79
85
  failures.forEach(i => {
80
86
  this.logger.warn(
81
87
  `failed polling ${this.requests[i].info.requestOptions.url} ${results[i]}`,