Skip to content

Commit 1b207d6

Browse files
authored
Merge pull request #93 from ExchangeUnion/feat/config-hardening
feat(config): harden configuration checks
2 parents 77c37a8 + 5149573 commit 1b207d6

File tree

3 files changed

+136
-61
lines changed

3 files changed

+136
-61
lines changed
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`checkConfigOptions does not allow LTC/LTC trading pair 1`] = `"Invalid trading pair LTC/LTC. Supported trading pairs are: ETH/BTC, BTC/USDT, LTC/BTC, LTC/USDT"`;
3+
exports[`checkConfigOptions LIVE_CEX disabled does not allow LTC/LTC trading pair 1`] = `"Invalid trading pair LTC/LTC. Supported trading pairs are: ETH/BTC, BTC/USDT, LTC/BTC, LTC/USDT"`;
4+
5+
exports[`checkConfigOptions LIVE_CEX disabled requires TEST_CENTRALIZED_EXCHANGE_BASEASSET_BALANCE 1`] = `"Incomplete configuration. Please add the following options to .env or as environment variables: TEST_CENTRALIZED_EXCHANGE_BASEASSET_BALANCE"`;
6+
7+
exports[`checkConfigOptions LIVE_CEX disabled requires TEST_CENTRALIZED_EXCHANGE_QUOTEASSET_BALANCE 1`] = `"Incomplete configuration. Please add the following options to .env or as environment variables: TEST_CENTRALIZED_EXCHANGE_QUOTEASSET_BALANCE"`;
8+
9+
exports[`checkConfigOptions LIVE_CEX enabled requires CEX_API_KEY 1`] = `"Incomplete configuration. Please add the following options to .env or as environment variables: CEX_API_KEY"`;
10+
11+
exports[`checkConfigOptions LIVE_CEX enabled requires CEX_API_SECRET 1`] = `"Incomplete configuration. Please add the following options to .env or as environment variables: CEX_API_SECRET"`;

src/config.spec.ts

Lines changed: 98 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
import { checkConfigOptions } from './config';
22

33
describe('checkConfigOptions', () => {
4-
it('allows BTC/USDT trading pair', () => {
5-
const dotEnvConfig = {
4+
describe('LIVE_CEX disabled', () => {
5+
const validLiveCEXdisabledConf = {
66
LOG_LEVEL: 'trace',
77
CEX: 'Binance',
8-
CEX_API_KEY: '123',
9-
CEX_API_SECRET: 'abc',
108
DATA_DIR: '/some/data/path',
119
OPENDEX_CERT_PATH: '/some/cert/path',
1210
OPENDEX_RPC_HOST: 'localhost',
@@ -18,39 +16,62 @@ describe('checkConfigOptions', () => {
1816
TEST_CENTRALIZED_EXCHANGE_QUOTEASSET_BALANCE: '123',
1917
LIVE_CEX: 'false',
2018
};
21-
const verifiedConfig = checkConfigOptions(dotEnvConfig);
22-
expect(verifiedConfig).toEqual({
23-
...dotEnvConfig,
24-
LIVE_CEX: false,
19+
20+
it('allows BTC/USDT', () => {
21+
expect.assertions(1);
22+
const config = checkConfigOptions(validLiveCEXdisabledConf);
23+
expect(config).toEqual({
24+
...config,
25+
LIVE_CEX: false,
26+
});
2527
});
26-
});
2728

28-
it('allows ETH/BTC trading pair', () => {
29-
const dotEnvConfig = {
30-
LOG_LEVEL: 'trace',
31-
CEX: 'Binance',
32-
CEX_API_KEY: '123',
33-
CEX_API_SECRET: 'abc',
34-
DATA_DIR: '/some/data/path',
35-
OPENDEX_CERT_PATH: '/some/cert/path',
36-
OPENDEX_RPC_HOST: 'localhost',
37-
OPENDEX_RPC_PORT: '1234',
38-
MARGIN: '0.06',
39-
BASEASSET: 'ETH',
40-
QUOTEASSET: 'BTC',
41-
TEST_CENTRALIZED_EXCHANGE_BASEASSET_BALANCE: '321',
42-
TEST_CENTRALIZED_EXCHANGE_QUOTEASSET_BALANCE: '123',
43-
LIVE_CEX: 'false',
44-
};
45-
const verifiedConfig = checkConfigOptions(dotEnvConfig);
46-
expect(verifiedConfig).toEqual({
47-
...dotEnvConfig,
48-
LIVE_CEX: false,
29+
it('allows ETH/BTC trading pair', () => {
30+
const config = checkConfigOptions({
31+
...validLiveCEXdisabledConf,
32+
...{ BASEASSET: 'ETH', QUOTEASSET: 'BTC' },
33+
});
34+
expect(config).toEqual({
35+
...config,
36+
LIVE_CEX: false,
37+
});
38+
});
39+
40+
it('does not allow LTC/LTC trading pair', () => {
41+
const config = {
42+
...validLiveCEXdisabledConf,
43+
...{ BASEASSET: 'LTC', QUOTEASSET: 'LTC' },
44+
};
45+
expect(() => {
46+
checkConfigOptions(config);
47+
}).toThrowErrorMatchingSnapshot();
48+
});
49+
50+
it('requires TEST_CENTRALIZED_EXCHANGE_BASEASSET_BALANCE', () => {
51+
expect.assertions(1);
52+
const config = {
53+
...validLiveCEXdisabledConf,
54+
};
55+
delete config.TEST_CENTRALIZED_EXCHANGE_BASEASSET_BALANCE;
56+
expect(() => {
57+
checkConfigOptions(config);
58+
}).toThrowErrorMatchingSnapshot();
59+
});
60+
61+
it('requires TEST_CENTRALIZED_EXCHANGE_QUOTEASSET_BALANCE', () => {
62+
expect.assertions(1);
63+
const config = {
64+
...validLiveCEXdisabledConf,
65+
};
66+
delete config.TEST_CENTRALIZED_EXCHANGE_QUOTEASSET_BALANCE;
67+
expect(() => {
68+
checkConfigOptions(config);
69+
}).toThrowErrorMatchingSnapshot();
4970
});
5071
});
5172

52-
it('does not allow LTC/LTC trading pair', () => {
53-
const dotEnvConfig = {
73+
describe('LIVE_CEX enabled', () => {
74+
const validLiveCEXenabledConf = {
5475
LOG_LEVEL: 'trace',
5576
CEX: 'Binance',
5677
CEX_API_KEY: '123',
@@ -60,14 +81,51 @@ describe('checkConfigOptions', () => {
6081
OPENDEX_RPC_HOST: 'localhost',
6182
OPENDEX_RPC_PORT: '1234',
6283
MARGIN: '0.06',
63-
BASEASSET: 'LTC',
64-
QUOTEASSET: 'LTC',
65-
TEST_CENTRALIZED_EXCHANGE_BASEASSET_BALANCE: '321',
66-
TEST_CENTRALIZED_EXCHANGE_QUOTEASSET_BALANCE: '123',
67-
LIVE_CEX: 'false',
84+
BASEASSET: 'BTC',
85+
QUOTEASSET: 'USDT',
86+
LIVE_CEX: 'true',
6887
};
69-
expect(() => {
70-
checkConfigOptions(dotEnvConfig);
71-
}).toThrowErrorMatchingSnapshot();
88+
89+
it('allows BTC/USDT', () => {
90+
expect.assertions(1);
91+
const config = checkConfigOptions(validLiveCEXenabledConf);
92+
expect(config).toEqual({
93+
...config,
94+
LIVE_CEX: true,
95+
});
96+
});
97+
98+
it('allows ETH/BTC trading pair', () => {
99+
const config = checkConfigOptions({
100+
...validLiveCEXenabledConf,
101+
...{ BASEASSET: 'ETH', QUOTEASSET: 'BTC' },
102+
});
103+
expect(config).toEqual({
104+
...config,
105+
LIVE_CEX: true,
106+
});
107+
});
108+
109+
it('requires CEX_API_KEY', () => {
110+
expect.assertions(1);
111+
const config = {
112+
...validLiveCEXenabledConf,
113+
};
114+
delete config.CEX_API_KEY;
115+
expect(() => {
116+
checkConfigOptions(config);
117+
}).toThrowErrorMatchingSnapshot();
118+
});
119+
120+
it('requires CEX_API_SECRET', () => {
121+
expect.assertions(1);
122+
const config = {
123+
...validLiveCEXenabledConf,
124+
};
125+
delete config.CEX_API_SECRET;
126+
expect(() => {
127+
checkConfigOptions(config);
128+
}).toThrowErrorMatchingSnapshot();
129+
});
72130
});
73131
});

src/config.ts

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,24 @@ export type Config = {
2424
const REQUIRED_CONFIGURATION_OPTIONS = [
2525
'LOG_LEVEL',
2626
'CEX',
27-
'CEX_API_KEY',
28-
'CEX_API_SECRET',
2927
'DATA_DIR',
3028
'OPENDEX_CERT_PATH',
3129
'OPENDEX_RPC_HOST',
3230
'OPENDEX_RPC_PORT',
3331
'MARGIN',
3432
'BASEASSET',
3533
'QUOTEASSET',
34+
'LIVE_CEX',
35+
];
36+
37+
const REQUIRED_CONFIGURATION_OPTIONS_LIVE_CEX_ENABLED = [
38+
'CEX_API_KEY',
39+
'CEX_API_SECRET',
40+
];
41+
42+
const REQUIRED_CONFIGURATION_OPTIONS_LIVE_CEX_DISABLED = [
3643
'TEST_CENTRALIZED_EXCHANGE_BASEASSET_BALANCE',
3744
'TEST_CENTRALIZED_EXCHANGE_QUOTEASSET_BALANCE',
38-
'LIVE_CEX',
3945
];
4046

4147
const setLogLevel = (logLevel: string): Level => {
@@ -48,31 +54,34 @@ const setLogLevel = (logLevel: string): Level => {
4854
};
4955

5056
const getEnvironmentConfig = (): DotenvParseOutput => {
51-
const environmentConfig = REQUIRED_CONFIGURATION_OPTIONS.reduce(
52-
(envConfig: DotenvParseOutput, configOption) => {
53-
if (process.env[configOption]) {
54-
return {
55-
...envConfig,
56-
[configOption]: process.env[configOption]!,
57-
};
58-
}
59-
return envConfig;
60-
},
61-
{}
62-
);
57+
const environmentConfig = REQUIRED_CONFIGURATION_OPTIONS.concat(
58+
REQUIRED_CONFIGURATION_OPTIONS_LIVE_CEX_ENABLED,
59+
REQUIRED_CONFIGURATION_OPTIONS_LIVE_CEX_DISABLED
60+
).reduce((envConfig: DotenvParseOutput, configOption) => {
61+
if (process.env[configOption]) {
62+
return {
63+
...envConfig,
64+
[configOption]: process.env[configOption]!,
65+
};
66+
}
67+
return envConfig;
68+
}, {});
6369
return environmentConfig;
6470
};
6571

6672
const getMissingOptions = (config: DotenvParseOutput): string => {
67-
return REQUIRED_CONFIGURATION_OPTIONS.reduce(
68-
(missingOptions: string[], configOption) => {
73+
const ADDITIONAL_CONF_OPTIONS =
74+
config['LIVE_CEX'] === 'true'
75+
? REQUIRED_CONFIGURATION_OPTIONS_LIVE_CEX_ENABLED
76+
: REQUIRED_CONFIGURATION_OPTIONS_LIVE_CEX_DISABLED;
77+
return REQUIRED_CONFIGURATION_OPTIONS.concat(ADDITIONAL_CONF_OPTIONS)
78+
.reduce((missingOptions: string[], configOption) => {
6979
if (!config[configOption]) {
7080
return missingOptions.concat(configOption);
7181
}
7282
return missingOptions;
73-
},
74-
[]
75-
).join(', ');
83+
}, [])
84+
.join(', ');
7685
};
7786

7887
const ALLOWED_TRADING_PAIRS: string[] = [

0 commit comments

Comments
 (0)