mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-17 01:37:54 +00:00
amount unit + tests
This commit is contained in:
parent
25ff880280
commit
ae51ce61c3
2 changed files with 264 additions and 0 deletions
120
lib/utilities/amount/amount_unit.dart
Normal file
120
lib/utilities/amount/amount_unit.dart
Normal file
|
@ -0,0 +1,120 @@
|
|||
import 'dart:math' as math;
|
||||
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:intl/number_symbols.dart';
|
||||
import 'package:intl/number_symbols_data.dart';
|
||||
import 'package:stackwallet/utilities/amount/amount.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
||||
enum AmountUnit {
|
||||
normal(0),
|
||||
milli(3),
|
||||
micro(6),
|
||||
nano(9),
|
||||
pico(12),
|
||||
femto(15),
|
||||
atto(18),
|
||||
;
|
||||
|
||||
const AmountUnit(this.shift);
|
||||
final int shift;
|
||||
}
|
||||
|
||||
extension AmountUnitExt on AmountUnit {
|
||||
String unitForCoin(Coin coin) {
|
||||
switch (this) {
|
||||
case AmountUnit.normal:
|
||||
return coin.ticker;
|
||||
case AmountUnit.milli:
|
||||
return "m${coin.ticker}";
|
||||
case AmountUnit.micro:
|
||||
return "µ${coin.ticker}";
|
||||
case AmountUnit.nano:
|
||||
if (coin == Coin.ethereum) {
|
||||
return "gwei";
|
||||
} else if (coin == Coin.wownero || coin == Coin.monero) {
|
||||
return "n${coin.ticker}";
|
||||
} else {
|
||||
return "sats";
|
||||
}
|
||||
case AmountUnit.pico:
|
||||
if (coin == Coin.ethereum) {
|
||||
return "mwei";
|
||||
} else if (coin == Coin.wownero || coin == Coin.monero) {
|
||||
return "p${coin.ticker}";
|
||||
} else {
|
||||
return "invalid";
|
||||
}
|
||||
case AmountUnit.femto:
|
||||
if (coin == Coin.ethereum) {
|
||||
return "kwei";
|
||||
} else {
|
||||
return "invalid";
|
||||
}
|
||||
case AmountUnit.atto:
|
||||
if (coin == Coin.ethereum) {
|
||||
return "wei";
|
||||
} else {
|
||||
return "invalid";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String displayAmount({
|
||||
required Amount amount,
|
||||
required String locale,
|
||||
required Coin coin,
|
||||
required int maxDecimalPlaces,
|
||||
}) {
|
||||
assert(maxDecimalPlaces >= 0);
|
||||
// ensure we don't shift past minimum atomic value
|
||||
final realShift = math.min(shift, amount.fractionDigits);
|
||||
|
||||
// shifted to unit
|
||||
final Decimal shifted = amount.decimal.shift(realShift);
|
||||
|
||||
// get shift int value without fractional value
|
||||
final BigInt wholeNumber = shifted.toBigInt();
|
||||
|
||||
// get decimal places to display
|
||||
final int places = math.max(0, amount.fractionDigits - realShift);
|
||||
|
||||
// start building the return value with just the whole value
|
||||
String returnValue = wholeNumber.toString();
|
||||
|
||||
// if any decimal places should be shown continue building the return value
|
||||
if (places > 0) {
|
||||
// get the fractional value
|
||||
final Decimal fraction = shifted - shifted.truncate();
|
||||
|
||||
// get final decimal based on max precision wanted
|
||||
final int actualDecimalPlaces = math.min(places, maxDecimalPlaces);
|
||||
|
||||
// get remainder string without the prepending "0."
|
||||
String remainder = fraction.toString().substring(2);
|
||||
|
||||
if (remainder.length > actualDecimalPlaces) {
|
||||
// trim unwanted trailing digits
|
||||
remainder = remainder.substring(0, actualDecimalPlaces);
|
||||
} else if (remainder.length < actualDecimalPlaces) {
|
||||
// pad with zeros to achieve requested precision
|
||||
for (int i = remainder.length; i < actualDecimalPlaces; i++) {
|
||||
remainder += "0";
|
||||
}
|
||||
}
|
||||
|
||||
// get decimal separator based on locale
|
||||
final String separator =
|
||||
(numberFormatSymbols[locale] as NumberSymbols?)?.DECIMAL_SEP ??
|
||||
(numberFormatSymbols[locale.substring(0, 2)] as NumberSymbols?)
|
||||
?.DECIMAL_SEP ??
|
||||
".";
|
||||
|
||||
// append separator and fractional amount
|
||||
returnValue += "$separator$remainder";
|
||||
}
|
||||
|
||||
// return the value with the proper unit symbol
|
||||
return "$returnValue ${unitForCoin(coin)}";
|
||||
}
|
||||
}
|
144
test/utilities/amount/amount_unit_test.dart
Normal file
144
test/utilities/amount/amount_unit_test.dart
Normal file
|
@ -0,0 +1,144 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:stackwallet/utilities/amount/amount.dart';
|
||||
import 'package:stackwallet/utilities/amount/amount_unit.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
||||
void main() {
|
||||
test("displayAmount BTC", () {
|
||||
final Amount amount = Amount(
|
||||
rawValue: BigInt.from(1012345678),
|
||||
fractionDigits: 8,
|
||||
);
|
||||
|
||||
expect(
|
||||
AmountUnit.normal.displayAmount(
|
||||
amount: amount,
|
||||
locale: "en_US",
|
||||
coin: Coin.bitcoin,
|
||||
maxDecimalPlaces: 8,
|
||||
),
|
||||
"10.12345678 BTC",
|
||||
);
|
||||
|
||||
expect(
|
||||
AmountUnit.milli.displayAmount(
|
||||
amount: amount,
|
||||
locale: "en_US",
|
||||
coin: Coin.bitcoin,
|
||||
maxDecimalPlaces: 8,
|
||||
),
|
||||
"10123.45678 mBTC",
|
||||
);
|
||||
|
||||
expect(
|
||||
AmountUnit.micro.displayAmount(
|
||||
amount: amount,
|
||||
locale: "en_US",
|
||||
coin: Coin.bitcoin,
|
||||
maxDecimalPlaces: 8,
|
||||
),
|
||||
"10123456.78 µBTC",
|
||||
);
|
||||
|
||||
expect(
|
||||
AmountUnit.nano.displayAmount(
|
||||
amount: amount,
|
||||
locale: "en_US",
|
||||
coin: Coin.bitcoin,
|
||||
maxDecimalPlaces: 8,
|
||||
),
|
||||
"1012345678 sats",
|
||||
);
|
||||
final dec = Decimal.parse("10.123456789123456789");
|
||||
|
||||
expect(dec.toString(), "10.123456789123456789");
|
||||
});
|
||||
|
||||
test("displayAmount ETH", () {
|
||||
final Amount amount = Amount.fromDecimal(
|
||||
Decimal.parse("10.123456789123456789"),
|
||||
fractionDigits: Coin.ethereum.decimals,
|
||||
);
|
||||
|
||||
expect(
|
||||
AmountUnit.normal.displayAmount(
|
||||
amount: amount,
|
||||
locale: "en_US",
|
||||
coin: Coin.ethereum,
|
||||
maxDecimalPlaces: 8,
|
||||
),
|
||||
"10.12345678 ETH",
|
||||
);
|
||||
|
||||
expect(
|
||||
AmountUnit.normal.displayAmount(
|
||||
amount: amount,
|
||||
locale: "en_US",
|
||||
coin: Coin.ethereum,
|
||||
maxDecimalPlaces: 18,
|
||||
),
|
||||
"10.123456789123456789 ETH",
|
||||
);
|
||||
|
||||
expect(
|
||||
AmountUnit.milli.displayAmount(
|
||||
amount: amount,
|
||||
locale: "en_US",
|
||||
coin: Coin.ethereum,
|
||||
maxDecimalPlaces: 9,
|
||||
),
|
||||
"10123.456789123 mETH",
|
||||
);
|
||||
|
||||
expect(
|
||||
AmountUnit.micro.displayAmount(
|
||||
amount: amount,
|
||||
locale: "en_US",
|
||||
coin: Coin.ethereum,
|
||||
maxDecimalPlaces: 8,
|
||||
),
|
||||
"10123456.78912345 µETH",
|
||||
);
|
||||
|
||||
expect(
|
||||
AmountUnit.nano.displayAmount(
|
||||
amount: amount,
|
||||
locale: "en_US",
|
||||
coin: Coin.ethereum,
|
||||
maxDecimalPlaces: 1,
|
||||
),
|
||||
"10123456789.1 gwei",
|
||||
);
|
||||
|
||||
expect(
|
||||
AmountUnit.pico.displayAmount(
|
||||
amount: amount,
|
||||
locale: "en_US",
|
||||
coin: Coin.ethereum,
|
||||
maxDecimalPlaces: 18,
|
||||
),
|
||||
"10123456789123.456789 mwei",
|
||||
);
|
||||
|
||||
expect(
|
||||
AmountUnit.femto.displayAmount(
|
||||
amount: amount,
|
||||
locale: "en_US",
|
||||
coin: Coin.ethereum,
|
||||
maxDecimalPlaces: 4,
|
||||
),
|
||||
"10123456789123456.789 kwei",
|
||||
);
|
||||
|
||||
expect(
|
||||
AmountUnit.atto.displayAmount(
|
||||
amount: amount,
|
||||
locale: "en_US",
|
||||
coin: Coin.ethereum,
|
||||
maxDecimalPlaces: 1,
|
||||
),
|
||||
"10123456789123456789 wei",
|
||||
);
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue