btc_sell_prices.rb

 1# frozen_string_literal: true
 2
 3require "em_promise"
 4require "money/bank/open_exchange_rates_bank"
 5
 6require_relative "bull_bitcoin"
 7require_relative "em"
 8require_relative "simple_swap"
 9
10class CryptoSellPrices
11	class PriceError < StandardError; end
12
13	def initialize(redis, oxr_app_id, bull: BullBitcoin.new)
14		@redis = redis
15		@bull = bull
16		@oxr = Money::Bank::OpenExchangeRatesBank.new(
17			Money::RatesStore::Memory.new
18		)
19		@oxr.app_id = oxr_app_id
20	end
21
22	def usd
23		EMPromise.all([cad, cad_to_usd]).then { |(a, b)| a * b }
24	end
25
26protected
27
28	def cad_to_usd
29		@redis.get("cad_to_usd").then do |rate|
30			next rate.to_f if rate
31
32			EM.promise_defer {
33				# OXR gem is not async, so defer to threadpool
34				@oxr.update_rates
35				@oxr.get_rate("CAD", "USD")
36			}.then do |orate|
37				@redis.setex("cad_to_usd", 60 * 60, orate).then { orate }
38			end
39		end
40	end
41end
42
43class BCHSellPrices < CryptoSellPrices
44	def initialize(
45		redis, oxr_app_id,
46		simple_swap: SimpleSwap.new, bull: BullBitcoin.new
47	)
48		super(redis, oxr_app_id, bull: bull)
49		@simple_swap = simple_swap
50	end
51
52	def cad
53		EMPromise.all([
54			@bull.fetch_btc_cad,
55			@simple_swap.fetch_rate("btc")
56		]).then do |(btc_cad, bch_per_btc)|
57			unless bch_per_btc&.positive?
58				raise PriceError, "SimpleSwap BTC to BCH rate was not positive"
59			end
60
61			btc_cad / bch_per_btc
62		end
63	end
64end
65
66class BTCSellPrices < CryptoSellPrices
67	def cad
68		@bull.fetch_btc_cad
69	end
70end