| 1 | import 'package:cw_core/amount/money.dart'; |
| 2 | import 'package:cw_core/currency.dart'; |
| 3 | |
| 4 | class ExchangeRate { |
| 5 | const ExchangeRate({required this.base, required this.quote}); |
| 6 | |
| 7 | /// The currency being priced (e.g. BTC in a BTC/USD pair). |
| 8 | final Currency base; |
| 9 | |
| 10 | /// The price of one whole unit of [base], in the quote currency |
| 11 | /// (e.g. 45000 USD in a BTC/USD pair). |
| 12 | final Money quote; |
| 13 | |
| 14 | /// Converts [amount] between the base and quote currencies. |
| 15 | /// |
| 16 | /// Results are truncated toward zero. |
| 17 | /// |
| 18 | /// Throws an [ArgumentError] if [amount]'s currency is not part of |
| 19 | /// this pair. |
| 20 | Money convert(Money amount) { |
| 21 | if (base == quote.currency && base == amount.currency) { |
| 22 | return amount; |
| 23 | } |
| 24 | |
| 25 | if (amount.currency == base) { |
| 26 | final scale = BigInt.from(10).pow(amount.decimals); |
| 27 | |
| 28 | return quote.isZero |
| 29 | ? Money.zero(quote.currency) |
| 30 | : Money(amount.amount * quote.amount ~/ scale, quote.currency, quote.decimals); |
| 31 | } |
| 32 | |
| 33 | if (amount.currency == quote.currency) { |
| 34 | if (quote.isZero) { |
| 35 | return Money.zero(base); |
| 36 | } |
| 37 | |
| 38 | final numerator = amount.amount * BigInt.from(10).pow(base.decimals + quote.decimals); |
| 39 | final denominator = quote.amount * BigInt.from(10).pow(amount.decimals); |
| 40 | |
| 41 | return Money(numerator ~/ denominator, base); |
| 42 | } |
| 43 | |
| 44 | throw ArgumentError( |
| 45 | "Unable to convert ${amount.currency.symbol} in ${base.symbol}/${quote.currency.symbol} pair", |
| 46 | ); |
| 47 | } |
| 48 | } |