UNPKG

4.16 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const node_fetch_1 = require("node-fetch");
4const sax = require("sax");
5const bignumber_js_1 = require("bignumber.js");
6const log_1 = require("../common/log");
7const log = log_1.create('ecb');
8const RATES_API = 'https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml';
9class 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}
75exports.default = ECBBackend;
76function 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//# sourceMappingURL=ecb.js.map
\No newline at end of file