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
@@ -1301,6 +1301,84 @@ internal static class Program
|
||||
Check(Ponzi.InflowMean(20, 0.08, 50) > Ponzi.InflowMean(20, 0.04, 50) * 2, "日息高于 4% 时存入按指数放大");
|
||||
});
|
||||
|
||||
Test("NPC 骗局:插针、空投与授权、第三方收益池", () =>
|
||||
{
|
||||
// 插针:出现频率、幅度、标记价只吃一半、当晚回去
|
||||
int wicks = 0, n = 4000;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
var mk = Market.CreateDefault(20); var rng = new Rng((ulong)(i + 1));
|
||||
double p0 = mk.Price;
|
||||
mk.Open(new List<MarketEvent>(), rng, 20);
|
||||
double open = mk.OpenPrice;
|
||||
double w = mk.TryWick(rng, 20);
|
||||
if (w == 0) continue;
|
||||
wicks++;
|
||||
Check(Math.Abs(Math.Abs(Math.Log(mk.Price / open)) - Math.Abs(w)) < 1e-9 && Math.Abs(w) >= Tuning.WickMin && Math.Abs(w) <= Tuning.WickMax, "插针幅度");
|
||||
Check(Math.Abs(mk.Mark - (open + mk.Price) / 2) < 1e-9 && mk.OpenPrice == open, "标记价用开门前的价格和插针价平均");
|
||||
double back = mk.WickBack, before = mk.Price;
|
||||
var none = new List<MarketEvent>();
|
||||
// 夜里:先回去 WickBack,再走正常回归
|
||||
var copy = Market.CreateDefault(20); copy.Main.SetPrice(before * Math.Exp(-w * back), Tuning.PoolDepth(20));
|
||||
mk.Night(none, new Rng(9), 20, a => 1); copy.Night(none, new Rng(9), 20, a => 1);
|
||||
Check(Math.Abs(mk.Price - copy.Price) / copy.Price < 0.05 && mk.Wick == 0, "当晚按比例回去");
|
||||
}
|
||||
Check(Math.Abs(wicks / (double)n - Tuning.WickChance) < 0.015, $"插针频率约 {Tuning.WickChance}:{wicks / (double)n:0.000}");
|
||||
// 空投
|
||||
var sc = new Scams(); var r2 = new Rng(5);
|
||||
var assets = new[] { Assets.CRT, Assets.PSC, Assets.CRC };
|
||||
int scam = 0, typo = 0, unlimited = 0;
|
||||
for (int i = 0; i < 2000; i++)
|
||||
{
|
||||
var a = sc.NewAirdrop(10, r2, assets);
|
||||
if (a.Scam) { scam++; if (double.IsPositiveInfinity(a.Approve) || a.Approve >= 20 * a.Reward - 10) unlimited++; if (!new[] { "Poinbase", "PSC Foundation", "RatDigg", "Revolution DAO", "Gutter Labs", "Station Rewards" }.Contains(a.Name)) typo++; }
|
||||
else Check(!double.IsPositiveInfinity(a.Approve) && a.Approve <= 60, "正规空投不要大额授权");
|
||||
}
|
||||
Check(Math.Abs(scam / 2000.0 - Tuning.AirdropScam) < 0.04 && unlimited == scam && typo > scam * 0.4, $"钓鱼占比 {scam / 2000.0:0.00},全部要无上限或远超奖励的授权,过半名字是仿冒 {typo}");
|
||||
var wl = new Wallet { Address = "0xa" }; wl.Add(Assets.CRT, 1000);
|
||||
var fake = new Airdrop { Id = 1, Name = "P0inbase", Asset = Assets.CRT, Approve = double.PositiveInfinity, Reward = 200, Scam = true, Expire = 12 };
|
||||
var ap = sc.Claim(fake, wl, 10, r2, out double got);
|
||||
Check(ap != null && ap.Scam && got < 20 && sc.Claim(fake, wl, 10, r2, out _) == null, "钓鱼空投只给诱饵,不能重复领");
|
||||
sc.Airdrops.Clear(); sc.Pools.Clear();
|
||||
var ev = sc.Night(ap.DrainDay, r2, x => x == "0xa" ? wl : null, assets);
|
||||
Check(ev.Any(e => e.Kind == "drain" && Math.Abs(e.Amount - 1000) < 1e-9) && wl.Get(Assets.CRT) < 1e-9, "到期那晚转走这个币");
|
||||
var wl2 = new Wallet { Address = "0xb" }; wl2.Add(Assets.CRT, 1000);
|
||||
var ap2 = sc.Claim(new Airdrop { Id = 2, Name = "x", Asset = Assets.CRT, Approve = double.PositiveInfinity, Scam = true, Expire = 12 }, wl2, 10, r2, out _);
|
||||
Check(sc.Revoke(ap2.Id), "撤销授权");
|
||||
sc.Night(ap2.DrainDay, r2, x => wl2, assets);
|
||||
Check(Math.Abs(wl2.Get(Assets.CRT) - 1000) < 1e-9, "撤销后不会被转走");
|
||||
var good = sc.Claim(new Airdrop { Id = 3, Name = "Poinbase", Asset = Assets.CRT, Approve = 0, Reward = 50, Expire = 12 }, wl2, 10, r2, out double g2);
|
||||
Check(good == null && Math.Abs(g2 - 50) < 1e-9, "正规空投给奖励、不留授权");
|
||||
// 收益池:骗局概率随日息、时间锁、审计变化
|
||||
Check(Scams.ScamChance(0.03, false, false) > Scams.ScamChance(0.01, false, false) && Scams.ScamChance(0.02, true, true) < Scams.ScamChance(0.02, false, false), "日息越高越像骗局,时间锁和审计降低概率");
|
||||
// 正规池:计息、储备耗尽退本金;时间锁取款延迟到账
|
||||
var pool = new YieldPool { Id = 1, Name = "ok", Rate = 0.02, Reserve = 100, Cap = 1e9, Timelock = true, OpenDay = 1 };
|
||||
var sc2 = new Scams(); sc2.Pools.Add(pool);
|
||||
var w3 = new Wallet { Address = "0xc" }; w3.Add(Assets.CRC, 3000);
|
||||
Check(sc2.Deposit(pool, w3, 1000, a => 1) && Math.Abs(w3.Get(Assets.CRC) - 2000) < 1e-9, "存入");
|
||||
sc2.Night(2, new Rng(1), x => w3, assets);
|
||||
Check(Math.Abs(pool.Of("0xc") - 1020) < 1e-9 && Math.Abs(pool.Reserve - 80) < 1e-9, "计息从储备出");
|
||||
Check(sc2.Withdraw(pool, w3, 3) == 0 && pool.Pending.Count == 1, "时间锁:进取款队列");
|
||||
sc2.Night(3 + Tuning.YieldLockDays, new Rng(1), x => w3, assets);
|
||||
Check(Math.Abs(w3.Get(Assets.CRC) - 3020) < 1e-9, "到期到账");
|
||||
var pool2 = new YieldPool { Id = 2, Name = "dry", Rate = 0.03, Reserve = 10, Cap = 1e9, OpenDay = 1 };
|
||||
sc2.Pools.Add(pool2); sc2.Deposit(pool2, w3, 1000, a => 1);
|
||||
var evd = sc2.Night(5, new Rng(1), x => w3, assets);
|
||||
Check(evd.Any(e => e.Kind == "dry") && pool2.Closed && Math.Abs(w3.Get(Assets.CRC) - 3020) < 1e-9, "储备不够付利息:退本金关闭");
|
||||
// 骗局池:跑路
|
||||
int rugs = 0;
|
||||
for (ulong sd = 1; sd <= 400; sd++)
|
||||
{
|
||||
var p = new YieldPool { Id = 9, Name = "scam", Rate = 0.03, Reserve = 1e9, Cap = 1e9, Scam = true, OpenDay = 1 };
|
||||
var s3 = new Scams(); s3.Pools.Add(p);
|
||||
var w4 = new Wallet { Address = "0xd" }; w4.Add(Assets.CRC, 100);
|
||||
s3.Deposit(p, w4, 100, a => 1);
|
||||
var e4 = s3.Night(2, new Rng(sd), x => w4, assets);
|
||||
if (e4.Any(e => e.Kind == "rug")) { rugs++; Check(p.Closed && p.Total == 0 && w4.Get(Assets.CRC) < 1e-9, "跑路后存款没了"); }
|
||||
}
|
||||
Check(Math.Abs(rugs / 400.0 - Tuning.YieldRugNightly) < 0.05, $"骗局池每晚跑路概率:{rugs / 400.0:0.00}");
|
||||
});
|
||||
|
||||
Test("预测市场:先验概率", () =>
|
||||
{
|
||||
Check(Math.Abs(PredictMath.PurityAtLeast(8500, 8000, 8999) - 0.5) < 1e-9, "纯度 8500 以上一半");
|
||||
|
||||
Reference in new issue
Block a user