1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const node_fetch_1 = require("node-fetch");
|
4 | const sax = require("sax");
|
5 | const bignumber_js_1 = require("bignumber.js");
|
6 | const log_1 = require("../common/log");
|
7 | const log = log_1.create('ecb');
|
8 | const RATES_API = 'https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml';
|
9 | class ECBBackend {
|
10 | constructor(opts, api) {
|
11 | this.spread = opts.spread || 0;
|
12 | this.ratesApiUrl = opts.ratesApiUrl || RATES_API;
|
13 | this.mockData = opts.mockData;
|
14 | this.getInfo = api.getInfo;
|
15 | this.rates = {};
|
16 | this.currencies = [];
|
17 | }
|
18 | async connect() {
|
19 | let apiData;
|
20 | if (this.mockData) {
|
21 | log.info('connect using mock data.');
|
22 | apiData = this.mockData;
|
23 | }
|
24 | else {
|
25 | log.info('connect. uri=' + this.ratesApiUrl);
|
26 | let result = await node_fetch_1.default(this.ratesApiUrl);
|
27 | apiData = await parseXMLResponse(await result.text());
|
28 | }
|
29 | this.rates = apiData.rates;
|
30 | this.rates[apiData.base] = 1;
|
31 | this.currencies = Object.keys(this.rates);
|
32 | this.currencies.sort();
|
33 | log.info('data loaded. numCurrencies=' + this.currencies.length);
|
34 | }
|
35 | _formatAmount(amount) {
|
36 | return new bignumber_js_1.default(amount).toFixed(2);
|
37 | }
|
38 | _formatAmountCeil(amount) {
|
39 | return new bignumber_js_1.default(amount).decimalPlaces(2, bignumber_js_1.default.ROUND_CEIL).toFixed(2);
|
40 | }
|
41 | async getRate(sourceAccount, destinationAccount) {
|
42 | const sourceInfo = this.getInfo(sourceAccount);
|
43 | const destinationInfo = this.getInfo(destinationAccount);
|
44 | if (!sourceInfo) {
|
45 | log.error('unable to fetch account info for source account. accountId=%s', sourceAccount);
|
46 | throw new Error('unable to fetch account info for source account. accountId=' + sourceAccount);
|
47 | }
|
48 | if (!destinationInfo) {
|
49 | log.error('unable to fetch account info for destination account. accountId=%s', destinationAccount);
|
50 | throw new Error('unable to fetch account info for destination account. accountId=' + destinationAccount);
|
51 | }
|
52 | const sourceCurrency = sourceInfo.assetCode;
|
53 | const destinationCurrency = destinationInfo.assetCode;
|
54 | const sourceRate = this.rates[sourceCurrency];
|
55 | const destinationRate = this.rates[destinationCurrency];
|
56 | if (!sourceRate) {
|
57 | log.error('no rate available for source currency. currency=%s', sourceCurrency);
|
58 | throw new Error('no rate available. currency=' + sourceCurrency);
|
59 | }
|
60 | if (!destinationRate) {
|
61 | log.error('no rate available for destination currency. currency=%s', destinationCurrency);
|
62 | throw new Error('no rate available. currency=' + destinationCurrency);
|
63 | }
|
64 | const rate = new bignumber_js_1.default(destinationRate).shiftedBy(destinationInfo.assetScale)
|
65 | .div(new bignumber_js_1.default(sourceRate).shiftedBy(sourceInfo.assetScale))
|
66 | .times(new bignumber_js_1.default(1).minus(this.spread))
|
67 | .toPrecision(15);
|
68 | log.trace('quoted rate. from=%s to=%s fromCur=%s toCur=%s rate=%s spread=%s', sourceAccount, destinationAccount, sourceCurrency, destinationCurrency, rate, this.spread);
|
69 | return Number(rate);
|
70 | }
|
71 | async submitPayment() {
|
72 | return Promise.resolve(undefined);
|
73 | }
|
74 | }
|
75 | exports.default = ECBBackend;
|
76 | function parseXMLResponse(data) {
|
77 | const parser = sax.parser(true, {});
|
78 | const apiData = { base: 'EUR', rates: {} };
|
79 | parser.onopentag = (node) => {
|
80 | if (node.name === 'Cube' && node.attributes.time) {
|
81 | apiData.date = node.attributes.time;
|
82 | }
|
83 | if (node.name === 'Cube' && node.attributes.currency && node.attributes.rate) {
|
84 | apiData.rates[node.attributes.currency] = node.attributes.rate;
|
85 | }
|
86 | };
|
87 | return new Promise((resolve, reject) => {
|
88 | parser.onerror = reject;
|
89 | parser.onend = () => resolve(apiData);
|
90 | parser.write(data).close();
|
91 | });
|
92 | }
|
93 |
|
\ | No newline at end of file |