Stage 6.1: CRA staking pool, SPARK balance token with mint/burn

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ZHU MINCHAOandClaude Sonnet 5.5 committed 2026-11-04 00:06:16 +08:00
1 parent 58dd93eca6
commit 98e80412e6
12 files changed
+371 -9

No files matched your search

@@ -808,6 +808,47 @@ internal static class Program
Check(!ChainAddress.Valid("0x12345") && !ChainAddress.Valid("0xzzzzzzzz") && !ChainAddress.WellFormed("12345678ab"), "格式不对的地址不合法");
});
Test("CRA 质押池:计息、解锁期、污点随币、螺旋", () =>
{
Func<string, double> price = a => a == Assets.PSC ? 100 : 1;
var w = new Wallet { Address = "0xa" }; w.Add(Assets.CRA, 1000); w.Add(Assets.PSC, 10); w.Taint = 400; w.Basis = 600;
var st = new Staking();
Check(!st.Stake(w, 2000, price), "余额不足不能质押");
Check(st.Stake(w, 500, price) && Math.Abs(w.Get(Assets.CRA) - 500) < 1e-9, "质押 500,钱包剩 500");
double lotTaint = st.Of("0xa").Taint;
Check(Math.Abs(lotTaint - 400 * 500.0 / 2000) < 1e-6 && Math.Abs(w.Taint - (400 - lotTaint)) < 1e-6, $"污点按价值比例进仓位:{lotTaint}");
var e1 = st.Night(1, Tuning.CraRate, _ => w);
Check(Math.Abs(st.Of("0xa").Amount - 500 * (1 + Tuning.CraRate)) < 1e-9 && e1.Count == 1, "每晚计息并入本金");
Check(!st.RequestUnstake("0xa", 9999, 1) && st.RequestUnstake("0xa", 200, 1), "申请取出 200");
double a0 = st.Of("0xa").Amount;
st.Night(2, Tuning.CraRate, _ => w);
Check(Math.Abs(st.Of("0xa").Amount - a0 * (1 + Tuning.CraRate)) < 1e-9, "排队的部分不计息");
Check(w.Get(Assets.CRA) < 501, "解锁期没到不能取");
for (int d = 3; d <= 1 + Tuning.CraUnlockDays; d++) st.Night(d, Tuning.CraRate, _ => w);
Check(Math.Abs(w.Get(Assets.CRA) - 700) < 1e-6, $"到期自动回钱包 200:{w.Get(Assets.CRA):0.##}");
Check(w.Taint > 400 - lotTaint + 1, "污点按比例回来");
// 螺旋:质押的 CRA 取回后只值当时的价格
var s = new Stablecoins(); s.CraSpiralDay = 5;
for (int d = 5; d <= 7; d++) s.Night(d, new Rng(1), 0);
Check(s.Cra < 0.05 && s.Spark < Tuning.SparkStart * 0.1, $"螺旋后 CRA {s.Cra},SPARK {s.Spark:0.00}");
});
Test("SPARK:随机游走有界,铸销来回只损手续费,事件冲击", () =>
{
double lo = 99, hi = 0;
for (ulong seed = 1; seed <= 20; seed++)
{
var s = new Stablecoins(); var rng = new Rng(seed);
for (int d = 1; d <= 150 && s.CraWarnDay < 0; d++) { s.Night(d, rng, 0); lo = Math.Min(lo, s.Spark); hi = Math.Max(hi, s.Spark); } // 螺旋前
}
Check(lo >= Tuning.SparkStart * Tuning.SparkMinMult - 1e-9 && hi <= Tuning.SparkStart * Tuning.SparkMaxMult + 1e-9 && hi / lo > 1.5, $"螺旋前的范围 {lo:0.0}–{hi:0.0}");
var s2 = new Stablecoins(); var w = new Wallet { Address = "w" }; w.Add(Assets.CRA, 100);
double sp = s2.Mint(w, 100), back = s2.Burn(w, sp);
Check(Math.Abs(back - 100 * Math.Pow(1 - Tuning.SparkFee, 2)) < 1e-6 && s2.Mint(w, 1e6) < 0, $"来回 100 → {back:0.00},余额不足返回 -1");
double before = s2.Spark; s2.OnEventStart(MarketEvent.RevRaidUpper, 1, new Rng(1));
Check(Math.Abs(s2.Spark - before * Tuning.SparkRaidShock) < 1e-9, "袭击上层 +15%");
});
Test("相似地址、手续费、确认数", () =>
{
var rng = new Rng(21);