From 6abbc6a2c5db9002c382df9006beb02b83e75860 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Cienfuegos?= Date: Mon, 22 Feb 2016 21:00:11 -0800 Subject: [PATCH 1/3] Fix: Return 1.0 from FiatAdapter#rate_for when comparing the CROSS_RATE_CURRENCY The current implementation for `FixerAdapter#rate_for`, which inherits from `FiatAdapter#rate_for`, was calling for `super` but wasn't honoring the result from `super` when the given `currency_code` was the `CROSS_RATE_CURRENCY` and would raise a `CurrencyNotSupported` error instead of using the `return 1` from the `CROSS_RATE_CURRENCY` comparison. --- .../exchange_rate_adapters/fiat_adapters/fixer_adapter.rb | 4 ++-- .../fiat_adapters/fixer_adapter_spec.rb | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/straight/exchange_rate_adapters/fiat_adapters/fixer_adapter.rb b/lib/straight/exchange_rate_adapters/fiat_adapters/fixer_adapter.rb index dd859b0..8e7eb0c 100644 --- a/lib/straight/exchange_rate_adapters/fiat_adapters/fixer_adapter.rb +++ b/lib/straight/exchange_rate_adapters/fiat_adapters/fixer_adapter.rb @@ -4,8 +4,8 @@ class FixerAdapter < FiatAdapter FETCH_URL = "http://api.fixer.io/latest?base=#{CROSS_RATE_CURRENCY}" def rate_for(currency_code) - super - rate = get_rate_value_from_hash(@rates, 'rates', currency_code) + rate = super + rate ||= get_rate_value_from_hash(@rates, 'rates', currency_code) rate_to_f(rate) end end diff --git a/spec/lib/exchange_rate_adapters/fiat_adapters/fixer_adapter_spec.rb b/spec/lib/exchange_rate_adapters/fiat_adapters/fixer_adapter_spec.rb index 270fbb8..bb5b372 100644 --- a/spec/lib/exchange_rate_adapters/fiat_adapters/fixer_adapter_spec.rb +++ b/spec/lib/exchange_rate_adapters/fiat_adapters/fixer_adapter_spec.rb @@ -19,4 +19,8 @@ expect( -> { @exchange_adapter.rate_for('KZT') }).to raise_error(Straight::ExchangeRate::Adapter::CurrencyNotSupported) end + it "returns 1.0 when the currency is the FiatAdapter::CROSS_RATE_CURRENCY" do + expect(@exchange_adapter. + rate_for(Straight::ExchangeRate::FiatAdapter::CROSS_RATE_CURRENCY)).to eq(1.0) + end end From dbcb33627ac795f67796d5a39cf8d45e839ff467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Cienfuegos?= Date: Wed, 17 Feb 2016 21:01:31 -0800 Subject: [PATCH 2/3] Handle address provider unsupported currencies when creating a new order When trying to create a `#new_order` for a Gateway with an `AddressProvider` that doesn't support the given currency we now convert that currency to one the AddressProvider can handle using the `FixerAdapter` rates that apply. --- lib/straight/gateway.rb | 21 +++++++++++++++++++++ spec/lib/gateway_spec.rb | 22 ++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/lib/straight/gateway.rb b/lib/straight/gateway.rb index 24fdbd5..9c99503 100644 --- a/lib/straight/gateway.rb +++ b/lib/straight/gateway.rb @@ -91,6 +91,15 @@ def new_order(args) raise OrderAmountInvalid, "amount cannot be nil and should be more than 0" end # Setting default values + + if address_provider.takes_fees? && + !address_provider.currency_supported?(args[:currency]) + supported_currency = select_supported_currency_by_address_provider + args[:amount] = convert_amount_to_supported_currency(args[:amount], + args[:currency], supported_currency) + args[:currency] = supported_currency + end + args[:currency] ||= default_currency args[:btc_denomination] ||= :satoshi @@ -197,6 +206,18 @@ def address_provider_type private + def select_supported_currency_by_address_provider + address_provider.class::SUPPORTED_CURRENCIES.first + end + + def convert_amount_to_supported_currency(amount, currency, supported_currency) + adapter = ExchangeRate::FixerAdapter.instance + rate_for_supported_currency = adapter.rate_for(supported_currency) + rate_for_currency = adapter.rate_for(currency) + + (amount * rate_for_supported_currency) / rate_for_currency + end + # Calls the block with each adapter until one of them does not fail. # Fails with the: # - priority_exception, if it is set and was raised at least once diff --git a/spec/lib/gateway_spec.rb b/spec/lib/gateway_spec.rb index 49d81d1..85e1086 100644 --- a/spec/lib/gateway_spec.rb +++ b/spec/lib/gateway_spec.rb @@ -74,6 +74,18 @@ @gateway.order_status_changed(order) end + describe "when the address provider doesn't support the selected currency" do + it "converts the currency to one the address provider supports" do + @gateway.address_provider = AddressProvider.new(provider: :cashila) + allow(@gateway.address_provider).to receive(:new_address_and_amount) + allow(@gateway).to receive(:select_supported_currency_by_address_provider). + and_return("EUR") + expect(@gateway).to receive(:amount_from_exchange_rate). + with(0.91996, currency: "EUR", btc_denomination: :satoshi) + @gateway.new_order(amount: 1, keychain_id: 1, currency: "USD") + end + end + describe "exchange rate calculation" do it "sets order amount in satoshis calculated from another currency" do @@ -153,3 +165,13 @@ end end + +AddressProvider = Struct.new(:provider) do + def takes_fees? + true + end + + def currency_supported?(currency) + currency == "EUR" + end +end From 4ec367c3a62bce49faebec1b1927a9c507cd4eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Cienfuegos?= Date: Thu, 25 Feb 2016 15:52:54 -0800 Subject: [PATCH 3/3] Add AddressProvider::Base#currency_supported? Address providers are expected to define this method as an Enumerable with valid currency codes. e.g. 'EUR', 'USD'. This method is used to determine if a the currency should be converted to one the address provider supports when creating an order. --- lib/straight/address_providers/base.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/straight/address_providers/base.rb b/lib/straight/address_providers/base.rb index 52efd80..4d037bb 100644 --- a/lib/straight/address_providers/base.rb +++ b/lib/straight/address_providers/base.rb @@ -23,6 +23,12 @@ def new_address(keychain_id:, **args) def takes_fees? false end + + # Address provider is expected to define SUPPORTED_CURRENCIES as an + # Enumerable with valid currency codes. e.g. 'EUR', 'USD' + def currency_supported?(currency) + SUPPORTED_CURRENCIES.include?(currency) + end end end end