UNPKG

bitcore-wallet-service

Version:
1,051 lines (1,014 loc) 30.6 kB
'use strict'; var async = require('async'); var chai = require('chai'); var sinon = require('sinon'); var should = chai.should(); var log = require('npmlog'); log.debug = log.verbose; log.level = 'info'; var { Common } = require('../../ts_build/lib/common'); var Defaults = Common.Defaults; var Constants = Common.Constants; var helpers = require('./helpers'); var { FiatRateService } = require('../../ts_build/lib/fiatrateservice'); describe('Fiat rate service', function() { this.timeout(5000); var service, request; before(function(done) { helpers.before(res => { done(); }); }); after(function(done) { helpers.after(done); }); beforeEach(function(done) { helpers.beforeEach(function() { service = new FiatRateService(); request = sinon.stub(); request.get = sinon.stub(); service.init( { storage: helpers.getStorage(), request: request }, function(err) { should.not.exist(err); service.startCron({}, done); } ); }); }); describe('#getRate', function() { it('should get current rate', function(done) { service.storage.storeFiatRate( 'bch', [ { code: 'USD', value: 123.45 } ], function(err) { should.not.exist(err); service.getRate( { coin: 'bch', code: 'USD' }, function(err, res) { should.not.exist(err); res.rate.should.equal(123.45); done(); } ); } ); }); it('should get current rate for different currency', function(done) { service.storage.storeFiatRate( 'btc', [ { code: 'USD', value: 123.45 } ], function(err) { should.not.exist(err); service.storage.storeFiatRate( 'btc', [ { code: 'EUR', value: 345.67 } ], function(err) { should.not.exist(err); service.getRate( { code: 'EUR' }, function(err, res) { should.not.exist(err); res.rate.should.equal(345.67); done(); } ); } ); } ); }); it('should get current rate for different coin', function(done) { service.storage.storeFiatRate( 'btc', [ { code: 'USD', value: 100.0 } ], function(err) { should.not.exist(err); service.storage.storeFiatRate( 'bch', [ { code: 'USD', value: 200.0 } ], function(err) { should.not.exist(err); service.getRate( { code: 'USD' }, function(err, res) { should.not.exist(err); res.rate.should.equal(100.0, 'Should use default coin'); service.getRate( { code: 'USD', coin: 'bch' }, function(err, res) { should.not.exist(err); res.rate.should.equal(200.0); done(); } ); } ); } ); } ); }); it('should get rate for specific ts', function(done) { var clock = sinon.useFakeTimers({ toFake: ['Date'] }); clock.tick(20); service.storage.storeFiatRate( 'btc', [ { code: 'USD', value: 123.45 } ], function(err) { should.not.exist(err); clock.tick(100); service.storage.storeFiatRate( 'btc', [ { code: 'USD', value: 345.67 } ], function(err) { should.not.exist(err); service.getRate( { code: 'USD', ts: 50 }, function(err, res) { should.not.exist(err); res.ts.should.equal(50); res.rate.should.equal(123.45); res.fetchedOn.should.equal(20); clock.restore(); done(); } ); } ); } ); }); it('should get rates for a series of ts', function(done) { var clock = sinon.useFakeTimers({ toFake: ['Date'] }); async.each( [1.0, 2.0, 3.0, 4.0], function(value, next) { clock.tick(100); service.storage.storeFiatRate( 'btc', [ { code: 'USD', value: value }, { code: 'EUR', value: value } ], next ); }, function(err) { should.not.exist(err); service.getRate( { code: 'USD', ts: [50, 100, 199, 500] }, function(err, res) { should.not.exist(err); res.length.should.equal(4); res[0].ts.should.equal(50); should.not.exist(res[0].rate); should.not.exist(res[0].fetchedOn); res[1].ts.should.equal(100); res[1].rate.should.equal(1.0); res[1].fetchedOn.should.equal(100); res[2].ts.should.equal(199); res[2].rate.should.equal(1.0); res[2].fetchedOn.should.equal(100); res[3].ts.should.equal(500); res[3].rate.should.equal(4.0); res[3].fetchedOn.should.equal(400); clock.restore(); done(); } ); } ); }); it('should get historical rates from ts to now', function(done) { const coins = ['btc', 'bch', 'eth', 'matic', 'xrp', 'doge', 'ltc']; var clock = sinon.useFakeTimers({ toFake: ['Date'] }); async.each( [1.0, 2.0, 3.0, 4.0, 5.0], function(value, next) { clock.tick(100); async.map( coins, (coin, cb) => { service.storage.storeFiatRate( coin, [ { code: 'USD', value: value }, { code: 'EUR', value: value } ], cb ); }, () => { return next(); } ); }, function(err) { should.not.exist(err); service.getHistoricalRates( { code: 'USD', ts: 100 }, function(err, res) { should.not.exist(err); should.exist(res); for (const coin of coins) { res[coin].length.should.equal(5); res[coin][4].ts.should.equal(100); res[coin][4].rate.should.equal(1.0); res[coin][3].ts.should.equal(200); res[coin][3].rate.should.equal(2.0); res[coin][2].ts.should.equal(300); res[coin][2].rate.should.equal(3.0); res[coin][1].ts.should.equal(400); res[coin][1].rate.should.equal(4.0); res[coin][0].ts.should.equal(500); res[coin][0].rate.should.equal(5.0); } clock.restore(); done(); } ); } ); }); it('should not throw if missing historical rates for a coin', function(done) { var clock = sinon.useFakeTimers({ toFake: ['Date'] }); async.each( [1.0, 2.0, 3.0, 4.0], function(value, next) { clock.tick(100); service.storage.storeFiatRate( 'btc', [ { code: 'USD', value: value }, { code: 'EUR', value: value } ], next ); }, function(err) { should.not.exist(err); service.getHistoricalRates( { code: 'USD', ts: 100 }, function(err, res) { should.not.exist(err); should.exist(res); res['btc'].length.should.equal(4); should.not.exist(res['bch']); should.not.exist(res['eth']); should.not.exist(res['matic']); should.not.exist(res['xrp']); should.not.exist(res['doge']); should.not.exist(res['ltc']); res['btc'][3].ts.should.equal(100); res['btc'][3].rate.should.equal(1.0); res['btc'][2].ts.should.equal(200); res['btc'][2].rate.should.equal(2.0); res['btc'][1].ts.should.equal(300); res['btc'][1].rate.should.equal(3.0); res['btc'][0].ts.should.equal(400); res['btc'][0].rate.should.equal(4.0); clock.restore(); done(); } ); } ); }); it('should return current rates if missing opts.ts when fetching historical rates', function(done) { const coins = ['btc', 'bch', 'eth', 'xrp', 'doge', 'ltc']; var clock = sinon.useFakeTimers({ toFake: ['Date'] }); async.each( [1.0, 2.0, 3.0, 4.0], function(value, next) { clock.tick(11 * 60 * 1000); async.map( coins, (coin, cb) => { service.storage.storeFiatRate( coin, [ { code: 'USD', value: value }, { code: 'EUR', value: value } ], cb ); }, () => { return next(); } ); }, function(err) { should.not.exist(err); service.getHistoricalRates( { code: 'USD' }, function(err, res) { should.not.exist(err); for (const coin of coins) { res[coin].length.should.equal(1); res[coin][0].ts.should.equal(2640000); res[coin][0].rate.should.equal(4.0); } clock.restore(); done(); } ); } ); }); it('should not get rate older than 2hs', function(done) { var clock = sinon.useFakeTimers({ toFake: ['Date'] }); service.storage.storeFiatRate( 'btc', [ { code: 'USD', value: 123.45 } ], function(err) { should.not.exist(err); clock.tick(24 * 3600 * 1000); // Some time in the future service.getRate( { ts: 2 * 3600 * 1000 - 1, // almost 2 hours code: 'USD' }, function(err, res) { should.not.exist(err); res.rate.should.equal(123.45); res.fetchedOn.should.equal(0); service.getRate( { ts: 2 * 3600 * 1000 + 1, // just past 2 hours code: 'USD' }, function(err, res) { should.not.exist(err); should.not.exist(res.rate); clock.restore(); done(); } ); } ); } ); }); }); describe('#fetch', function() { it('should fetch rates from all coins', function(done) { var clock = sinon.useFakeTimers({ now: 100, toFake: ['Date'] }); var btc = [ { code: 'USD', rate: 123.45 }, { code: 'EUR', rate: 234.56 } ]; var bch = [ { code: 'USD', rate: 120 }, { code: 'EUR', rate: 120 } ]; var eth = [ { code: 'USD', rate: 121 }, { code: 'EUR', rate: 121 } ]; var matic = [ { code: 'USD', rate: 1.19 }, { code: 'EUR', rate: 1.19 } ]; var xrp = [ { code: 'USD', rate: 0.222222 }, { code: 'EUR', rate: 0.211111 } ]; var doge = [ { code: 'USD', rate: 0.05 }, { code: 'EUR', rate: 0.04 } ]; var ltc = [ { code: 'USD', rate: 150 }, { code: 'EUR', rate: 170 } ]; var shib = [ { code: 'USD', rate: 0.00003678 }, { code: 'EUR', rate: 0.00003276 } ]; var ape = [ { code: 'USD', rate: 6.66 }, { code: 'EUR', rate: 6.64 } ]; var sol = [ { code: 'USD', rate: 150 }, { code: 'EUR', rate: 156 } ]; request.get .withArgs({ url: 'https://bitpay.com/api/rates/BTC?p=bws', json: true }) .yields(null, null, btc); request.get .withArgs({ url: 'https://bitpay.com/api/rates/BCH?p=bws', json: true }) .yields(null, null, bch); request.get .withArgs({ url: 'https://bitpay.com/api/rates/ETH?p=bws', json: true }) .yields(null, null, eth); request.get .withArgs({ url: 'https://bitpay.com/api/rates/MATIC?p=bws', json: true }) .yields(null, null, matic); request.get .withArgs({ url: 'https://bitpay.com/api/rates/XRP?p=bws', json: true }) .yields(null, null, xrp); request.get .withArgs({ url: 'https://bitpay.com/api/rates/DOGE?p=bws', json: true }) .yields(null, null, doge); request.get .withArgs({ url: 'https://bitpay.com/api/rates/LTC?p=bws', json: true }) .yields(null, null, ltc); request.get .withArgs({ url: 'https://bitpay.com/api/rates/SHIB?p=bws', json: true }) .yields(null, null, shib); request.get .withArgs({ url: 'https://bitpay.com/api/rates/APE?p=bws', json: true }) .yields(null, null, ape); request.get .withArgs({ url: 'https://bitpay.com/api/rates/SOL?p=bws', json: true }) .yields(null, null, sol); request.get .withArgs({ url: 'https://bitpay.com/api/rates/WBTC?p=bws', json: true }) .yields(null, null, btc); request.get .withArgs({ url: 'https://bitpay.com/api/rates/WETH?p=bws', json: true }) .yields(null, null, eth); service._fetch(function(err) { should.not.exist(err); service.getRate( { code: 'USD' }, function(err, res) { should.not.exist(err); res.fetchedOn.should.equal(100); res.rate.should.equal(123.45); service.getRate( { code: 'USD', coin: 'bch' }, function(err, res) { should.not.exist(err); res.fetchedOn.should.equal(100); res.rate.should.equal(120.0); service.getRate( { code: 'USD', coin: 'eth' }, function(err, res) { should.not.exist(err); res.fetchedOn.should.equal(100); res.rate.should.equal(121); service.getRate( { code: 'USD', coin: 'matic' }, function(err, res) { should.not.exist(err); res.fetchedOn.should.equal(100); res.rate.should.equal(1.19); service.getRate( { code: 'USD', coin: 'xrp' }, function(err, res) { should.not.exist(err); res.fetchedOn.should.equal(100); res.rate.should.equal(0.222222); service.getRate( { code: 'USD', coin: 'doge' }, function(err, res) { should.not.exist(err); res.fetchedOn.should.equal(100); res.rate.should.equal(0.05); service.getRate( { code: 'USD', coin: 'ltc' }, function(err, res) { should.not.exist(err); res.fetchedOn.should.equal(100); res.rate.should.equal(150); service.getRate( { code: 'EUR' }, function(err, res) { should.not.exist(err); res.fetchedOn.should.equal(100); res.rate.should.equal(234.56); service.getRate( { code: 'USD', coin: 'shib' }, function(err, res) { should.not.exist(err); res.fetchedOn.should.equal(100); res.rate.should.equal(0.00003678); service.getRate( { code: 'USD', coin: 'ape' }, function(err, res) { should.not.exist(err); res.fetchedOn.should.equal(100); res.rate.should.equal(6.66); service.getRate( { code: 'USD', coin: 'usdc' }, function(err, res) { should.not.exist(err); res.fetchedOn.should.equal(100); res.rate.should.equal(1); service.getRate( { code: 'USD', coin: 'weth' }, function(err, res) { should.not.exist(err); res.fetchedOn.should.equal(100); res.rate.should.equal(121); service.getRate( { code: 'USD', coin: 'sol' }, function(err, res) { should.not.exist(err); res.fetchedOn.should.equal(100); res.rate.should.equal(150); clock.restore(); done(); } ); } ); } ); } ); } ); } ); } ); } ); } ); } ); } ); } ); } ); }); }); }); describe('#getRates', function() { it('should get the rates of each coin in all supported fiat currencies', function(done) { service.getRates({}, function(err, res) { should.not.exist(err); Object.keys(res).forEach(key => { res[key].length.should.equal(Defaults.FIAT_CURRENCIES.length); }); done(); }); }); it('should get the rates of all coins supported', function(done) { service.getRates({}, function(err, res) { should.not.exist(err); Object.keys(res).length.should.equal( Object.keys(Constants.BITPAY_SUPPORTED_COINS).length) done(); }); }); it('should get rates of all coins in the specified fiat currency if it is supported', function(done) { service.getRates( { code: 'EUR' }, function(err, res) { should.not.exist(err); Object.keys(res).length.should.equal( Object.keys(Constants.BITPAY_SUPPORTED_COINS).length) Object.keys(res).forEach(key=>{ res[key].length.should.equal(1); }); done(); } ); }); it('should throw error if the specified fiat currency code is not supported', function(done) { service.getRates( { code: 'AOA' }, function(err) { should.exist(err); err.should.equal('AOA is not supported'); done(); } ); }); it('should get rate for specific ts', function(done) { var clock = sinon.useFakeTimers({ toFake: ['Date'] }); clock.tick(20); service.storage.storeFiatRate( 'btc', [ { code: 'USD', value: 123.45 } ], function(err) { should.not.exist(err); clock.tick(100); service.storage.storeFiatRate( 'btc', [ { code: 'USD', value: 345.67 } ], function(err) { should.not.exist(err); service.getRates( { coin: 'btc', code: 'USD', ts: 50 }, function(err, res) { should.not.exist(err); Object.keys(res).forEach(key => { res[key][0].ts.should.equal(50); }); clock.restore(); done(); } ); } ); } ); }); }); describe('#getRatesByCoin', function() { const bchRates = [ { code: 'USD', value: 268.94 }, { code: 'INR', value: 19680.35 }, { code: 'EUR', value: 226.37 }, { code: 'CAD', value: 352.33 }, { code: 'COP', value: 1026617.26 }, { code: 'NGN', value: 104201.93 }, { code: 'GBP', value: 201.62 }, { code: 'ARS', value: 19900.21 }, { code: 'AUD', value: 365.8 }, { code: 'BRL', value: 1456.93 }, { code: 'JPY', value: 1124900.43 }, { code: 'NZD', value: 16119.66 } ]; const btcRates = [ { code: 'USD', value: 44173.54 }, { code: 'INR', value: 3306411.94 }, { code: 'GBP', value: 32558.07 }, { code: 'EUR', value: 38642.15 }, { code: 'CAD', value: 56070.58 }, { code: 'COP', value: 173924929.36 }, { code: 'NGN', value: 18409323.7 }, { code: 'BRL', value: 233457.17 }, { code: 'ARS', value: 4678684.28 }, { code: 'AUD', value: 61503.4 }, { code: 'JPY', value: 5099004.98 }, { code: 'NZD', value: 50966068.64 } ]; it('should get rates for all the supported fiat currencies of the specified coin', function(done) { service.storage.storeFiatRate('bch', bchRates, function(err) { should.not.exist(err); service.getRatesByCoin( { coin: 'bch' }, function(err, res) { should.not.exist(err); res.length.should.equal(bchRates.length); done(); } ); }); }); it('should get rate for the specified coin and currency if they are supported', function(done) { service.storage.storeFiatRate('bch', bchRates, function(err) { should.not.exist(err); service.getRatesByCoin( { coin: 'bch', code: 'EUR' }, function(err, res) { should.not.exist(err); res[0].rate.should.equal(226.37); done(); } ); }); }); it('should throw error if the specified currency code is not supported', function(done) { service.storage.storeFiatRate('bch', bchRates, function(err) { should.not.exist(err); service.getRatesByCoin( { coin: 'bch', code: 'AOA' }, function(err) { should.exist(err); err.should.equal('AOA is not supported'); done(); } ); }); }); it('should get fiat rates for a USD stablecoin', function(done) { sinon.spy(service, 'getRatesForStablecoin'); service.storage.storeFiatRate('btc', btcRates, function(err) { should.not.exist(err); service.getRatesByCoin({ coin: 'gusd' }, function(err, res) { should.not.exist(err); should.exist(res); res .reduce((rates, { code, rate }) => ({ ...rates, [code]: rate }), {}) .should.deep.equal({ ARS: 105.92, AUD: 1.39, BRL: 5.29, CAD: 1.27, COP: 3937.31, EUR: 0.87, GBP: 0.74, INR: 74.85, JPY: 115.43, NGN: 416.75, NZD: 1153.77, USD: 1 }); service.getRatesForStablecoin .calledWith( sinon.match({ code: 'USD', ts: sinon.match.number }) ) .should.equal(true); done(); }); }); }); it('should get rate for specific ts', function(done) { var clock = sinon.useFakeTimers({ toFake: ['Date'] }); clock.tick(20); service.storage.storeFiatRate( 'btc', [ { code: 'USD', value: 123.45 } ], function(err) { should.not.exist(err); clock.tick(100); service.storage.storeFiatRate( 'btc', [ { code: 'USD', value: 345.67 } ], function(err) { should.not.exist(err); service.getRatesByCoin( { coin: 'btc', code: 'USD', ts: 50 }, function(err, res) { should.not.exist(err); res[0].ts.should.equal(50); res[0].rate.should.equal(123.45); res[0].fetchedOn.should.equal(20); clock.restore(); done(); } ); } ); } ); }); }); });