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