From b1df11acfabbc2b81408c1e0567ae471fd6c2cef Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Thu, 31 Aug 2017 17:29:58 +0100 Subject: [PATCH] Rewrite ExchangeRate to use BigDecimal Rewrite ExchangeRate to use BigDecimal for the quantity multiplication, to ensure that there is no loss of precision during the conversion process. The previous version using double-precision floating point maths inherently means that the precision is not fixed, but is floating. Change ExchangeRate to an abstract class rather than an interface, so the functions on it can be implemented directly rather than being extension functions, to improve Java compatibility. --- .../client/jfx/model/ExchangeRateModel.kt | 33 +++++++++++-------- .../corda/client/jfx/utils/AmountBindings.kt | 2 +- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/client/jfx/src/main/kotlin/net/corda/client/jfx/model/ExchangeRateModel.kt b/client/jfx/src/main/kotlin/net/corda/client/jfx/model/ExchangeRateModel.kt index 243d87843e..636603d1ab 100644 --- a/client/jfx/src/main/kotlin/net/corda/client/jfx/model/ExchangeRateModel.kt +++ b/client/jfx/src/main/kotlin/net/corda/client/jfx/model/ExchangeRateModel.kt @@ -3,25 +3,30 @@ package net.corda.client.jfx.model import javafx.beans.property.SimpleObjectProperty import javafx.beans.value.ObservableValue import net.corda.core.contracts.Amount +import java.math.BigDecimal +import java.math.RoundingMode import java.util.* - -interface ExchangeRate { - fun rate(from: Currency, to: Currency): Double -} - -fun ExchangeRate.exchangeAmount(amount: Amount, to: Currency) = - Amount(exchangeDouble(amount, to).toLong(), to) - -fun ExchangeRate.exchangeDouble(amount: Amount, to: Currency) = - rate(amount.token, to) * amount.quantity - /** * This model provides an exchange rate from arbitrary currency to arbitrary currency. - * TODO hook up an actual oracle */ +abstract class ExchangeRate { + /** + * Convert the given amount of a currency into the target currency. + * + * @return the original amount converted to an amount in the target currency. + */ + fun exchangeAmount(amount: Amount, to: Currency) = Amount.fromDecimal(amount.toDecimal().multiply(rate(amount.token, to)), to) + + abstract fun rate(from: Currency, to: Currency): BigDecimal +} + +/** + * Default implementation of an exchange rate model, which uses a fixed exchange rate. + */ +// TODO hook up an actual oracle class ExchangeRateModel { - val exchangeRate: ObservableValue = SimpleObjectProperty(object : ExchangeRate { - override fun rate(from: Currency, to: Currency) = 1.0 + val exchangeRate: ObservableValue = SimpleObjectProperty(object : ExchangeRate() { + override fun rate(from: Currency, to: Currency) = BigDecimal.ONE }) } diff --git a/client/jfx/src/main/kotlin/net/corda/client/jfx/utils/AmountBindings.kt b/client/jfx/src/main/kotlin/net/corda/client/jfx/utils/AmountBindings.kt index 26387c1663..49e76e227a 100644 --- a/client/jfx/src/main/kotlin/net/corda/client/jfx/utils/AmountBindings.kt +++ b/client/jfx/src/main/kotlin/net/corda/client/jfx/utils/AmountBindings.kt @@ -29,7 +29,7 @@ object AmountBindings { return EasyBind.combine(observableCurrency, observableExchangeRate) { currency, exchangeRate -> Pair) -> Long>( currency, - { (quantity, _, token) -> (exchangeRate.rate(token, currency) * quantity).toLong() } + { amount -> exchangeRate.exchangeAmount(amount, currency).quantity } ) } }