diff --git a/src/Decentralized/ModFiles/Localization/en.csv b/src/Decentralized/ModFiles/Localization/en.csv index a030996..bf29fb7 100644 --- a/src/Decentralized/ModFiles/Localization/en.csv +++ b/src/Decentralized/ModFiles/Localization/en.csv @@ -163,3 +163,12 @@ trade.h,"Trade" web3.wallet.h,"On-chain wallet" trade.hint,"Buying pays in the quote coin; |selling sells the traded coin." bank.hint,"Deposit turns credits into CRC; |withdrawing turns CRC back into credits |and passes compliance review." +col.peg,"Price" +col.status,"Status" +stable.ok,"Pegged" +stable.depeg,"Depegged" +stable.warn,"Warning: staking subsidy pool low" +stable.spiral,"Collapsing" +aml.window,"Withdrawn in the last {0} days: {1} credits (cumulative line {2})" +aml.taint,"Wallet taint share: {0}%" +aml.chance,"At this amount, estimated review chance: {0}%" diff --git a/src/Decentralized/ModFiles/Localization/zh.csv b/src/Decentralized/ModFiles/Localization/zh.csv index 61df222..031330a 100644 --- a/src/Decentralized/ModFiles/Localization/zh.csv +++ b/src/Decentralized/ModFiles/Localization/zh.csv @@ -162,3 +162,12 @@ trade.h,"交易" web3.wallet.h,"链上钱包" trade.hint,"买入按计价币的数量支付;|卖出按所交易币的数量卖出。" bank.hint,"存入把信用点换成 CRC;|提取把 CRC 换回信用点,|提取要过合规审查。" +col.peg,"价格" +col.status,"状态" +stable.ok,"锚定正常" +stable.depeg,"脱锚" +stable.warn,"预兆:质押补贴池告急" +stable.spiral,"崩盘中" +aml.window,"近 {0} 天已提取 {1} 信用点(累计线 {2})" +aml.taint,"钱包污点比例:{0}%" +aml.chance,"按这个数量,预计审查概率:{0}%" diff --git a/src/Decentralized/TerminalWindow.cs b/src/Decentralized/TerminalWindow.cs index aea83af..0655526 100644 --- a/src/Decentralized/TerminalWindow.cs +++ b/src/Decentralized/TerminalWindow.cs @@ -139,11 +139,54 @@ namespace Decentralized r.AddHeader(L.T("bank.ops")); foreach (var line in L.T("bank.hint").Split('|')) r.AddLabel(line); AmountRow(r); + AmlPreview(r); r.AddButton(L.T("trade.deposit"), Deposit); r.AddButton(L.T("trade.withdraw"), Withdraw); }); } + /// 提取前的合规审查提示:本周已提取的累计、污点比例,以及按当前数量估算的审查概率。 + private static void AmlPreview(CustomUIBuilder b) + { + var d = Session.Data; + int day = StoreStation.GetDayCounter(); + double rent = Session.Rent(); + double recent = d.Exchange.History.Where(h => h.Key > day - Tuning.AmlWindowDays).Sum(h => h.Value); + b.AddSeparator(); + b.AddLabel(L.T("aml.window", Tuning.AmlWindowDays, Fmt.Credits(recent), Fmt.Credits(Tuning.AmlCumRents * rent))); + double total = d.Hot.Value(Session.Price); + double taintRatio = total > 0 ? d.Hot.Taint / total : 0; + b.AddLabel(L.T("aml.taint", (int)Math.Round(taintRatio * 100))); + if (double.TryParse((_amount ?? "").Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out double v) && v > 0) + { + double value = Math.Min(v, d.Hot.Get(Assets.CRC)) * Session.Price(Assets.CRC); + double taint = total > 0 ? d.Hot.Taint * Math.Min(1, value / total) : 0; + double chance = Exchange.HitChance(value, taint, recent, rent, d.Hot.Flagged); + b.AddLabel(L.T("aml.chance", (int)Math.Round(chance * 100))); + } + } + + private static readonly float[] StableW = { 80f, 100f, 220f }; + + private static string StableStatus(Stablecoins st, string asset, int day) + { + double p = st.Price(asset); + if (asset == Assets.CRA && st.CraWarning(day)) return L.T("stable.warn"); + if (asset == Assets.CRA && p < 0.97) return L.T("stable.spiral"); + return p < 0.99 ? L.T("stable.depeg") : L.T("stable.ok"); + } + + /// 稳定币行情:价格与状态(脱锚、预兆)。 + private static void StableTable(CustomUIBuilder b) + { + var st = Session.Data.Stable; + int day = StoreStation.GetDayCounter(); + b.AddSeparator(); + TableHeader(b, StableW, L.T("col.asset"), L.T("col.peg"), L.T("col.status")); + foreach (var a in new[] { Assets.CRC, Assets.CRT, Assets.CRA }) + TableRow(b, StableW, a, Fmt.Num(st.Price(a)), StableStatus(st, a, day)); + } + private static void TradeRows(CustomUIBuilder b, Venue venue) { foreach (var pool in Session.Data.Market.Pools.Where(x => x.Venue == venue)) @@ -199,6 +242,7 @@ namespace Decentralized l.AddSeparator(); l.AddLabel(L.T("wallet.total", Fmt.Credits(w.Value(Session.Price)))); if (w.Taint > 0.5) l.AddLabel(L.T("wallet.taint", Fmt.Credits(w.Taint))); + StableTable(l); }, r => { r.AddHeader(L.T("trade.h"));