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"));