污点按币种记脏枚数、只在 Web3 钱包里;Poinbase 只收干净的币;删除出金审查;永续操纵只记罪证;泄露记罪证;剧情替换;存档迁移到数据版本 5

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ZHU MINCHAOandClaude Opus 5.5 committed 2026-11-08 20:04:09 +08:00
1 parent f0a6051591
commit 34b70023c9
37 files changed
+744 -647

No files matched your search

+23 -5
View File
@@ -255,7 +255,8 @@ namespace Decentralized
b.End();
b.BeginPanel(130f, 26f, TextAnchor.MiddleRight, 0f, 0f);
_clear.Add(b.Last.image);
b.AddLabel(Amt(q) + (w.Frozen.TryGetValue(a, out var fz) && fz > 0 ? L.T("hw.balance.frozen", Amt(fz)) : ""));
double dq = w.DirtyOf(a);
b.AddLabel(Amt(q) + (w.Frozen.TryGetValue(a, out var fz) && fz > 0 ? L.T("hw.balance.frozen", Amt(fz)) : "") + (dq > 1e-9 ? L.T("hw.balance.dirty", Amt(dq)) : ""));
b.End();
b.BeginPanel(RowW - 12f - 90f - 130f, 26f, TextAnchor.MiddleRight, 0f, 0f);
_clear.Add(b.Last.image);
@@ -266,7 +267,7 @@ namespace Decentralized
}
b.AddSeparator();
b.AddLabel(L.T("hw.total", Fmt.Credits(w.Value(Session.Price))));
if (w.Taint > 0.5) b.AddLabel(L.T("wallet.taint", Fmt.Credits(w.Taint)));
if (w.Taint(Session.Price) > 0.5) b.AddLabel(L.T("wallet.taint", Fmt.Credits(w.Taint(Session.Price))));
if (Pending != null) b.AddLabel(Pending.Contract ? L.T("hw.pending.sign", Pending.Summary) : L.T("hw.pending.bill", Pending.Summary));
if (Congested) b.AddLabel(L.T("hw.congested"), "congest_note");
b.AddSpace(6f);
@@ -345,11 +346,24 @@ namespace Decentralized
if (bill.Asset != dev.Asset) return L.T("hw.err.asset", bill.Asset);
if (v + 1e-9 < bill.Amount) return L.T("hw.err.short", Amt(bill.Amount), bill.Asset);
}
else if (IsPoinbase(to)) { if (!Exchange.Listed.Contains(dev.Asset)) return L.T("hw.err.poinbase", dev.Asset); }
else if (IsPoinbase(to))
{
if (!Exchange.Listed.Contains(dev.Asset)) return L.T("hw.err.poinbase", dev.Asset);
// Poinbase 只收干净的币:这种币最多充干净的枚数(手续费同币种时先扣掉)
double clean = CleanAfterFee(w, dev.Asset, dev.Asset == FeeAssetOf(dev) ? FeeIn(dev.Asset, dev.Tier) : 0);
if (v > clean + 1e-6) return L.T("hw.err.tainted", Amt(w.DirtyOf(dev.Asset)), dev.Asset, Amt(clean));
}
else if (Session.Data.Own(to) == null && Known(to)) return L.T("hw.err.nobill");
return null;
}
/// <summary>扣掉同币种的手续费(按脏比例带走一点脏的)之后,这种币干净、能动用的枚数。</summary>
private static double CleanAfterFee(Wallet w, string asset, double fee)
{
double r = w.DirtyRatio(asset);
return Math.Max(0, Math.Min(w.Avail(asset) - fee, (w.Get(asset) - fee) * (1 - r)));
}
private static Bill Match(string to) => Pending != null && !Pending.Contract && ChainAddress.Same(Pending.Address, to) ? Pending : null;
/// <summary>有过往来的地址(平台、商家、混币器、兑换处):没有账单时对方不收。</summary>
@@ -539,7 +553,7 @@ namespace Decentralized
Open(dev);
}
/// <summary>动画走完(或点了跳过):交易落地。付账单的执行终端那边的动作;转给自己的钱包或 Poinbase 的按比例带上污点;没人用的地址,币就没了。</summary>
/// <summary>动画走完(或点了跳过):交易落地。付账单的执行终端那边的动作;转给自己的钱包的按比例带上污点,转给 Poinbase 的只转干净的、污点留在钱包;没人用的地址,币就没了。</summary>
private static void Finish(Device dev)
{
var tx = dev.Tx;
@@ -562,6 +576,8 @@ namespace Decentralized
}
int day = StoreStation.GetDayCounter();
double amt = tx.To != null ? Math.Min(tx.Amount, w.Avail(tx.Asset)) : 0;
// Poinbase 只收干净的币:落地时价格可能变了,超出干净部分的不转(留在钱包)
if (tx.To != null && tx.Bill == null && IsPoinbase(tx.To)) amt = Math.Min(amt, w.CleanAvail(tx.Asset));
if (tx.To != null)
{
d.Chain(w.Address, tx.To, tx.Asset, amt, tx.FeeAsset == tx.Asset ? tx.Fee : 0, tx.Block);
@@ -586,7 +602,9 @@ namespace Decentralized
if (tx.To == null) return;
var own = d.Own(tx.To);
Wallet target = own ?? (IsPoinbase(tx.To) ? d.Poinbase : new Wallet());
Wallet.Transfer(w, target, tx.Asset, amt, Session.Price);
// Poinbase 只收干净的币:污点留在钱包里
if (target == d.Poinbase) Wallet.TransferClean(w, target, tx.Asset, amt, Session.Price);
else Wallet.Transfer(w, target, tx.Asset, amt, Session.Price);
if (own == null && target != d.Poinbase) Log.Info($"转进没人用的地址 {tx.To}:{amt} {tx.Asset}");
if (own == null && d.Scams.ScamAddrs.Any(a => ChainAddress.Same(a, tx.To))) PlayerStore.Instance.AddNightLog(L.T("nightlog.scam.sent", Fmt.Num(amt), tx.Asset), "cc7755");
TerminalWindow.Refresh(null);