using System.Globalization; namespace PalladiumWallet.Core.Wallet; /// /// Satoshi ↔ coin unit conversion (8 decimal places) for display and input. /// All internal computation uses satoshis; the formatted string is presentation only. /// public static class CoinAmount { public const long SatsPerCoin = 100_000_000; /// Selectable display units (config §8). public static readonly string[] Units = ["PLM", "mPLM", "µPLM", "sat"]; /// (satoshis per unit, displayed decimals) for each unit. private static (long Factor, int Decimals) Of(string unit) => unit switch { "PLM" => (SatsPerCoin, 8), "mPLM" => (100_000, 5), "µPLM" => (100, 2), "sat" => (1, 0), _ => throw new ArgumentException($"Unknown coin unit: {unit}", nameof(unit)), }; public static string Format(long sats, string unit = "") => (sats / (decimal)SatsPerCoin).ToString("0.00000000", CultureInfo.InvariantCulture) + (unit.Length > 0 ? " " + unit : ""); /// Formats in the chosen unit (e.g. 150000 sat → "1.50000 mPLM"). public static string FormatIn(long sats, string unit, bool withLabel = true) { var (factor, decimals) = Of(unit); var value = (sats / (decimal)factor).ToString( decimals == 0 ? "0" : "0." + new string('0', decimals), CultureInfo.InvariantCulture); return withLabel ? $"{value} {unit}" : value; } /// Parses an amount expressed in the chosen unit into satoshis. public static bool TryParseIn(string text, string unit, out long sats) { sats = 0; var (factor, _) = Of(unit); text = text.Trim().Replace(',', '.'); if (!decimal.TryParse(text, NumberStyles.Number, CultureInfo.InvariantCulture, out var value) || value < 0) return false; try { var satsDecimal = value * factor; if (satsDecimal % 1 != 0) return false; sats = (long)satsDecimal; } catch (OverflowException) { return false; } return true; } /// Parses a coin amount (decimal point or comma) into satoshis. public static bool TryParseCoins(string text, out long sats) { sats = 0; text = text.Trim().Replace(',', '.'); if (!decimal.TryParse(text, NumberStyles.Number, CultureInfo.InvariantCulture, out var coins) || coins < 0) return false; try { var satsDecimal = coins * SatsPerCoin; if (satsDecimal % 1 != 0) return false; sats = (long)satsDecimal; } catch (OverflowException) { return false; } return true; } }