Skip to content

Commit 66bb43d

Browse files
author
Karl Ranna
committed
feat: add Kraken support
1 parent c3fee0f commit 66bb43d

File tree

10 files changed

+95
-25
lines changed

10 files changed

+95
-25
lines changed

.env-example

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
BINANCE_API_KEY=123
2-
BINANCE_API_SECRET=abc
1+
CEX=Binance
2+
CEX_API_KEY=123
3+
CEX_API_SECRET=abc
34
DATA_DIR=/home/user/arby/data
45
OPENDEX_CERT_PATH=/home/user/.xud/tls.cert
56
OPENDEX_RPC_HOST=localhost
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`getExchange throws for unsupported exchange 1`] = `[Error: Could not get centralized exchange. Invalide CEX configuration option]`;

src/centralized/ccxt/exchange.spec.ts

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,50 @@ import { getExchange } from './exchange';
55
jest.mock('ccxt');
66

77
describe('getExchange', () => {
8-
it('initializes exchange with API key and secret', () => {
9-
const config = testConfig();
8+
afterEach(() => {
9+
jest.clearAllMocks();
10+
});
11+
12+
it('initializes Binance with API key and secret', () => {
13+
const config = {
14+
...testConfig(),
15+
...{ CEX: 'Binance' },
16+
};
1017
getExchange(config);
1118
expect(ccxt.binance).toHaveBeenCalledTimes(1);
1219
expect(ccxt.binance).toHaveBeenCalledWith(
1320
expect.objectContaining({
14-
apiKey: config.BINANCE_API_KEY,
15-
secret: config.BINANCE_API_SECRET,
21+
apiKey: config.CEX_API_KEY,
22+
secret: config.CEX_API_SECRET,
23+
})
24+
);
25+
});
26+
27+
it('initializes Kraken with API key and secret', () => {
28+
const config = {
29+
...testConfig(),
30+
...{ CEX: 'Kraken' },
31+
};
32+
getExchange(config);
33+
expect(ccxt.kraken).toHaveBeenCalledTimes(1);
34+
expect(ccxt.kraken).toHaveBeenCalledWith(
35+
expect.objectContaining({
36+
apiKey: config.CEX_API_KEY,
37+
secret: config.CEX_API_SECRET,
1638
})
1739
);
1840
});
41+
42+
it('throws for unsupported exchange', () => {
43+
expect.assertions(1);
44+
const config = {
45+
...testConfig(),
46+
...{ CEX: 'Michael' },
47+
};
48+
try {
49+
getExchange(config);
50+
} catch (e) {
51+
expect(e).toMatchSnapshot();
52+
}
53+
});
1954
});

src/centralized/ccxt/exchange.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,22 @@ import ccxt, { Exchange } from 'ccxt';
22
import { Config } from '../../config';
33

44
const getExchange = (config: Config): Exchange => {
5-
return new ccxt.binance({
6-
apiKey: config.BINANCE_API_KEY,
7-
secret: config.BINANCE_API_SECRET,
8-
});
5+
switch (config.CEX) {
6+
case 'Binance':
7+
return new ccxt.binance({
8+
apiKey: config.CEX_API_KEY,
9+
secret: config.CEX_API_SECRET,
10+
});
11+
case 'Kraken':
12+
return new ccxt.kraken({
13+
apiKey: config.CEX_API_KEY,
14+
secret: config.CEX_API_SECRET,
15+
});
16+
default:
17+
throw new Error(
18+
'Could not get centralized exchange. Invalide CEX configuration option'
19+
);
20+
}
921
};
1022

1123
export { getExchange };

src/centralized/convert-balances.spec.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,13 @@ describe('convertBalances', () => {
2222
quoteAssetBalance: new BigNumber('2'),
2323
});
2424
});
25+
26+
it('returns 0 when CCXT balance does not exist', () => {
27+
const config = testConfig();
28+
const balances = ({} as unknown) as Balances;
29+
expect(convertBalances(config, balances)).toEqual({
30+
baseAssetBalance: new BigNumber('0'),
31+
quoteAssetBalance: new BigNumber('0'),
32+
});
33+
});
2534
});

src/centralized/convert-balances.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@ const convertBalances = (
77
config: Config,
88
balances: Balances
99
): ExchangeAssetAllocation => {
10-
const baseAssetBalance = new BigNumber(balances[config.BASEASSET].total);
11-
const quoteAssetBalance = new BigNumber(balances[config.QUOTEASSET].total);
10+
const baseAssetTotal =
11+
(balances[config.BASEASSET] && balances[config.BASEASSET].total) || '0';
12+
const baseAssetBalance = new BigNumber(baseAssetTotal);
13+
const quoteAssetTotal =
14+
(balances[config.QUOTEASSET] && balances[config.QUOTEASSET].total) || '0';
15+
const quoteAssetBalance = new BigNumber(quoteAssetTotal);
1216
return {
1317
baseAssetBalance,
1418
quoteAssetBalance,

src/config.spec.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ describe('checkConfigOptions', () => {
44
it('allows BTC/USDT trading pair', () => {
55
const dotEnvConfig = {
66
LOG_LEVEL: 'trace',
7-
BINANCE_API_KEY: '123',
8-
BINANCE_API_SECRET: 'abc',
7+
CEX: 'Binance',
8+
CEX_API_KEY: '123',
9+
CEX_API_SECRET: 'abc',
910
DATA_DIR: '/some/data/path',
1011
OPENDEX_CERT_PATH: '/some/cert/path',
1112
OPENDEX_RPC_HOST: 'localhost',
@@ -27,8 +28,9 @@ describe('checkConfigOptions', () => {
2728
it('allows ETH/BTC trading pair', () => {
2829
const dotEnvConfig = {
2930
LOG_LEVEL: 'trace',
30-
BINANCE_API_KEY: '123',
31-
BINANCE_API_SECRET: 'abc',
31+
CEX: 'Binance',
32+
CEX_API_KEY: '123',
33+
CEX_API_SECRET: 'abc',
3234
DATA_DIR: '/some/data/path',
3335
OPENDEX_CERT_PATH: '/some/cert/path',
3436
OPENDEX_RPC_HOST: 'localhost',
@@ -50,8 +52,9 @@ describe('checkConfigOptions', () => {
5052
it('does not allow LTC/LTC trading pair', () => {
5153
const dotEnvConfig = {
5254
LOG_LEVEL: 'trace',
53-
BINANCE_API_KEY: '123',
54-
BINANCE_API_SECRET: 'abc',
55+
CEX: 'Binance',
56+
CEX_API_KEY: '123',
57+
CEX_API_SECRET: 'abc',
5558
DATA_DIR: '/some/data/path',
5659
OPENDEX_CERT_PATH: '/some/cert/path',
5760
OPENDEX_RPC_HOST: 'localhost',

src/config.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ import { Asset } from './constants';
66

77
export type Config = {
88
LOG_LEVEL: Level;
9-
BINANCE_API_KEY: string;
10-
BINANCE_API_SECRET: string;
9+
CEX: string;
10+
CEX_API_KEY: string;
11+
CEX_API_SECRET: string;
1112
DATA_DIR: string;
1213
OPENDEX_CERT_PATH: string;
1314
OPENDEX_RPC_HOST: string;
@@ -22,8 +23,9 @@ export type Config = {
2223

2324
const REQUIRED_CONFIGURATION_OPTIONS = [
2425
'LOG_LEVEL',
25-
'BINANCE_API_KEY',
26-
'BINANCE_API_SECRET',
26+
'CEX',
27+
'CEX_API_KEY',
28+
'CEX_API_SECRET',
2729
'DATA_DIR',
2830
'OPENDEX_CERT_PATH',
2931
'OPENDEX_RPC_HOST',

src/opendex/errors.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const errors = {
3636
code: errorCodes.CENTRALIZED_EXCHANGE_PRICE_FEED_ERROR,
3737
},
3838
CEX_INVALID_CREDENTIALS: {
39-
message: 'Invalid BINANCE_API_KEY or BINANCE_API_SECRET',
39+
message: 'Invalid CEX_API_KEY or CEX_API_SECRET',
4040
code: errorCodes.CEX_INVALID_CREDENTIALS,
4141
},
4242
};

src/test-utils.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import { Level, Loggers } from './logger';
44
const testConfig = (): Config => {
55
return {
66
LOG_LEVEL: Level.Trace,
7-
BINANCE_API_KEY: '123',
8-
BINANCE_API_SECRET: 'abc',
7+
CEX: 'Binance',
8+
CEX_API_KEY: '123',
9+
CEX_API_SECRET: 'abc',
910
DATA_DIR: '',
1011
OPENDEX_CERT_PATH: `${__dirname}/../mock-data/tls.cert`,
1112
OPENDEX_RPC_HOST: 'localhost',

0 commit comments

Comments
 (0)