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
+13
-2
@@ -2,7 +2,18 @@
|
|||||||
|
|
||||||
## 未发布
|
## 未发布
|
||||||
|
|
||||||
### 第七阶段:预测市场与操纵(7.1 预测市场、7.2 操纵检出与高息理财)
|
### 第七阶段:预测市场、操纵与骗局(7.1、7.2、7.3)
|
||||||
|
|
||||||
|
- 7.3 NPC 骗局:
|
||||||
|
- 插针:第 10 天起,每天开门 7% 概率价格被瞬间打上或砸下 15–30%(PSC 主池);七成当晚回去 60–100%,三成是真的(不回去)。永续当晚的标记价仍用"开门价与收盘价的平均",开门价取插针前的价格,所以强平只吃一半;预测盘和夜间结算读回去之后的价格。
|
||||||
|
- 空投与钓鱼授权(Web3 新增"空投"页签):每晚 35% 概率出一个空投,2 天内可领;四成是钓鱼。正规空投不要授权或只要 10–60 的小额授权,奖励 20–120 CRC;钓鱼空投七成要"无上限授权"、三成要奖励 20–100 倍的大额授权,名字六成是仿冒(0/o、1/l、m/n 之类),领到的只有标称奖励的 5%,1–2 晚后在授权额度内把那个钱包里的这种币转走(污点按比例一起走)。领取是合约调用,PLEDGER 核对页写明授权范围;右栏列出当前钱包的授权,可以签名撤销,撤销后就转不走。
|
||||||
|
- 第三方收益池(质押页下面):同时最多 3 个,每晚 25% 概率新开;日息 1 / 2 / 3%,储备、时间锁、审计看得见,是否骗局看不见:骗局概率按日息 15 / 40 / 75%,有时间锁 −25%,有审计 −20%。正规池从储备付利息,储备付不起时退本金关闭;骗局池照常显示利息,每晚 18% 概率跑路,存款和在途取款全没。有时间锁的池子取款要等 2 天(等的时候跑路也没了)。单池上限 2000 + 60 × 天数。存入、取出都是合约调用,污点与成本随存款进出。
|
||||||
|
- 假客服:第 10 天起每天 4% 概率,一位"Poinbase 客服"上门说账户被风控,要把 300–1500 CRC 转到"安全地址"。地址记为骗子地址,转过去的币就没了,晨间日志点明。
|
||||||
|
- 伪造转账:第 10 天起用币付款的顾客里 8% 是骗子,开口说"已经转过去了,截图给你看,赶紧给货"(正常顾客说"链上确认要一会儿");成交后信用点被扣回、币不到账,晨间日志列出谁拿走了什么。
|
||||||
|
- 假买墙、貔貅币依赖 NPC 项目币,挪到阶段 8 和发币一起做。
|
||||||
|
- 游戏内验证:空投页列出 4 个空投(含"Revo1ution DAO 授权 PSC 9,120""PSC Foundation 授权 CRT 无上限");签名领取钓鱼空投只得 4 CRC,授权出现在右栏;领"Revo1ution DAO"后过夜,晨间日志"主钱包 的 20 PSC 被「Revo1ution DAO」用授权转走了",钱包 PSC 归零;收益池表格(日息 / 储备 / 时间锁 / 审计 / 存款)显示正常,签名存入 500 到 3% 的池子,三晚后 546;插针让 PSC 估值 2000 → 2445;假客服上门对话。没有在游戏里验证:撤销授权、骗局池跑路和正规池退本金(单元测试覆盖)、时间锁取款到账、伪造转账顾客(要自然出现的用币顾客)、转给假客服地址后的日志、英文界面。
|
||||||
|
|
||||||
|
#### 7.1、7.2
|
||||||
|
|
||||||
- 高息理财改用链上钱包:开张(宣传费 800 CRC)和卷走都是合约调用,用当前钱包签名;产品记下发行钱包,每晚垫付的利息从它出,卷走的池子进它(污点全额),卷走要用发行钱包签名。游戏内验证:主钱包签名开张 6%,三夜后签名卷走 1634,钱包 CRC 1000 → 200 → 1833,污点 1634,卷走手续费 1.13 CRT。
|
- 高息理财改用链上钱包:开张(宣传费 800 CRC)和卷走都是合约调用,用当前钱包签名;产品记下发行钱包,每晚垫付的利息从它出,卷走的池子进它(污点全额),卷走要用发行钱包签名。游戏内验证:主钱包签名开张 6%,三夜后签名卷走 1634,钱包 CRC 1000 → 200 → 1833,污点 1634,卷走手续费 1.13 CRT。
|
||||||
- 柜台线人接进预测市场:游戏里卖消息的顾客(乞丐、线人,提前 1–4 天说出新闻事件)、传闻纸条、派系特权都会把事件以"已知"排进日程;每天开门补盘时,对每个这样的、开始日在后天及以后的事件保证有一个盘口(窗口就是开始那天),开盘价按公开信息下的基础概率(不看冷却,每天有事件的概率取 35%),不因为已经排期而抬高——当晚价格才向 92% 靠拢,知道的人能赚到中间的差;押「是」算内幕单。游戏内验证:调试排一个 3 天后的已知停电,开盘出现"第 19 天:出现「停电」",是 0.03,线索"排期:第 19 天开始"。
|
- 柜台线人接进预测市场:游戏里卖消息的顾客(乞丐、线人,提前 1–4 天说出新闻事件)、传闻纸条、派系特权都会把事件以"已知"排进日程;每天开门补盘时,对每个这样的、开始日在后天及以后的事件保证有一个盘口(窗口就是开始那天),开盘价按公开信息下的基础概率(不看冷却,每天有事件的概率取 35%),不因为已经排期而抬高——当晚价格才向 92% 靠拢,知道的人能赚到中间的差;押「是」算内幕单。游戏内验证:调试排一个 3 天后的已知停电,开盘出现"第 19 天:出现「停电」",是 0.03,线索"排期:第 19 天开始"。
|
||||||
@@ -15,7 +26,7 @@
|
|||||||
- 复核(ops `research/manipsim`,第 30 天):先空后砸本身不赚——永续单边滑点加现货来回价差,砸盘 4000–20000 配 5000–20000 的空单平均净亏 66–4400,只有砸盘 4 万(推价 57%)配小空单才勉强为正;尾盘拉价格过价格盘阈值在没有检出时几乎稳赢(成本 40–125,净赚 570–1390,亏钱概率 ≈ 0),加检出后下注 ≤ 1000 平均只赚 100–240、亏钱概率 40–60%,下注 3000 平均亏 400–1500。
|
- 复核(ops `research/manipsim`,第 30 天):先空后砸本身不赚——永续单边滑点加现货来回价差,砸盘 4000–20000 配 5000–20000 的空单平均净亏 66–4400,只有砸盘 4 万(推价 57%)配小空单才勉强为正;尾盘拉价格过价格盘阈值在没有检出时几乎稳赢(成本 40–125,净赚 570–1390,亏钱概率 ≈ 0),加检出后下注 ≤ 1000 平均只赚 100–240、亏钱概率 40–60%,下注 3000 平均亏 400–1500。
|
||||||
- 游戏内验证:Poinbase 买 4000 CRC 的 PSC,推价累计 +15.1%,价格盘线索栏显示"你推价 +15.1%,易被查"。没有在游戏里验证:被查后的没收、新闻、永续冻结(单元测试覆盖预测盘判定;永续平仓的判定只有代码路径)。
|
- 游戏内验证:Poinbase 买 4000 CRC 的 PSC,推价累计 +15.1%,价格盘线索栏显示"你推价 +15.1%,易被查"。没有在游戏里验证:被查后的没收、新闻、永续冻结(单元测试覆盖预测盘判定;永续平仓的判定只有代码路径)。
|
||||||
|
|
||||||
### 第七阶段:预测市场(7.1)
|
#### 7.1
|
||||||
|
|
||||||
- Web3 页"预测"子页(游戏第 8 天起,Web3 治理社区已买下):每个盘口是一道是非题,开盘当天到窗口开始前可以买卖,窗口最后一天夜里结算;每天开门后补盘,同时开放 3–6 个,每天最多新开 2 个。资金走链上钱包的 CRC:买入、全部卖出都是合约调用,要在钱包上签名(和质押一样;买入的手续费在核对页选档、用 CRC 付,卖出用价值最高的币付);持仓记在签名的钱包名下,结算时兑付回这个钱包,同一盘口各钱包只能押同一边,持仓上限和内幕判定按盘口合计(拆到几个钱包躲不过)。污点与成本按花掉的价值比例随资金进持仓,赢的钱继承押注资金的污点比例,卖回时按比例退。
|
- Web3 页"预测"子页(游戏第 8 天起,Web3 治理社区已买下):每个盘口是一道是非题,开盘当天到窗口开始前可以买卖,窗口最后一天夜里结算;每天开门后补盘,同时开放 3–6 个,每天最多新开 2 个。资金走链上钱包的 CRC:买入、全部卖出都是合约调用,要在钱包上签名(和质押一样;买入的手续费在核对页选档、用 CRC 付,卖出用价值最高的币付);持仓记在签名的钱包名下,结算时兑付回这个钱包,同一盘口各钱包只能押同一边,持仓上限和内幕判定按盘口合计(拆到几个钱包躲不过)。污点与成本按花掉的价值比例随资金进持仓,赢的钱继承押注资金的污点比例,卖回时按比例退。
|
||||||
- 盘口类型:新闻事件("出现某常规事件",先验 = 游戏掷骰规则:5 天后每天 50 / 35 / 25% 有事件,再按权重抽)、派系行动("某派系有行动开始",每天开始概率 6%,估计值)、水纯度(明天上层 / 下层水纯度 ≥ 阈值,先验精确)、PSC 价格(窗口最后一天夜间结算前的价格 ≥ 阈值,先验用价格过程的正态近似)。事件和派系行动靠夜间对比"昨晚生效的事件"得到当天新出现的;窗口里缺任何一天的记录(没睡觉结算)盘口作废、退回本金。
|
- 盘口类型:新闻事件("出现某常规事件",先验 = 游戏掷骰规则:5 天后每天 50 / 35 / 25% 有事件,再按权重抽)、派系行动("某派系有行动开始",每天开始概率 6%,估计值)、水纯度(明天上层 / 下层水纯度 ≥ 阈值,先验精确)、PSC 价格(窗口最后一天夜间结算前的价格 ≥ 阈值,先验用价格过程的正态近似)。事件和派系行动靠夜间对比"昨晚生效的事件"得到当天新出现的;窗口里缺任何一天的记录(没睡觉结算)盘口作废、退回本金。
|
||||||
|
|||||||
@@ -23,6 +23,31 @@ namespace Decentralized.Domain
|
|||||||
public double OpenPrice = Tuning.PscStartPrice;
|
public double OpenPrice = Tuning.PscStartPrice;
|
||||||
/// <summary>玩家自己的现货大单把价格推高(正)或压低(负)的对数幅度,每晚随价格回归一起衰减。操纵检出和预测盘用它估"没有玩家时的价格"。</summary>
|
/// <summary>玩家自己的现货大单把价格推高(正)或压低(负)的对数幅度,每晚随价格回归一起衰减。操纵检出和预测盘用它估"没有玩家时的价格"。</summary>
|
||||||
public double PlayerPush;
|
public double PlayerPush;
|
||||||
|
/// <summary>今天的插针(对数幅度,0 = 没有)和当晚回去的比例(0 = 真跌真涨)。</summary>
|
||||||
|
public double Wick, WickBack;
|
||||||
|
|
||||||
|
/// <summary>夜间结算开始时:插针按比例回去(结算、预测盘读的是回去后的价格)。</summary>
|
||||||
|
public void UndoWick(int day)
|
||||||
|
{
|
||||||
|
if (Wick == 0) return;
|
||||||
|
Main.SetPrice(Price * Math.Exp(-Wick * WickBack), Tuning.PoolDepth(day));
|
||||||
|
Wick = 0; WickBack = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 插针:开门后价格瞬间被打到一边(大户扫强平、砸盘吸筹),大部分当晚回去,一部分是真的。
|
||||||
|
/// 标记价用开门前的价格和收盘价平均,强平只吃一半。返回幅度(0 = 今天没有)。
|
||||||
|
/// </summary>
|
||||||
|
public double TryWick(Rng rng, int day)
|
||||||
|
{
|
||||||
|
Wick = 0; WickBack = 0;
|
||||||
|
if (!rng.Chance(Tuning.WickChance)) return 0;
|
||||||
|
double size = rng.Range(Tuning.WickMin, Tuning.WickMax) * (rng.Chance(0.5) ? 1 : -1);
|
||||||
|
Wick = size;
|
||||||
|
WickBack = rng.Chance(Tuning.WickReal) ? 0 : rng.Range(Tuning.WickRevertMin, Tuning.WickRevertMax);
|
||||||
|
Main.SetPrice(Price * Math.Exp(size), Tuning.PoolDepth(day));
|
||||||
|
return size;
|
||||||
|
}
|
||||||
public double NeutralPrice => Price * Math.Exp(-PlayerPush);
|
public double NeutralPrice => Price * Math.Exp(-PlayerPush);
|
||||||
/// <summary>被查概率:推价幅度(绝对值)超过 ManipFree 后随幅度升高。</summary>
|
/// <summary>被查概率:推价幅度(绝对值)超过 ManipFree 后随幅度升高。</summary>
|
||||||
public static double ManipChance(double push)
|
public static double ManipChance(double push)
|
||||||
@@ -113,6 +138,7 @@ namespace Decentralized.Domain
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Night(ICollection<MarketEvent> active, Rng rng, int day, Func<string, double> stablePrice)
|
public void Night(ICollection<MarketEvent> active, Rng rng, int day, Func<string, double> stablePrice)
|
||||||
{
|
{
|
||||||
|
if (Wick != 0) { Main.SetPrice(Price * Math.Exp(-Wick * WickBack), Tuning.PoolDepth(day)); Wick = 0; WickBack = 0; }
|
||||||
PlayerPush *= 1 - Tuning.Revert;
|
PlayerPush *= 1 - Tuning.Revert;
|
||||||
Sentiment *= Math.Exp(Tuning.SentimentKappa * -Math.Log(Sentiment) + rng.Gauss() * Tuning.SentimentVol);
|
Sentiment *= Math.Exp(Tuning.SentimentKappa * -Math.Log(Sentiment) + rng.Gauss() * Tuning.SentimentVol);
|
||||||
double anchor = Anchor(active);
|
double anchor = Anchor(active);
|
||||||
|
|||||||
@@ -0,0 +1,224 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Decentralized.Domain
|
||||||
|
{
|
||||||
|
/// <summary>空投:签名领取。正规空投不要授权或只要有限授权,给一点币;钓鱼空投要求对某个币"无上限授权",几晚后把这个钱包里的这种币转走。</summary>
|
||||||
|
public sealed class Airdrop
|
||||||
|
{
|
||||||
|
public int Id, Expire;
|
||||||
|
public string Name, Asset;
|
||||||
|
/// <summary>领取要授权的额度:0 = 不要授权;double.PositiveInfinity = 无上限。</summary>
|
||||||
|
public double Approve;
|
||||||
|
public double Reward;
|
||||||
|
public bool Scam, Claimed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>钱包对某个合约的授权。钓鱼授权到 DrainDay 那晚把这种币转走,撤销后作废。</summary>
|
||||||
|
public sealed class Approval
|
||||||
|
{
|
||||||
|
public int Id, DrainDay = -1;
|
||||||
|
public string Wallet, Asset, Spender;
|
||||||
|
public double Limit;
|
||||||
|
public bool Scam;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>第三方收益池(CRC):日息、储备、有没有时间锁、有没有审计都看得见;是不是骗局看不见,跑路时存款全部没了。</summary>
|
||||||
|
public sealed class YieldPool
|
||||||
|
{
|
||||||
|
public int Id, OpenDay;
|
||||||
|
public string Name;
|
||||||
|
public double Rate, Reserve, Cap;
|
||||||
|
public bool Timelock, Audited, Scam, Closed;
|
||||||
|
public Dictionary<string, double> Deposits = new Dictionary<string, double>();
|
||||||
|
public Dictionary<string, double> Taint = new Dictionary<string, double>(), Basis = new Dictionary<string, double>();
|
||||||
|
/// <summary>时间锁池子的取款队列:钱包 → (到账日, 数额)。</summary>
|
||||||
|
public List<YieldWithdraw> Pending = new List<YieldWithdraw>();
|
||||||
|
public double Total => Deposits.Values.Sum();
|
||||||
|
public double Of(string wallet) => Deposits.TryGetValue(wallet, out var v) ? v : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class YieldWithdraw { public string Wallet; public int Day; public double Amount, Taint, Basis; }
|
||||||
|
|
||||||
|
/// <summary>夜间发生的事。Kind:drain(钓鱼授权转走)/ rug(收益池跑路)/ dry(正规池储备耗尽,退本金)/ paid(取款到账)/ wickback(插针回去了)。</summary>
|
||||||
|
public sealed class ScamEvent
|
||||||
|
{
|
||||||
|
public string Kind, Name, Wallet, Asset;
|
||||||
|
public double Amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>NPC 骗局:空投与授权、第三方收益池。插针在 <see cref="Market"/> 里。</summary>
|
||||||
|
public sealed class Scams
|
||||||
|
{
|
||||||
|
public List<Airdrop> Airdrops = new List<Airdrop>();
|
||||||
|
public List<Approval> Approvals = new List<Approval>();
|
||||||
|
public List<YieldPool> Pools = new List<YieldPool>();
|
||||||
|
public int Seq;
|
||||||
|
/// <summary>骗子用过的收款地址(假客服、钓鱼):转到这些地址时晨间日志说明被骗。</summary>
|
||||||
|
public List<string> ScamAddrs = new List<string>();
|
||||||
|
|
||||||
|
private static readonly string[] AirdropNames = { "Poinbase", "PSC Foundation", "RatDigg", "Revolution DAO", "Gutter Labs", "Station Rewards" };
|
||||||
|
private static readonly string[] PoolNames = { "Nebula Yield", "Rustwater Vault", "Orbit Farm", "Deck 9 Savings", "Gutterflow Pool", "Halo Staking", "Ironclad Earn" };
|
||||||
|
|
||||||
|
public static double ScamChance(double rate, bool timelock, bool audited)
|
||||||
|
{
|
||||||
|
int i = Array.IndexOf(Tuning.YieldRates, rate);
|
||||||
|
double p = i >= 0 ? Tuning.YieldScamByRate[i] : 0.5;
|
||||||
|
if (timelock) p -= Tuning.YieldScamTimelock;
|
||||||
|
if (audited) p -= Tuning.YieldScamAudit;
|
||||||
|
return Math.Max(0.02, Math.Min(0.95, p));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ——— 空投 ———
|
||||||
|
|
||||||
|
/// <summary>新空投。钓鱼的名字常是正规名字的仿冒(一个字符不同),要求对一种币无上限授权,奖励看起来更高。</summary>
|
||||||
|
public Airdrop NewAirdrop(int day, Rng rng, string[] assets)
|
||||||
|
{
|
||||||
|
bool scam = rng.Chance(Tuning.AirdropScam);
|
||||||
|
string name = AirdropNames[rng.Range(0, AirdropNames.Length - 1)];
|
||||||
|
if (scam && rng.Chance(0.6)) name = Typo(name, rng);
|
||||||
|
string asset = assets[rng.Range(0, assets.Length - 1)];
|
||||||
|
double reward = Math.Round(rng.Range(Tuning.AirdropRewardMin, Tuning.AirdropRewardMax));
|
||||||
|
if (scam) reward = Math.Round(reward * rng.Range(1.5, 3.0));
|
||||||
|
// 钓鱼:多数要无上限授权,三成要一个看着像有限、其实远大于奖励的额度
|
||||||
|
double approve = scam ? (rng.Chance(0.3) ? Math.Round(reward * rng.Range(20.0, 100.0) / 10) * 10 : double.PositiveInfinity) : rng.Chance(0.5) ? 0 : Math.Round(rng.Range(10.0, 60.0));
|
||||||
|
var a = new Airdrop { Id = ++Seq, Name = name, Asset = asset, Approve = approve, Reward = reward, Scam = scam, Expire = day + Tuning.AirdropDays };
|
||||||
|
Airdrops.Add(a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string Typo(string s, Rng rng)
|
||||||
|
{
|
||||||
|
var swaps = new Dictionary<char, char> { ['o'] = '0', ['i'] = '1', ['l'] = '1', ['e'] = '3', ['a'] = '4', ['s'] = '5', ['n'] = 'm' };
|
||||||
|
var idx = Enumerable.Range(0, s.Length).Where(i => swaps.ContainsKey(char.ToLowerInvariant(s[i]))).ToList();
|
||||||
|
if (idx.Count == 0) return s + "s";
|
||||||
|
int k = idx[rng.Range(0, idx.Count - 1)];
|
||||||
|
return s.Substring(0, k) + swaps[char.ToLowerInvariant(s[k])] + s.Substring(k + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>领取:正规空投给奖励(干净的 CRC),钓鱼空投给一点点诱饵;有授权的记一条授权,钓鱼授权定下转走的那晚。</summary>
|
||||||
|
public Approval Claim(Airdrop a, Wallet w, int day, Rng rng, out double got)
|
||||||
|
{
|
||||||
|
got = 0;
|
||||||
|
if (a.Claimed || day > a.Expire) return null;
|
||||||
|
a.Claimed = true;
|
||||||
|
got = a.Scam ? Math.Round(a.Reward * 0.05, 2) : a.Reward;
|
||||||
|
w.Add(Assets.CRC, got); w.Basis += got;
|
||||||
|
if (a.Approve <= 0) return null;
|
||||||
|
var ap = new Approval { Id = ++Seq, Wallet = w.Address, Asset = a.Asset, Spender = a.Name, Limit = a.Approve, Scam = a.Scam, DrainDay = a.Scam ? day + rng.Range(Tuning.AirdropDrainMin, Tuning.AirdropDrainMax) : -1 };
|
||||||
|
Approvals.Add(ap);
|
||||||
|
return ap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Revoke(int id) => Approvals.RemoveAll(x => x.Id == id) > 0;
|
||||||
|
|
||||||
|
// ——— 收益池 ———
|
||||||
|
|
||||||
|
public YieldPool NewPool(int day, Rng rng)
|
||||||
|
{
|
||||||
|
double rate = Tuning.YieldRates[rng.Range(0, Tuning.YieldRates.Length - 1)];
|
||||||
|
bool timelock = rng.Chance(0.5), audited = rng.Chance(0.4);
|
||||||
|
bool scam = rng.Chance(ScamChance(rate, timelock, audited));
|
||||||
|
double cap = Tuning.YieldCap0 + Tuning.YieldCapPerDay * day;
|
||||||
|
var used = Pools.Where(p => !p.Closed).Select(p => p.Name).ToList();
|
||||||
|
var names = PoolNames.Where(n => !used.Contains(n)).ToList();
|
||||||
|
var p2 = new YieldPool
|
||||||
|
{
|
||||||
|
Id = ++Seq, OpenDay = day, Name = names.Count > 0 ? names[rng.Range(0, names.Count - 1)] : "Pool " + Seq,
|
||||||
|
Rate = rate, Timelock = timelock, Audited = audited, Scam = scam, Cap = cap,
|
||||||
|
// 正规池的储备够付若干天满额利息;骗局池报一个好看的数字(不会真付到那么多天,跑路前一直照付)
|
||||||
|
Reserve = Math.Round(rate * cap * Tuning.YieldReserveDays * (scam ? rng.Range(0.8, 1.6) : rng.Range(0.6, 1.2))),
|
||||||
|
};
|
||||||
|
Pools.Add(p2);
|
||||||
|
return p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Deposit(YieldPool p, Wallet w, double amount, Func<string, double> pr)
|
||||||
|
{
|
||||||
|
if (p.Closed || amount <= 0 || w.Avail(Assets.CRC) + 1e-9 < amount || p.Total + amount > p.Cap + 1e-9) return false;
|
||||||
|
double total = w.Value(pr), share = total > 0 ? Math.Min(1, amount * pr(Assets.CRC) / total) : 0;
|
||||||
|
double taint = w.Taint * share, basis = w.Basis * share;
|
||||||
|
w.Add(Assets.CRC, -amount); w.Taint -= taint; w.Basis -= basis;
|
||||||
|
p.Deposits[w.Address] = p.Of(w.Address) + amount;
|
||||||
|
p.Taint[w.Address] = (p.Taint.TryGetValue(w.Address, out var t) ? t : 0) + taint;
|
||||||
|
p.Basis[w.Address] = (p.Basis.TryGetValue(w.Address, out var b) ? b : 0) + basis;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>取出:没有时间锁的马上到账;有时间锁的进队列,几天后到账(跑路了就没了)。返回马上到账的数额。</summary>
|
||||||
|
public double Withdraw(YieldPool p, Wallet w, int day)
|
||||||
|
{
|
||||||
|
double amt = p.Of(w.Address);
|
||||||
|
if (amt <= 0 || p.Closed) return 0;
|
||||||
|
double taint = p.Taint.TryGetValue(w.Address, out var t) ? t : 0, basis = p.Basis.TryGetValue(w.Address, out var b) ? b : 0;
|
||||||
|
p.Deposits.Remove(w.Address); p.Taint.Remove(w.Address); p.Basis.Remove(w.Address);
|
||||||
|
if (p.Timelock) { p.Pending.Add(new YieldWithdraw { Wallet = w.Address, Day = day + Tuning.YieldLockDays, Amount = amt, Taint = taint, Basis = basis }); return 0; }
|
||||||
|
Pay(w, amt, taint, basis);
|
||||||
|
return amt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Pay(Wallet w, double amt, double taint, double basis)
|
||||||
|
{
|
||||||
|
w.Add(Assets.CRC, amt); w.Taint += taint; w.Basis += basis;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ——— 夜间 ———
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 夜间:钓鱼授权到期转走;收益池计息、储备耗尽的正规池退本金关闭、骗局池按概率跑路;时间锁取款到账;过期空投清掉;随机新空投和新收益池。
|
||||||
|
/// </summary>
|
||||||
|
public List<ScamEvent> Night(int day, Rng rng, Func<string, Wallet> own, string[] airdropAssets, Func<string, double> pr = null)
|
||||||
|
{
|
||||||
|
var evs = new List<ScamEvent>();
|
||||||
|
foreach (var ap in Approvals.Where(x => x.Scam && x.DrainDay >= 0 && x.DrainDay <= day).ToList())
|
||||||
|
{
|
||||||
|
Approvals.Remove(ap);
|
||||||
|
var w = own(ap.Wallet);
|
||||||
|
if (w == null) continue;
|
||||||
|
double amt = Math.Min(ap.Limit, w.Avail(ap.Asset));
|
||||||
|
if (amt <= 1e-9) continue;
|
||||||
|
if (pr != null) w.Spend(ap.Asset, amt, pr); else w.Add(ap.Asset, -amt);
|
||||||
|
evs.Add(new ScamEvent { Kind = "drain", Name = ap.Spender, Wallet = ap.Wallet, Asset = ap.Asset, Amount = amt });
|
||||||
|
}
|
||||||
|
foreach (var p in Pools.Where(x => !x.Closed).ToList())
|
||||||
|
{
|
||||||
|
if (p.Scam && p.Total > 0 && day > p.OpenDay && rng.Chance(Tuning.YieldRugNightly))
|
||||||
|
{
|
||||||
|
foreach (var kv in p.Deposits) evs.Add(new ScamEvent { Kind = "rug", Name = p.Name, Wallet = kv.Key, Asset = Assets.CRC, Amount = kv.Value });
|
||||||
|
foreach (var q in p.Pending) evs.Add(new ScamEvent { Kind = "rug", Name = p.Name, Wallet = q.Wallet, Asset = Assets.CRC, Amount = q.Amount });
|
||||||
|
p.Deposits.Clear(); p.Pending.Clear(); p.Closed = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
double interest = p.Total * p.Rate;
|
||||||
|
if (!p.Scam && interest > p.Reserve)
|
||||||
|
{
|
||||||
|
foreach (var kv in p.Deposits.ToList())
|
||||||
|
{
|
||||||
|
var w = own(kv.Key);
|
||||||
|
if (w != null) Pay(w, kv.Value, p.Taint.TryGetValue(kv.Key, out var t) ? t : 0, p.Basis.TryGetValue(kv.Key, out var b) ? b : 0);
|
||||||
|
evs.Add(new ScamEvent { Kind = "dry", Name = p.Name, Wallet = kv.Key, Asset = Assets.CRC, Amount = kv.Value });
|
||||||
|
}
|
||||||
|
p.Deposits.Clear(); p.Closed = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p.Reserve -= interest;
|
||||||
|
foreach (var k in p.Deposits.Keys.ToList()) p.Deposits[k] *= 1 + p.Rate;
|
||||||
|
}
|
||||||
|
foreach (var q in p.Pending.Where(x => x.Day <= day).ToList())
|
||||||
|
{
|
||||||
|
p.Pending.Remove(q);
|
||||||
|
var w = own(q.Wallet);
|
||||||
|
if (w != null) Pay(w, q.Amount, q.Taint, q.Basis);
|
||||||
|
evs.Add(new ScamEvent { Kind = "paid", Name = p.Name, Wallet = q.Wallet, Asset = Assets.CRC, Amount = q.Amount });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Pools.RemoveAll(p => p.Closed && p.Pending.Count == 0 && day - p.OpenDay > 20);
|
||||||
|
Airdrops.RemoveAll(a => a.Expire < day + 1);
|
||||||
|
if (rng.Chance(Tuning.AirdropChance)) NewAirdrop(day + 1, rng, airdropAssets);
|
||||||
|
if (Pools.Count(p => !p.Closed) < Tuning.YieldPoolMax && rng.Chance(Tuning.YieldPoolChance)) NewPool(day + 1, rng);
|
||||||
|
return evs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -218,6 +218,21 @@ namespace Decentralized.Domain
|
|||||||
public const double PonziReport0 = 0.02, PonziReportRate = 0.5, PonziReportSize = 0.04;
|
public const double PonziReport0 = 0.02, PonziReportRate = 0.5, PonziReportSize = 0.04;
|
||||||
public const double PonziCrime = 1200;
|
public const double PonziCrime = 1200;
|
||||||
|
|
||||||
|
/// <summary>插针:每天开门时出现的概率、幅度范围(对数价格的绝对值)、当晚回去的比例范围、不回去(真跌真涨)的概率。</summary>
|
||||||
|
public const double WickChance = 0.07, WickMin = 0.15, WickMax = 0.30, WickRevertMin = 0.6, WickRevertMax = 1.0, WickReal = 0.3;
|
||||||
|
/// <summary>空投:每晚出现新空投的概率、有效天数、骗局占比、正规空投奖励范围(信用点等值)、钓鱼授权后被转走的延迟(晚)。</summary>
|
||||||
|
public const double AirdropChance = 0.35, AirdropScam = 0.4, AirdropRewardMin = 20, AirdropRewardMax = 120;
|
||||||
|
public const int AirdropDays = 2, AirdropDrainMin = 1, AirdropDrainMax = 2;
|
||||||
|
/// <summary>第三方收益池:同时最多几个、每晚新开的概率;日息档位;按日息的骗局概率,时间锁、审计各减多少;骗局池每晚跑路概率;
|
||||||
|
/// 单池存款上限(随天数);正规池的储备(日息 × 存款上限 × 天数);时间锁取款等待天数。</summary>
|
||||||
|
public const int YieldPoolMax = 3, YieldLockDays = 2;
|
||||||
|
public const double YieldPoolChance = 0.25, YieldRugNightly = 0.18, YieldCap0 = 2000, YieldCapPerDay = 60, YieldReserveDays = 25;
|
||||||
|
public static readonly double[] YieldRates = { 0.01, 0.02, 0.03 }, YieldScamByRate = { 0.15, 0.40, 0.75 };
|
||||||
|
public const double YieldScamTimelock = 0.25, YieldScamAudit = 0.20;
|
||||||
|
/// <summary>假客服:每天上门的概率;伪造转账:用币付款的顾客里是骗子的比例;两者都从第几天起。</summary>
|
||||||
|
public const double FakeSupportChance = 0.04, FakeTransferShare = 0.08;
|
||||||
|
public const int ScamMinDay = 10;
|
||||||
|
|
||||||
/// <summary>主交易对(信用点一侧)的深度随天数增长。</summary>
|
/// <summary>主交易对(信用点一侧)的深度随天数增长。</summary>
|
||||||
public static double PoolDepth(int day) => PoolDepth0 * (1 + day / 60.0);
|
public static double PoolDepth(int day) => PoolDepth0 * (1 + day / 60.0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace Decentralized
|
|||||||
public static class CoinCustomers
|
public static class CoinCustomers
|
||||||
{
|
{
|
||||||
private static readonly HashSet<StoreClient> Marked = new HashSet<StoreClient>();
|
private static readonly HashSet<StoreClient> Marked = new HashSet<StoreClient>();
|
||||||
private static int markDay = -1;
|
private static int markDay = -1, supportDay = -1;
|
||||||
|
|
||||||
public static void Subscribe()
|
public static void Subscribe()
|
||||||
{
|
{
|
||||||
@@ -152,7 +152,7 @@ namespace Decentralized
|
|||||||
c.mainDialogue.SetText(c.displayName, "CRT.").SetEndAction(() => { });
|
c.mainDialogue.SetText(c.displayName, "CRT.").SetEndAction(() => { });
|
||||||
c.AddBasicDialog();
|
c.AddBasicDialog();
|
||||||
c.CompleteClientCreation();
|
c.CompleteClientCreation();
|
||||||
Mark(c, Assets.CRT);
|
Mark(c, Assets.CRT, false);
|
||||||
Log.Info($"用币付款顾客(测试)已设置,钱包污点 {Session.Data.Hot.Taint:0.##},当前顾客 {PlayerStore.Instance.currentClientInstance?.GetClientBlueprint()?.identifier},队列 {PlayerStore.Instance.storeClientManager.clientStack.Count} 人");
|
Log.Info($"用币付款顾客(测试)已设置,钱包污点 {Session.Data.Hot.Taint:0.##},当前顾客 {PlayerStore.Instance.currentClientInstance?.GetClientBlueprint()?.identifier},队列 {PlayerStore.Instance.storeClientManager.clientStack.Count} 人");
|
||||||
PlayerStore.Instance.currentClientInstance = null; // 测试:丢掉在场的顾客(开局的高利贷者不可遣散)
|
PlayerStore.Instance.currentClientInstance = null; // 测试:丢掉在场的顾客(开局的高利贷者不可遣散)
|
||||||
PlayerStore.Instance.storeClientManager.clientStack.Insert(0, c);
|
PlayerStore.Instance.storeClientManager.clientStack.Insert(0, c);
|
||||||
@@ -171,29 +171,80 @@ namespace Decentralized
|
|||||||
{
|
{
|
||||||
int day = StoreStation.GetDayCounter();
|
int day = StoreStation.GetDayCounter();
|
||||||
if (day != markDay) { Marked.Clear(); markDay = day; }
|
if (day != markDay) { Marked.Clear(); markDay = day; }
|
||||||
|
// 假客服:一天最多一次
|
||||||
|
if (day >= Tuning.ScamMinDay && supportDay != day)
|
||||||
|
{
|
||||||
|
supportDay = day;
|
||||||
|
if (Session.Data.Rng.Chance(Tuning.FakeSupportChance)) manager.AddClient(FakeSupport());
|
||||||
|
}
|
||||||
foreach (var c in manager.clientStack)
|
foreach (var c in manager.clientStack)
|
||||||
{
|
{
|
||||||
if (c == null || c.isSecurity || Marked.Contains(c) || c.clientIntent != StoreClient.ClientIntent.BUY || c.isNoContributeToEvidence) continue;
|
if (c == null || c.isSecurity || Marked.Contains(c) || c.clientIntent != StoreClient.ClientIntent.BUY || c.isNoContributeToEvidence) continue;
|
||||||
Marked.Add(c);
|
Marked.Add(c);
|
||||||
string asset = CoinPayment.AssetFor(c.clientFaction);
|
string asset = CoinPayment.AssetFor(c.clientFaction);
|
||||||
if (asset == null || !Session.Data.Rng.Chance(CoinPayment.Chance(asset))) continue;
|
if (asset == null || !Session.Data.Rng.Chance(CoinPayment.Chance(asset))) continue;
|
||||||
Mark(c, asset);
|
Mark(c, asset, day >= Tuning.ScamMinDay && Session.Data.Rng.Chance(Tuning.FakeTransferShare));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Mark(StoreClient c, string asset)
|
/// <summary>
|
||||||
|
/// 标成用币付款的顾客。开口先说用什么币付:正常的说"链上确认要一会儿";骗子(伪造转账)说"已经转了,给你看截图,快给货"——
|
||||||
|
/// 成交后信用点照样被扣回,币却不会到账。玩家能做的就是听清这句话,不卖给他。
|
||||||
|
/// </summary>
|
||||||
|
private static void Mark(StoreClient c, string asset, bool fake)
|
||||||
{
|
{
|
||||||
var before = c.onItemBought;
|
var before = c.onItemBought;
|
||||||
double total = 0; // 这位顾客这一单一共付了多少币
|
double total = 0; // 这位顾客这一单一共付了多少币
|
||||||
c.isNoContributeToEvidence = true;
|
c.isNoContributeToEvidence = true;
|
||||||
|
var intro = new Dialogue().SetText(c.displayName, L.T(fake ? "coinpay.intro.fake" : "coinpay.intro", asset));
|
||||||
|
intro.SetNextDialogue(c.mainDialogue);
|
||||||
|
c.mainDialogue = intro;
|
||||||
c.onItemBought = (item, cost) =>
|
c.onItemBought = (item, cost) =>
|
||||||
{
|
{
|
||||||
before?.Invoke(item, cost);
|
before?.Invoke(item, cost);
|
||||||
Log.Guard("用币付款成交", () => { total += Pay(c, asset, item, cost); Say(c, asset, total); });
|
Log.Guard("用币付款成交", () =>
|
||||||
|
{
|
||||||
|
if (fake) { FakePay(c, asset, item, cost); total += cost / Session.Price(asset); }
|
||||||
|
else total += Pay(c, asset, item, cost);
|
||||||
|
Say(c, asset, total);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>伪造转账:信用点扣回(顾客没真付),币不会到账,晨间日志说明。</summary>
|
||||||
|
private static void FakePay(StoreClient client, string asset, GameItem item, int cost)
|
||||||
|
{
|
||||||
|
if (cost <= 0) return;
|
||||||
|
ModHelper.AddCredit(-cost, false);
|
||||||
|
Session.Data.FakePaidToday.Add(L.T("coinpay.fake.entry", client.displayName, item.name, cost));
|
||||||
|
Log.Info($"伪造转账:{client.displayName} 拿走 {item.name}({cost} 信用点),{asset} 不会到账");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>假客服:自称 Poinbase 客服,说账户被风控,要把 CRC 转到"安全地址"。Poinbase 从不上门,也从不要求转账;转过去的币就没了。</summary>
|
||||||
|
public static StoreClient FakeSupportForTest() => FakeSupport();
|
||||||
|
|
||||||
|
private static StoreClient FakeSupport()
|
||||||
|
{
|
||||||
|
var d = Session.Data;
|
||||||
|
string addr = ChainAddress.Make(d.Rng.NextUInt());
|
||||||
|
d.Scams.ScamAddrs.Add(addr);
|
||||||
|
int amount = 100 * d.Rng.Range(3, 15);
|
||||||
|
var c = new StoreClient
|
||||||
|
{
|
||||||
|
identifier = "pd_fake_support", displayName = L.T("scam.support.name"), spriteName = SpriteDict.GetRandomUpperSpriteName(),
|
||||||
|
clientIntent = StoreClient.ClientIntent.DIALOGUE,
|
||||||
|
};
|
||||||
|
c.mainDialogue.SetText(c.displayName, L.T("scam.support.1")).NextDialogue()
|
||||||
|
.SetText(c.displayName, L.T("scam.support.2", amount, addr)).NextDialogue()
|
||||||
|
.SetText(c.displayName, L.T("scam.support.3"));
|
||||||
|
ModHelper.SetClientSource(c, ModInfo.Id);
|
||||||
|
c.AddBasicDialog();
|
||||||
|
c.CompleteClientCreation();
|
||||||
|
Log.Info($"假客服上门:要 {amount} CRC 转到 {addr}");
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>成交后顾客说的话:告诉玩家这单是币到账,不是信用点。</summary>
|
/// <summary>成交后顾客说的话:告诉玩家这单是币到账,不是信用点。</summary>
|
||||||
private static void Say(StoreClient client, string asset, double total)
|
private static void Say(StoreClient client, string asset, double total)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -97,6 +97,23 @@ namespace Decentralized
|
|||||||
StoreStation.Instance.storeEventManager.QueueFuturEvent(EventListNormal.CreatePowerShortage(), 3, true);
|
StoreStation.Instance.storeEventManager.QueueFuturEvent(EventListNormal.CreatePowerShortage(), 3, true);
|
||||||
Log.Info("测试:停电 3 天后(已知)");
|
Log.Info("测试:停电 3 天后(已知)");
|
||||||
}));
|
}));
|
||||||
|
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Scams: airdrops + pools + wick (test)", () => Log.Guard("骗局测试", () =>
|
||||||
|
{
|
||||||
|
var d = Session.Data; int day = StoreStation.GetDayCounter();
|
||||||
|
var assets = new[] { Assets.CRT, Assets.PSC, Assets.CRC, Assets.CRA };
|
||||||
|
for (int i = 0; i < 4; i++) d.Scams.NewAirdrop(day, d.Rng, assets);
|
||||||
|
while (d.Scams.Pools.Count(p => !p.Closed) < Tuning.YieldPoolMax) d.Scams.NewPool(day, d.Rng);
|
||||||
|
d.Market.Wick = 0; double w = 0; for (int i = 0; i < 200 && w == 0; i++) w = d.Market.TryWick(d.Rng, day);
|
||||||
|
Log.Info($"测试:空投 {string.Join(",", d.Scams.Airdrops.Select(a => a.Name + (a.Scam ? "*" : "")))};池子 {string.Join(",", d.Scams.Pools.Select(p => p.Name + (p.Scam ? "*" : "")))};插针 {w:0.000} 回去 {d.Market.WickBack:0.00}");
|
||||||
|
}));
|
||||||
|
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Scams: fake support now (test)", () => Log.Guard("假客服测试", () =>
|
||||||
|
{
|
||||||
|
var m = PlayerStore.Instance.storeClientManager;
|
||||||
|
var c = CoinCustomers.FakeSupportForTest();
|
||||||
|
PlayerStore.Instance.currentClientInstance = null;
|
||||||
|
m.clientStack.Insert(0, c);
|
||||||
|
PlayerStore.Instance.TryCallNextClient();
|
||||||
|
}));
|
||||||
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Predict: window = tomorrow (test)", () => { foreach (var m in Session.Data.Predict.Markets) { m.FromDay = m.ToDay = StoreStation.GetDayCounter() + 1; } Log.Info("测试:所有盘口窗口改成明天"); });
|
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Predict: window = tomorrow (test)", () => { foreach (var m in Session.Data.Predict.Markets) { m.FromDay = m.ToDay = StoreStation.GetDayCounter() + 1; } Log.Info("测试:所有盘口窗口改成明天"); });
|
||||||
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Perp fund 0 (test)", () => { Session.Data.Perps.InsuranceFund = 0; Log.Info("测试:保险基金清零"); });
|
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "Perp fund 0 (test)", () => { Session.Data.Perps.InsuranceFund = 0; Log.Info("测试:保险基金清零"); });
|
||||||
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "SPARK x0.3 (test)", () => { var st = Session.Data.Stable; st.Spark *= 0.3; Log.Info($"测试:SPARK 价格 {st.Spark:0.00}"); });
|
ModHelper.AddDebugFunction(ModInfo.Id, ModInfo.Name, "SPARK x0.3 (test)", () => { var st = Session.Data.Stable; st.Spark *= 0.3; Log.Info($"测试:SPARK 价格 {st.Spark:0.00}"); });
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ black.kind.Contraband.3,Contraband (high)
|
|||||||
black.kind.Tech,High-tech (markup)
|
black.kind.Tech,High-tech (markup)
|
||||||
nightlog.bm.ready,"Black market: {0} arrived; a courier will come by once you open."
|
nightlog.bm.ready,"Black market: {0} arrived; a courier will come by once you open."
|
||||||
item.web3guide.name,Web3 Handbook
|
item.web3guide.name,Web3 Handbook
|
||||||
item.web3guide.desc,"Bank: depositing turns credits into CRC in your Poinbase account; withdrawing turns CRC back into credits and goes through compliance screening, which looks at the Poinbase account's taint. Trading: buys are paid in the quote coin, sells in the traded coin. Mixer: pick a coin, amount and rounds; each round takes a fee and lowers taint, rounds equal days of waiting, and the coins come back to the same address; the more you deposit, the worse the cleaning. Hardware wallets: on-chain coins sit in PLEDGER hardware wallets, each with its own balances and taint; open and connect them on the terminal's Wallets page. The Web3 page's trading, black market and mixer use the connected wallet, and coin-paying customers and mining rewards go into it too. Payments (black market, mixer, Ponero desk, listing fees) start as an invoice on the terminal; type the payee address on the wallet and hold ✓ to sign. The last two characters of an address are a checksum, so a one-character typo is usually caught; once in a while it happens to be valid and the coins go to an address nobody uses. DEX swaps also need a signature on the wallet. RatDigg miners (M1 / M2 / M3) are standalone machines with far more hash than a card and a lower power draw per hash; they need a battery, take modules and use no rig slots. Only the black market's miner dealers sell them, gated by black-market standing (M1 40, M2 60, M3 80), sometimes second-hand. When one burns out, repair it by putting electronic components in its repair slot in order; it comes back 20 health lower. Somewhere between day 50 and day 90 a "miner era" arrives, announced in the paper a few days earlier: the big farms halve their power costs, network hash climbs, GPU miners are diluted and low-end cards barely earn, while miners still do fine. Perps: the Perps tab on Poinbase uses your account CRC as margin, up to 5× on PSC and 3× on SPARK, one position per product, never long and short at once. Fills are worse than the quote (more so for bigger orders, like the spot pool) and opening and closing both cost a fee. Liquidation is checked only overnight against the day's average price: equity under 10% of notional wipes the margin. There is also a nightly funding payment; when the price is above its 7-day average, longs pay shorts. If a liquidation loses more than the margin, the insurance fund covers the gap; when it runs dry (a SPARK collapse can do that) winning positions are auto-deleveraged and give up half their profit; anything beyond that becomes your debt. Debt grows 2% a day, is repaid first from CRC in the account every night, blocks new positions and cash-outs, and after seven days items in your shop are seized to cover it; whatever is still short is written off and the perp account is banned for 30 days. Poinbase is a custodial account and can withdraw straight to the connected wallet; depositing from a wallet means sending to Poinbase's deposit address, which takes only CRC and PSC. More hardware wallets are sold by Dr. Jackson; drag one onto the trading terminal to add it, up to 5. The black market has cheaper ones. A wallet you no longer want can be destroyed on the Wallets page once its coins are moved out. Transfers pay a fee: slow, normal or fast, and gas prices rise and fall over roughly a week; when the network is congested fees rise and slow transactions may be dropped from the mempool. Check the full address before sending. Staking: CRA staked in the Revolution pool earns a daily rate that compounds into the stake; withdrawing means requesting first and waiting four days, with no interest while waiting and no way to take it early. The pool pays from a subsidy fund; when it runs low the rate is cut and word of big holders pulling out may spread. Treat that as a warning: once it collapses CRA is worthless within three days and four days of unlocking is too slow. The balance token SPARK can be minted and burned against CRA at the going price (with a fee); its price swings hard and crashes with the collapse. Staking, minting and burning are contract calls and need a signature on the wallet. Black market: coin only, no CRC, 30% above normal channels, with extra markup on high-tech goods and GPUs; the coin you pay leaves its share of taint with the seller and the goods carry no stolen tag; GPUs may be fake, inspect them yourself. Orders are cheaper than spot but take days and may be intercepted; merchants sell by type at their own price factor, 5+ items get 5% off and 10+ get 10% off, and a bulk merchant appears at random with the lowest prices but six days of waiting; escrow costs 5%, is released on delivery and refunded if the seller runs; advance release takes another 10% off, but a scammer keeps the money and only sellers with 30+ trades accept; the platform itself can rug, be taken over by enforcement, or a seller can be arrested, after which your orders get traced and crime logged; forum rumors can be warnings. An intercepted parcel sometLine truncated
|
item.web3guide.desc,"Bank: depositing turns credits into CRC in your Poinbase account; withdrawing turns CRC back into credits and goes through compliance screening, which looks at the Poinbase account's taint. Trading: buys are paid in the quote coin, sells in the traded coin. Mixer: pick a coin, amount and rounds; each round takes a fee and lowers taint, rounds equal days of waiting, and the coins come back to the same address; the more you deposit, the worse the cleaning. Hardware wallets: on-chain coins sit in PLEDGER hardware wallets, each with its own balances and taint; open and connect them on the terminal's Wallets page. The Web3 page's trading, black market and mixer use the connected wallet, and coin-paying customers and mining rewards go into it too. Payments (black market, mixer, Ponero desk, listing fees) start as an invoice on the terminal; type the payee address on the wallet and hold ✓ to sign. The last two characters of an address are a checksum, so a one-character typo is usually caught; once in a while it happens to be valid and the coins go to an address nobody uses. DEX swaps also need a signature on the wallet. RatDigg miners (M1 / M2 / M3) are standalone machines with far more hash than a card and a lower power draw per hash; they need a battery, take modules and use no rig slots. Only the black market's miner dealers sell them, gated by black-market standing (M1 40, M2 60, M3 80), sometimes second-hand. When one burns out, repair it by putting electronic components in its repair slot in order; it comes back 20 health lower. Somewhere between day 50 and day 90 a "miner era" arrives, announced in the paper a few days earlier: the big farms halve their power costs, network hash climbs, GPU miners are diluted and low-end cards barely earn, while miners still do fine. Perps: the Perps tab on Poinbase uses your account CRC as margin, up to 5× on PSC and 3× on SPARK, one position per product, never long and short at once. Fills are worse than the quote (more so for bigger orders, like the spot pool) and opening and closing both cost a fee. Liquidation is checked only overnight against the day's average price: equity under 10% of notional wipes the margin. There is also a nightly funding payment; when the price is above its 7-day average, longs pay shorts. If a liquidation loses more than the margin, the insurance fund covers the gap; when it runs dry (a SPARK collapse can do that) winning positions are auto-deleveraged and give up half their profit; anything beyond that becomes your debt. Debt grows 2% a day, is repaid first from CRC in the account every night, blocks new positions and cash-outs, and after seven days items in your shop are seized to cover it; whatever is still short is written off and the perp account is banned for 30 days. Poinbase is a custodial account and can withdraw straight to the connected wallet; depositing from a wallet means sending to Poinbase's deposit address, which takes only CRC and PSC. More hardware wallets are sold by Dr. Jackson; drag one onto the trading terminal to add it, up to 5. The black market has cheaper ones. A wallet you no longer want can be destroyed on the Wallets page once its coins are moved out. Transfers pay a fee: slow, normal or fast, and gas prices rise and fall over roughly a week; when the network is congested fees rise and slow transactions may be dropped from the mempool. Check the full address before sending. Staking: CRA staked in the Revolution pool earns a daily rate that compounds into the stake; withdrawing means requesting first and waiting four days, with no interest while waiting and no way to take it early. The pool pays from a subsidy fund; when it runs low the rate is cut and word of big holders pulling out may spread. Treat that as a warning: once it collapses CRA is worthless within three days and four days of unlocking is too slow. The balance token SPARK can be minted and burned against CRA at the going price (with a fee); its price swings hard and crashes with the collapse. Staking, minting and burning are contract calls and need a signature on the wallet. Black market: coin only, no CRC, 30% above normal channels, with extra markup on high-tech goods and GPUs; the coin you pay leaves its share of taint with the seller and the goods carry no stolen tag; GPUs may be fake, inspect them yourself. Orders are cheaper than spot but take days and may be intercepted; merchants sell by type at their own price factor, 5+ items get 5% off and 10+ get 10% off, and a bulk merchant appears at random with the lowest prices but six days of waiting; escrow costs 5%, is released on delivery and refunded if the seller runs; advance release takes another 10% off, but a scammer keeps the money and only sellers with 30+ trades accept; the platform itself can rug, be taken over by enforcement, or a seller can be arrested, after which your orders get traced and crime logged; forum rumors can be warnings. An intercepted parcel sometLine truncated
|
||||||
courier.odd1,...Package is here.
|
courier.odd1,...Package is here.
|
||||||
courier.odd2,"(His hand stays in his pocket.) Sign here."
|
courier.odd2,"(His hand stays in his pocket.) Sign here."
|
||||||
courier.sign,Sign
|
courier.sign,Sign
|
||||||
@@ -662,3 +662,55 @@ ponzi.start.sum,"Open high-yield scheme, daily rate {0}%, marketing {1} CRC"
|
|||||||
ponzi.rug.sum,Rug the pool {0}
|
ponzi.rug.sum,Rug the pool {0}
|
||||||
ponzi.err.wallet,Sign with the issuer wallet.
|
ponzi.err.wallet,Sign with the issuer wallet.
|
||||||
predict.clue.counter,"Intel: scheduled (counter informant, rumor slip)"
|
predict.clue.counter,"Intel: scheduled (counter informant, rumor slip)"
|
||||||
|
web3.sub.airdrop,Airdrops
|
||||||
|
air.h,Airdrops
|
||||||
|
air.none,No airdrops to claim right now.
|
||||||
|
air.row,{0} reward {1} CRC {2} until day {3}
|
||||||
|
air.claim,Claim
|
||||||
|
air.noapprove,no approval needed
|
||||||
|
air.unlimited,approve {0} unlimited
|
||||||
|
air.limited,approve {0} {1}
|
||||||
|
air.approvals,Approvals of {0}
|
||||||
|
air.approvals.none,No approvals.
|
||||||
|
air.approval,{0}: {1}
|
||||||
|
air.revoke,Revoke
|
||||||
|
air.sum,Claim airdrop {0} ({1})
|
||||||
|
air.claimed,Received {0} CRC.
|
||||||
|
air.revoke.sum,Revoke {0}'s {1} approval
|
||||||
|
air.revoked,Approval revoked.
|
||||||
|
air.err.wallet,Sign with the approving wallet.
|
||||||
|
pool.h,Third-party yield pools (CRC)
|
||||||
|
pool.none,None right now.
|
||||||
|
pool.col.name,Pool
|
||||||
|
pool.col.rate,Daily
|
||||||
|
pool.col.reserve,Reserve
|
||||||
|
pool.col.lock,Timelock
|
||||||
|
pool.col.audit,Audit
|
||||||
|
pool.col.mine,Mine
|
||||||
|
pool.yes,yes
|
||||||
|
pool.no,no
|
||||||
|
pool.pending,withdrawing
|
||||||
|
pool.closed,(closed)
|
||||||
|
pool.deposit,Deposit
|
||||||
|
pool.withdraw,Withdraw
|
||||||
|
pool.withdraw.lock,Request withdrawal ({0} days)
|
||||||
|
pool.err.cap,Over the pool cap; {0} left.
|
||||||
|
pool.err.none,No deposit.
|
||||||
|
pool.sum.in,Deposit to {0}: {1} CRC
|
||||||
|
pool.sum.out,Withdraw {1} CRC from {0}
|
||||||
|
pool.done.in,Deposited {0} CRC to {1}.
|
||||||
|
pool.done.out,Withdrew {0} CRC.
|
||||||
|
pool.done.lock,"Requested {0} CRC, arrives on day {1}."
|
||||||
|
nightlog.scam.drain,"{1} {2} in {0} was taken by ""{3}"" through an approval."
|
||||||
|
nightlog.scam.rug,"Yield pool ""{0}"" rugged; {1} CRC from {2} is gone."
|
||||||
|
nightlog.scam.dry,"Yield pool ""{0}"" ran out of reserve and closed; {1} CRC returned to {2}."
|
||||||
|
nightlog.scam.paid,"Withdrawal from ""{0}"" arrived: {2} received {1} CRC."
|
||||||
|
nightlog.scam.fakepay,Forged transfer: {0}
|
||||||
|
nightlog.scam.sent,"The {0} {1} sent to the ""support"" safe address went to a scammer."
|
||||||
|
coinpay.intro,I'll pay in {0}; it takes a moment to confirm on chain.
|
||||||
|
coinpay.intro.fake,"Already sent the {0}, here's the screenshot. Hand it over, I'm in a hurry."
|
||||||
|
coinpay.fake.entry,{0} took {1} claiming to have paid {2} credits in coin; no such transaction on chain.
|
||||||
|
scam.support.name,Poinbase Support
|
||||||
|
scam.support.1,"Hello, Poinbase support here. We detected an unusual login on your account and it has been flagged."
|
||||||
|
scam.support.2,Please send {0} CRC to the safe address {1} today for verification; it will be returned right after.
|
||||||
|
scam.support.3,"Otherwise the account will be frozen for good. I have to go, remember to send it."
|
||||||
@@ -267,7 +267,7 @@ black.kind.Contraband.3,违禁品(高)
|
|||||||
black.kind.Tech,高科技物品(加价)
|
black.kind.Tech,高科技物品(加价)
|
||||||
nightlog.bm.ready,"黑市:{0} 到货,开店后会有快递员上门。"
|
nightlog.bm.ready,"黑市:{0} 到货,开店后会有快递员上门。"
|
||||||
item.web3guide.name,Web3 手册
|
item.web3guide.name,Web3 手册
|
||||||
item.web3guide.desc,"银行:存入把信用点换成 Poinbase 账户里的 CRC;提取把 CRC 换回信用点,要过合规审查,审查看 Poinbase 账户的污点。交易:买入按计价币的数量支付,卖出按所交易币的数量卖出。混币器:选币种、填数量和轮数,每轮扣手续费并降低污点,轮数即等待天数,到期提回同一个地址;存入越多,清洗越差。硬件钱包:链上的币放在 PLEDGER 硬件钱包里,每个钱包的余额和污点各算各的;在终端的钱包页打开、连接。Web3 页的交易、黑市、混币器用已连接的钱包,用币付款的顾客和挖矿收益也进它。付款(黑市、混币器、Ponero 兑换处、上架费)先在终端开账单,再在钱包里手输收款地址、按住 ✓ 签名;地址末尾两位是校验位,输错一位多半会被拦下,偶尔碰巧合法,币就转进了没人用的地址。DEX 兑换也要在钱包上签名。Poinbase 是托管账户,可以直接提到已连接的钱包;从钱包充值要转到 Poinbase 的充值地址,只收 CRC 和 PSC。更多硬件钱包向杰克逊博士购买,拖到交易终端上添加,最多 5 个;黑市上也有更便宜的。不要的钱包可以在钱包页销毁,要先把币转走。转账要付手续费,分慢、普通、快三档,gas 价格大约一周一个起落;网络拥堵时手续费变贵,慢档可能被挤出内存池。转账前核对完整地址。质押:把 CRA 质押进革命军质押池每天有日息,利息并入本金;取出要先申请,等四天才到账,等待期间没有利息,也不能提前拿。质押池靠补贴池付息,补贴池见底会降息,有时还会传出大户撤出的消息,那是预兆:一旦崩盘,三天内 CRA 就一文不值,四天的解锁期来不及。平衡代币 SPARK 可以和 CRA 按价格互相铸销(收手续费),价格波动很大,崩盘时会跟着暴跌。质押、铸销都是合约调用,要在钱包上签名。RatDigg 矿机(M1 / M2 / M3)是独立的机器,算力比显卡大得多、耗电更省,要放电池才挖,可以放模块,不占矿架槽位;只在黑市的矿机商那里有,要黑市声望(M1 40、M2 60、M3 80),偶尔有二手的。暴毙后要往修理槽里放电子元件按顺序修好,修好健康少 20。第 50 到 90 天之间会有一次"矿机时代",提前几天上报纸预告,之后大矿场的耗电成本砍半,全网算力涨上去,显卡矿工的收益被摊薄,低档显卡几乎不赚钱,矿机还行。永续合约:Poinbase 的"永续"页,用账户里的 CRC 当保证金,PSC 最高 5 倍、SPARK 最高 3 倍,一个品种只有一个仓位,不能同时多空。成交价比现价差一截(单越大差得越多,和现货池一样),开平仓还收手续费。强平只在夜里按当天均价检查,权益不到名义价值的 10% 就被强平,保证金没了;每晚还有资金费,价格比近 7 天均价高时多头付给空头。强平后亏光保证金还不够的缺口,先由保险基金垫,基金见底(SPARK 崩盘这类大行情会抽干它)后盈利的仓位会被自动减仓、少拿一半盈利,再不够就记成你的欠款:欠款每天涨 2%,账户里的 CRC 每晚先拿去还,没还清不能开仓、不能出金,七天不还就没收店里的物品抵债,抵不够的核销并拉黑永续账户 30 天。黑市:只收币,不收 CRC,价格比正常渠道贵 30%,高科技物品和显卡另有加价;付出去的币带着按比例的污点留在卖家那边,货不带赃物标签;显卡不保证真假,自己鉴定。订单比现货便宜,要等几天,路上可能被截获;商家按类型卖货,价格系数各不相同,一次订 5 件以上 95 折、10 件以上 9 折,大宗商家随机出现,价格最低但要等六天;托管多付 5% 托管费,收货后放款,卖家跑路时退款;提前放款再打九折,卖家若是骗子钱就没了,只有成交 30 单以上的卖家接受;平台自己也可能跑路,也可能被执法接管,或者卖家落网,之后你的订单会被追查、记罪证;论坛上的传闻可以当预兆。被截获的包裹有时会变成执法人员上门:签收当场记罪证并查封,拒签只损失货款。出售:在黑市的卖货页把储藏区里的违禁品、高科技物品和显卡上架,标价是参考价的 0.6 到 1.8 倍。倍率越高成交越慢(0.9 以下约一天,1.0 约两天,1.8 约十四天),货款带污点的可能性和比例也越高,近 7 天出售的量越大,污点越重;同时最多上架 10 件,上架收 5% 上架费,上架后可以改价(收 2% 改价费,标价按参考价重算,成交的快慢跟着新倍率走),成交扣 8% 抽成,货款托管 3 天后进钱包;卖假卡可能被买家看穿而退货,拉低好评;平台跑路时上架的货和未放款的货款都没了Line truncated
|
item.web3guide.desc,"银行:存入把信用点换成 Poinbase 账户里的 CRC;提取把 CRC 换回信用点,要过合规审查,审查看 Poinbase 账户的污点。交易:买入按计价币的数量支付,卖出按所交易币的数量卖出。混币器:选币种、填数量和轮数,每轮扣手续费并降低污点,轮数即等待天数,到期提回同一个地址;存入越多,清洗越差。硬件钱包:链上的币放在 PLEDGER 硬件钱包里,每个钱包的余额和污点各算各的;在终端的钱包页打开、连接。Web3 页的交易、黑市、混币器用已连接的钱包,用币付款的顾客和挖矿收益也进它。付款(黑市、混币器、Ponero 兑换处、上架费)先在终端开账单,再在钱包里手输收款地址、按住 ✓ 签名;地址末尾两位是校验位,输错一位多半会被拦下,偶尔碰巧合法,币就转进了没人用的地址。DEX 兑换也要在钱包上签名。Poinbase 是托管账户,可以直接提到已连接的钱包;从钱包充值要转到 Poinbase 的充值地址,只收 CRC 和 PSC。更多硬件钱包向杰克逊博士购买,拖到交易终端上添加,最多 5 个;黑市上也有更便宜的。不要的钱包可以在钱包页销毁,要先把币转走。转账要付手续费,分慢、普通、快三档,gas 价格大约一周一个起落;网络拥堵时手续费变贵,慢档可能被挤出内存池。转账前核对完整地址。质押:把 CRA 质押进革命军质押池每天有日息,利息并入本金;取出要先申请,等四天才到账,等待期间没有利息,也不能提前拿。质押池靠补贴池付息,补贴池见底会降息,有时还会传出大户撤出的消息,那是预兆:一旦崩盘,三天内 CRA 就一文不值,四天的解锁期来不及。平衡代币 SPARK 可以和 CRA 按价格互相铸销(收手续费),价格波动很大,崩盘时会跟着暴跌。质押、铸销都是合约调用,要在钱包上签名。RatDigg 矿机(M1 / M2 / M3)是独立的机器,算力比显卡大得多、耗电更省,要放电池才挖,可以放模块,不占矿架槽位;只在黑市的矿机商那里有,要黑市声望(M1 40、M2 60、M3 80),偶尔有二手的。暴毙后要往修理槽里放电子元件按顺序修好,修好健康少 20。第 50 到 90 天之间会有一次"矿机时代",提前几天上报纸预告,之后大矿场的耗电成本砍半,全网算力涨上去,显卡矿工的收益被摊薄,低档显卡几乎不赚钱,矿机还行。永续合约:Poinbase 的"永续"页,用账户里的 CRC 当保证金,PSC 最高 5 倍、SPARK 最高 3 倍,一个品种只有一个仓位,不能同时多空。成交价比现价差一截(单越大差得越多,和现货池一样),开平仓还收手续费。强平只在夜里按当天均价检查,权益不到名义价值的 10% 就被强平,保证金没了;每晚还有资金费,价格比近 7 天均价高时多头付给空头。强平后亏光保证金还不够的缺口,先由保险基金垫,基金见底(SPARK 崩盘这类大行情会抽干它)后盈利的仓位会被自动减仓、少拿一半盈利,再不够就记成你的欠款:欠款每天涨 2%,账户里的 CRC 每晚先拿去还,没还清不能开仓、不能出金,七天不还就没收店里的物品抵债,抵不够的核销并拉黑永续账户 30 天。黑市:只收币,不收 CRC,价格比正常渠道贵 30%,高科技物品和显卡另有加价;付出去的币带着按比例的污点留在卖家那边,货不带赃物标签;显卡不保证真假,自己鉴定。订单比现货便宜,要等几天,路上可能被截获;商家按类型卖货,价格系数各不相同,一次订 5 件以上 95 折、10 件以上 9 折,大宗商家随机出现,价格最低但要等六天;托管多付 5% 托管费,收货后放款,卖家跑路时退款;提前放款再打九折,卖家若是骗子钱就没了,只有成交 30 单以上的卖家接受;平台自己也可能跑路,也可能被执法接管,或者卖家落网,之后你的订单会被追查、记罪证;论坛上的传闻可以当预兆。被截获的包裹有时会变成执法人员上门:签收当场记罪证并查封,拒签只损失货款。出售:在黑市的卖货页把储藏区里的违禁品、高科技物品和显卡上架,标价是参考价的 0.6 到 1.8 倍。倍率越高成交越慢(0.9 以下约一天,1.0 约两天,1.8 约十四天),货款带污点的可能性和比例也越高,近 7 天出售的量越大,污点越重;同时最多上架 10 件,上架收 5% 上架费,上架后可以改价(收 2% 改价费,标价按参考价重算,成交的快慢跟着新倍率走),成交扣 8% 抽成,货款托管 3 天后进钱包;卖假卡可能被买家看穿而退货,拉低好评;平台跑路时上架的货和未放款的货款都没了Line truncated
|
||||||
courier.odd1,……东西到了。
|
courier.odd1,……东西到了。
|
||||||
courier.odd2,"(他的手一直放在口袋里)在这儿签个字。"
|
courier.odd2,"(他的手一直放在口袋里)在这儿签个字。"
|
||||||
courier.sign,签收
|
courier.sign,签收
|
||||||
@@ -661,3 +661,55 @@ ponzi.start.sum,开高息理财,日息 {0}%,宣传费 {1} CRC
|
|||||||
ponzi.rug.sum,卷走理财池 {0}
|
ponzi.rug.sum,卷走理财池 {0}
|
||||||
ponzi.err.wallet,要用发行钱包签名。
|
ponzi.err.wallet,要用发行钱包签名。
|
||||||
predict.clue.counter,情报:已排期(柜台线人、传闻纸条)
|
predict.clue.counter,情报:已排期(柜台线人、传闻纸条)
|
||||||
|
web3.sub.airdrop,空投
|
||||||
|
air.h,空投
|
||||||
|
air.none,现在没有可领的空投。
|
||||||
|
air.row,{0} 奖励 {1} CRC {2} 第 {3} 天截止
|
||||||
|
air.claim,领取
|
||||||
|
air.noapprove,不需要授权
|
||||||
|
air.unlimited,授权 {0} 无上限
|
||||||
|
air.limited,授权 {0} {1}
|
||||||
|
air.approvals,{0} 的授权
|
||||||
|
air.approvals.none,没有授权。
|
||||||
|
air.approval,{0}:{1}
|
||||||
|
air.revoke,撤销
|
||||||
|
air.sum,领取空投 {0}({1})
|
||||||
|
air.claimed,领到 {0} CRC。
|
||||||
|
air.revoke.sum,撤销 {0} 的 {1} 授权
|
||||||
|
air.revoked,授权已撤销。
|
||||||
|
air.err.wallet,要用授权的那个钱包签名。
|
||||||
|
pool.h,第三方收益池(CRC)
|
||||||
|
pool.none,暂时没有。
|
||||||
|
pool.col.name,池子
|
||||||
|
pool.col.rate,日息
|
||||||
|
pool.col.reserve,储备
|
||||||
|
pool.col.lock,时间锁
|
||||||
|
pool.col.audit,审计
|
||||||
|
pool.col.mine,存款
|
||||||
|
pool.yes,有
|
||||||
|
pool.no,无
|
||||||
|
pool.pending,取款中
|
||||||
|
pool.closed,(已关闭)
|
||||||
|
pool.deposit,存入
|
||||||
|
pool.withdraw,取出
|
||||||
|
pool.withdraw.lock,申请取出({0} 天)
|
||||||
|
pool.err.cap,超过池子上限,还能存 {0}。
|
||||||
|
pool.err.none,没有存款。
|
||||||
|
pool.sum.in,存入 {0}:{1} CRC
|
||||||
|
pool.sum.out,从 {0} 取出 {1} CRC
|
||||||
|
pool.done.in,存入 {0} CRC 到 {1}。
|
||||||
|
pool.done.out,取出 {0} CRC。
|
||||||
|
pool.done.lock,已申请取出 {0} CRC,第 {1} 天到账。
|
||||||
|
nightlog.scam.drain,{0} 的 {1} {2} 被「{3}」用授权转走了。
|
||||||
|
nightlog.scam.rug,收益池「{0}」跑路,{2} 存的 {1} CRC 没了。
|
||||||
|
nightlog.scam.dry,收益池「{0}」储备用完关闭,{2} 的 {1} CRC 退回。
|
||||||
|
nightlog.scam.paid,收益池「{0}」取款到账:{2} 收到 {1} CRC。
|
||||||
|
nightlog.scam.fakepay,伪造转账:{0}
|
||||||
|
nightlog.scam.sent,转给「客服」安全地址的 {0} {1} 进了骗子的口袋。
|
||||||
|
coinpay.intro,我用 {0} 付,链上确认要一会儿。
|
||||||
|
coinpay.intro.fake,{0} 我已经转过去了,截图给你看,赶紧给货,我赶时间。
|
||||||
|
coinpay.fake.entry,{0} 拿走了 {1},说付了 {2} 信用点的币,链上没有这笔。
|
||||||
|
scam.support.name,Poinbase 客服
|
||||||
|
scam.support.1,您好,我是 Poinbase 客服。系统检测到您的账户有异常登录,已经被风控了。
|
||||||
|
scam.support.2,请在今天内把 {0} CRC 转到安全地址 {1} 做验证,验证完马上退回。
|
||||||
|
scam.support.3,不处理的话账户会被永久冻结。我先走了,记得转。
|
||||||
@@ -56,6 +56,7 @@ namespace Decentralized
|
|||||||
int day = StoreStation.GetDayCounter();
|
int day = StoreStation.GetDayCounter();
|
||||||
d.Market.Open(ActiveEvents(), d.Rng, day);
|
d.Market.Open(ActiveEvents(), d.Rng, day);
|
||||||
d.Market.Whale(d.Rng);
|
d.Market.Whale(d.Rng);
|
||||||
|
if (day >= Tuning.ScamMinDay) { double wk = d.Market.TryWick(d.Rng, day); if (wk != 0) Log.Info($"插针 {wk:+0.000;-0.000},当晚回去 {d.Market.WickBack:0.00}"); }
|
||||||
PredictGame.Morning(d, day);
|
PredictGame.Morning(d, day);
|
||||||
if (!d.OpeningNewsShown)
|
if (!d.OpeningNewsShown)
|
||||||
{
|
{
|
||||||
@@ -184,9 +185,11 @@ namespace Decentralized
|
|||||||
if (d.Network.Reward < rewardBefore) d.Market.OnHalving(d.Rng);
|
if (d.Network.Reward < rewardBefore) d.Market.OnHalving(d.Rng);
|
||||||
if (d.Network.Reward < rewardBefore) News.Show("pd_news_halving_" + day, L.T("news.halving.title"), L.T("news.halving.desc"), 2);
|
if (d.Network.Reward < rewardBefore) News.Show("pd_news_halving_" + day, L.T("news.halving.title"), L.T("news.halving.desc"), 2);
|
||||||
// 预测市场:先登记今晚的观测再结算到期的盘口;行情盘读夜间更新之前的价格
|
// 预测市场:先登记今晚的观测再结算到期的盘口;行情盘读夜间更新之前的价格
|
||||||
|
double pscMark = d.Market.Mark;
|
||||||
|
d.Market.UndoWick(day);
|
||||||
PredictGame.ClosePrice = d.Market.Price; PredictGame.CloseGas = d.Gas; PredictGame.ClosePush = d.Market.PlayerPush;
|
PredictGame.ClosePrice = d.Market.Price; PredictGame.CloseGas = d.Gas; PredictGame.ClosePush = d.Market.PlayerPush;
|
||||||
// 永续:用今天的标记价(当日均价)结算,要在今晚的价格更新之前
|
// 永续:用今天的标记价(当日均价)结算,要在今晚的价格更新之前
|
||||||
var perpEvents = d.Perps.Night(day, new Dictionary<string, double> { ["PSC"] = d.Market.Mark, ["SPARK"] = d.Stable.Spark }, d.Poinbase, Session.Price);
|
var perpEvents = d.Perps.Night(day, new Dictionary<string, double> { ["PSC"] = pscMark, ["SPARK"] = d.Stable.Spark }, d.Poinbase, Session.Price);
|
||||||
if (perpEvents.Any(e => e.Kind == "seize")) SeizeForDebt(d, day);
|
if (perpEvents.Any(e => e.Kind == "seize")) SeizeForDebt(d, day);
|
||||||
var stakeEvents = d.Staking.Night(day, d.Stable.CraRate, d.WalletAt);
|
var stakeEvents = d.Staking.Night(day, d.Stable.CraRate, d.WalletAt);
|
||||||
double crcFactor = d.Stable.Night(day, d.Rng, d.Staking.Earning);
|
double crcFactor = d.Stable.Night(day, d.Rng, d.Staking.Earning);
|
||||||
@@ -241,6 +244,18 @@ namespace Decentralized
|
|||||||
News.Show("pd_news_ponzi_" + day, L.T("news.ponzi.title"), L.T("news.ponzi.desc"), 4);
|
News.Show("pd_news_ponzi_" + day, L.T("news.ponzi.title"), L.T("news.ponzi.desc"), 4);
|
||||||
Log.Info($"理财崩盘:{ponzi.Kind},池子 {ponzi.Amount:0} 被没收");
|
Log.Info($"理财崩盘:{ponzi.Kind},池子 {ponzi.Amount:0} 被没收");
|
||||||
}
|
}
|
||||||
|
foreach (var e in d.Scams.Night(day, d.Rng, d.Own, new[] { Assets.CRT, Assets.PSC, Assets.CRC, Assets.CRA }, Session.Price))
|
||||||
|
{
|
||||||
|
var sw = d.Own(e.Wallet);
|
||||||
|
string wn = sw != null ? WalletWindow.NameOf(sw) : e.Wallet;
|
||||||
|
if (e.Kind == "drain") ps.AddNightLog(L.T("nightlog.scam.drain", wn, Fmt.Num(e.Amount), e.Asset, e.Name), "cc7755");
|
||||||
|
else if (e.Kind == "rug") ps.AddNightLog(L.T("nightlog.scam.rug", e.Name, Fmt.Num(e.Amount), wn), "cc7755");
|
||||||
|
else if (e.Kind == "dry") ps.AddNightLog(L.T("nightlog.scam.dry", e.Name, Fmt.Num(e.Amount), wn));
|
||||||
|
else if (e.Kind == "paid") ps.AddNightLog(L.T("nightlog.scam.paid", e.Name, Fmt.Num(e.Amount), wn));
|
||||||
|
if (sw != null) WalletWindow.RefreshDevice(sw);
|
||||||
|
}
|
||||||
|
foreach (var f in d.FakePaidToday) ps.AddNightLog(L.T("nightlog.scam.fakepay", f), "cc7755");
|
||||||
|
d.FakePaidToday.Clear();
|
||||||
foreach (var e in predictEvents)
|
foreach (var e in predictEvents)
|
||||||
{
|
{
|
||||||
if (e.Kind == "win") ps.AddNightLog(L.T("nightlog.predict.win", PredictGame.Question(e.Market), Fmt.Credits(e.Amount)));
|
if (e.Kind == "win") ps.AddNightLog(L.T("nightlog.predict.win", PredictGame.Question(e.Market), Fmt.Credits(e.Amount)));
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ namespace Decentralized
|
|||||||
public PredictBook Predict = new PredictBook();
|
public PredictBook Predict = new PredictBook();
|
||||||
/// <summary>高息理财(庞氏):一个存档只能开一次。</summary>
|
/// <summary>高息理财(庞氏):一个存档只能开一次。</summary>
|
||||||
public Ponzi Ponzi = new Ponzi();
|
public Ponzi Ponzi = new Ponzi();
|
||||||
|
/// <summary>NPC 骗局:空投与授权、第三方收益池、骗子地址。</summary>
|
||||||
|
public Scams Scams = new Scams();
|
||||||
|
/// <summary>今天被伪造转账骗走的(晨间日志用):顾客名 + 信用点。</summary>
|
||||||
|
public List<string> FakePaidToday = new List<string>();
|
||||||
/// <summary>近几天的 gas 指数(每晚记明天的),情报线索里显示;最近一份局势简报。</summary>
|
/// <summary>近几天的 gas 指数(每晚记明天的),情报线索里显示;最近一份局势简报。</summary>
|
||||||
public List<double> GasHist = new List<double>();
|
public List<double> GasHist = new List<double>();
|
||||||
public List<string> Brief = new List<string>();
|
public List<string> Brief = new List<string>();
|
||||||
|
|||||||
@@ -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 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 double _ponziRate = 0.04;
|
||||||
private static bool _ponziConfirm;
|
private static bool _ponziConfirm;
|
||||||
@@ -843,6 +975,7 @@ namespace Decentralized
|
|||||||
if (_web3Tab == Web3Tab.Stake) { StakePage(b); return; }
|
if (_web3Tab == Web3Tab.Stake) { StakePage(b); return; }
|
||||||
if (_web3Tab == Web3Tab.Predict) { PredictPage(b); return; }
|
if (_web3Tab == Web3Tab.Predict) { PredictPage(b); return; }
|
||||||
if (_web3Tab == Web3Tab.Ponzi) { PonziPage(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.Mining) { ReportPage(b); return; }
|
||||||
if (_web3Tab == Web3Tab.Mixer) { MixerPage(b); return; }
|
if (_web3Tab == Web3Tab.Mixer) { MixerPage(b); return; }
|
||||||
if (_web3Tab == Web3Tab.Black) { BlackPage(b); return; }
|
if (_web3Tab == Web3Tab.Black) { BlackPage(b); return; }
|
||||||
@@ -1307,7 +1440,7 @@ namespace Decentralized
|
|||||||
Open();
|
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 Web3Tab _web3Tab = Web3Tab.Trade;
|
||||||
private static string _mixAsset = Assets.PSC;
|
private static string _mixAsset = Assets.PSC;
|
||||||
private static int _mixRounds = 2;
|
private static int _mixRounds = 2;
|
||||||
@@ -1406,6 +1539,7 @@ namespace Decentralized
|
|||||||
}
|
}
|
||||||
l.AddSeparator();
|
l.AddSeparator();
|
||||||
l.AddLabel(L.T("spark.price", Fmt.Num(st.Spark)));
|
l.AddLabel(L.T("spark.price", Fmt.Num(st.Spark)));
|
||||||
|
YieldPools(l, w, day);
|
||||||
}, r =>
|
}, r =>
|
||||||
{
|
{
|
||||||
r.AddHeader(L.T("stake.ops", WalletWindow.NameOf(w)));
|
r.AddHeader(L.T("stake.ops", WalletWindow.NameOf(w)));
|
||||||
|
|||||||
@@ -619,6 +619,7 @@ namespace Decentralized
|
|||||||
Wallet target = own ?? (IsPoinbase(tx.To) ? d.Poinbase : new Wallet());
|
Wallet target = own ?? (IsPoinbase(tx.To) ? d.Poinbase : new Wallet());
|
||||||
Wallet.Transfer(w, target, tx.Asset, amt, Session.Price);
|
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 && 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);
|
TerminalWindow.Refresh(null);
|
||||||
if (own != null) RefreshDevice(own);
|
if (own != null) RefreshDevice(own);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1301,6 +1301,84 @@ internal static class Program
|
|||||||
Check(Ponzi.InflowMean(20, 0.08, 50) > Ponzi.InflowMean(20, 0.04, 50) * 2, "日息高于 4% 时存入按指数放大");
|
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("预测市场:先验概率", () =>
|
Test("预测市场:先验概率", () =>
|
||||||
{
|
{
|
||||||
Check(Math.Abs(PredictMath.PurityAtLeast(8500, 8000, 8999) - 0.5) < 1e-9, "纯度 8500 以上一半");
|
Check(Math.Abs(PredictMath.PurityAtLeast(8500, 8000, 8999) - 0.5) < 1e-9, "纯度 8500 以上一半");
|
||||||
|
|||||||
Reference in new issue
Block a user