Stage 7.3: NPC scams (wicks, phishing airdrops, rug pools, fake support, forged transfers)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4279d48374
commit
6c5db17758
13 files changed
+691
-11
No files matched your search
@@ -349,6 +349,138 @@ namespace Decentralized
|
||||
});
|
||||
}
|
||||
|
||||
private static readonly float[] PoolW = { 128f, 50f, 64f, 64f, 50f, 60f };
|
||||
|
||||
/// <summary>第三方收益池:日息、储备、时间锁、审计、我的存款,存入 / 取出(合约调用,签名)。是不是骗局看不见。</summary>
|
||||
private static void YieldPools(CustomUIBuilder l, Wallet w, int day)
|
||||
{
|
||||
var sc = Session.Data.Scams;
|
||||
var pools = sc.Pools.Where(p => !p.Closed || p.Pending.Any(q => ChainAddress.Same(q.Wallet, w.Address))).ToList();
|
||||
l.AddSeparator();
|
||||
l.AddHeader(L.T("pool.h"));
|
||||
if (pools.Count == 0) { l.AddLabel(L.T("pool.none")); return; }
|
||||
TableHeader(l, PoolW, L.T("pool.col.name"), L.T("pool.col.rate"), L.T("pool.col.reserve"), L.T("pool.col.lock"), L.T("pool.col.audit"), L.T("pool.col.mine"));
|
||||
foreach (var p in pools)
|
||||
{
|
||||
var pp = p;
|
||||
string mine = Fmt.Num(p.Of(w.Address)) + (p.Pending.Any(q => ChainAddress.Same(q.Wallet, w.Address)) ? "+" + L.T("pool.pending") : "");
|
||||
TableRow(l, PoolW, p.Name + (p.Closed ? " " + L.T("pool.closed") : ""), (p.Rate * 100).ToString("0", CultureInfo.InvariantCulture) + "%", Fmt.Num(p.Reserve), L.T(p.Timelock ? "pool.yes" : "pool.no"), L.T(p.Audited ? "pool.yes" : "pool.no"), mine);
|
||||
if (p.Closed) continue;
|
||||
l.BeginRow(4f);
|
||||
l.AddButton(L.T("pool.deposit"), () => PoolCall(pp, true));
|
||||
if (p.Of(w.Address) > 0) l.AddButton(L.T(p.Timelock ? "pool.withdraw.lock" : "pool.withdraw", Tuning.YieldLockDays), () => PoolCall(pp, false));
|
||||
l.End();
|
||||
}
|
||||
}
|
||||
|
||||
private static void PoolCall(YieldPool p, bool deposit)
|
||||
{
|
||||
var d = Session.Data;
|
||||
var w = d.Hot;
|
||||
double v = 0;
|
||||
if (deposit)
|
||||
{
|
||||
if (!ReadAmount(out v)) return;
|
||||
if (w.Avail(Assets.CRC) + 1e-9 < v) { _message = L.T("msg.balance"); Open(); return; }
|
||||
if (p.Total + v > p.Cap + 1e-9) { _message = L.T("pool.err.cap", Fmt.Num(Math.Max(0, p.Cap - p.Total))); Open(); return; }
|
||||
}
|
||||
_message = L.T("hw.wait");
|
||||
Open();
|
||||
WalletWindow.OpenForBill(new WalletWindow.Bill
|
||||
{
|
||||
Contract = true, Asset = Assets.CRC, Amount = v, Spend = deposit ? v : 0, FeeAsset = deposit ? null : BestFeeAsset(w),
|
||||
Summary = L.T(deposit ? "pool.sum.in" : "pool.sum.out", p.Name, Fmt.Num(deposit ? v : p.Of(w.Address))),
|
||||
Execute = pw =>
|
||||
{
|
||||
int day = StoreStation.GetDayCounter();
|
||||
if (deposit) _message = d.Scams.Deposit(p, pw, v, Session.Price) ? L.T("pool.done.in", Fmt.Num(v), p.Name) : L.T("msg.balance");
|
||||
else
|
||||
{
|
||||
double amt = p.Of(pw.Address), got = d.Scams.Withdraw(p, pw, day);
|
||||
_message = amt <= 0 ? L.T("pool.err.none") : got > 0 ? L.T("pool.done.out", Fmt.Num(got)) : L.T("pool.done.lock", Fmt.Num(amt), day + Tuning.YieldLockDays);
|
||||
}
|
||||
Session.Save();
|
||||
Open();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>空投页:可领取的空投(名字、奖励、要求的授权)和当前钱包的授权(可撤销)。领取和撤销都是合约调用,签名时 PLEDGER 上会写明授权范围。</summary>
|
||||
private static void AirdropPage(CustomUIBuilder b)
|
||||
{
|
||||
var d = Session.Data;
|
||||
var w = d.Hot;
|
||||
int day = StoreStation.GetDayCounter();
|
||||
Columns(b, l =>
|
||||
{
|
||||
l.AddHeader(L.T("air.h"));
|
||||
var list = d.Scams.Airdrops.Where(a => !a.Claimed && a.Expire >= day).ToList();
|
||||
if (list.Count == 0) l.AddLabel(L.T("air.none"));
|
||||
foreach (var a in list)
|
||||
{
|
||||
var ad = a;
|
||||
l.AddLabel(L.T("air.row", a.Name, Fmt.Num(a.Reward), ApproveText(a.Approve, a.Asset), a.Expire));
|
||||
l.AddButton(L.T("air.claim"), () => ClaimAirdrop(ad));
|
||||
}
|
||||
}, r =>
|
||||
{
|
||||
r.AddHeader(L.T("air.approvals", WalletWindow.NameOf(w)));
|
||||
var aps = d.Scams.Approvals.Where(x => ChainAddress.Same(x.Wallet, w.Address)).ToList();
|
||||
if (aps.Count == 0) r.AddLabel(L.T("air.approvals.none"));
|
||||
foreach (var ap in aps)
|
||||
{
|
||||
int id = ap.Id;
|
||||
r.AddLabel(L.T("air.approval", ap.Spender, ApproveText(ap.Limit, ap.Asset)));
|
||||
r.AddButton(L.T("air.revoke"), () => RevokeApproval(id));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static string ApproveText(double limit, string asset) =>
|
||||
limit <= 0 ? L.T("air.noapprove") : double.IsPositiveInfinity(limit) ? L.T("air.unlimited", asset) : L.T("air.limited", asset, Fmt.Num(limit));
|
||||
|
||||
private static void ClaimAirdrop(Airdrop a)
|
||||
{
|
||||
var d = Session.Data;
|
||||
_message = L.T("hw.wait");
|
||||
Open();
|
||||
var w = d.Hot;
|
||||
WalletWindow.OpenForBill(new WalletWindow.Bill
|
||||
{
|
||||
Contract = true, Asset = Assets.CRC, Amount = 0, Spend = 0, FeeAsset = BestFeeAsset(w),
|
||||
Summary = L.T("air.sum", a.Name, ApproveText(a.Approve, a.Asset)),
|
||||
Execute = pw =>
|
||||
{
|
||||
var ap = d.Scams.Claim(a, pw, StoreStation.GetDayCounter(), d.Rng, out double got);
|
||||
_message = L.T("air.claimed", Fmt.Num(got));
|
||||
Log.Info($"领取空投 {a.Name}:得 {got},授权 {(ap == null ? "无" : ap.Asset + " " + ap.Limit)},骗局 {a.Scam}");
|
||||
Session.Save();
|
||||
Open();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private static void RevokeApproval(int id)
|
||||
{
|
||||
var d = Session.Data;
|
||||
var ap = d.Scams.Approvals.Find(x => x.Id == id);
|
||||
if (ap == null) return;
|
||||
var w = d.Own(ap.Wallet) ?? d.Hot;
|
||||
_message = L.T("hw.wait");
|
||||
Open();
|
||||
WalletWindow.OpenForBill(new WalletWindow.Bill
|
||||
{
|
||||
Contract = true, Asset = Assets.CRC, Amount = 0, Spend = 0, FeeAsset = BestFeeAsset(w),
|
||||
Summary = L.T("air.revoke.sum", ap.Spender, ap.Asset),
|
||||
Execute = pw =>
|
||||
{
|
||||
_message = ChainAddress.Same(pw.Address, ap.Wallet) && d.Scams.Revoke(id) ? L.T("air.revoked") : L.T("air.err.wallet");
|
||||
Session.Save();
|
||||
Open();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private static bool PonziVisible => Session.Data != null && (Session.Data.Ponzi.Open || Session.Data.Ponzi.Done || StoreStation.GetDayCounter() >= Tuning.PonziMinDay);
|
||||
private static double _ponziRate = 0.04;
|
||||
private static bool _ponziConfirm;
|
||||
@@ -843,6 +975,7 @@ namespace Decentralized
|
||||
if (_web3Tab == Web3Tab.Stake) { StakePage(b); return; }
|
||||
if (_web3Tab == Web3Tab.Predict) { PredictPage(b); return; }
|
||||
if (_web3Tab == Web3Tab.Ponzi) { PonziPage(b); return; }
|
||||
if (_web3Tab == Web3Tab.Airdrop) { AirdropPage(b); return; }
|
||||
if (_web3Tab == Web3Tab.Mining) { ReportPage(b); return; }
|
||||
if (_web3Tab == Web3Tab.Mixer) { MixerPage(b); return; }
|
||||
if (_web3Tab == Web3Tab.Black) { BlackPage(b); return; }
|
||||
@@ -1307,7 +1440,7 @@ namespace Decentralized
|
||||
Open();
|
||||
}
|
||||
|
||||
private enum Web3Tab { Trade, Stake, Predict, Ponzi, Mining, Mixer, Black }
|
||||
private enum Web3Tab { Trade, Stake, Airdrop, Predict, Ponzi, Mining, Mixer, Black }
|
||||
private static Web3Tab _web3Tab = Web3Tab.Trade;
|
||||
private static string _mixAsset = Assets.PSC;
|
||||
private static int _mixRounds = 2;
|
||||
@@ -1406,6 +1539,7 @@ namespace Decentralized
|
||||
}
|
||||
l.AddSeparator();
|
||||
l.AddLabel(L.T("spark.price", Fmt.Num(st.Spark)));
|
||||
YieldPools(l, w, day);
|
||||
}, r =>
|
||||
{
|
||||
r.AddHeader(L.T("stake.ops", WalletWindow.NameOf(w)));
|
||||
|
||||
Reference in new issue
Block a user