第十阶段 stage 2(二):CRA 部分抵押(储备、抵押率、挪用与崩盘线、劫掠补储备)、官方铸造与销毁排队、官方跑路、质押多币种入口

This commit is contained in:
ZHU MINCHAO committed 2026-11-05 07:14:38 +08:00
1 parent 3758049dcb
commit d0dfa93226
17 files changed
+493 -117

No files matched your search

+55 -16
View File
@@ -2234,7 +2234,15 @@ namespace Decentralized
}
}
l.AddSeparator();
l.AddLabel(L.T("mint.reserve", (st.Ratio * 100).ToString("0", CultureInfo.InvariantCulture), (st.C * 100).ToString("0", CultureInfo.InvariantCulture)), "mint_reserve_dim");
l.AddLabel(L.T("spark.price", Fmt.Num(st.Spark)));
var mine = st.Orders.Where(o => d.Own(o.Wallet) != null).ToList();
if (mine.Count > 0)
{
l.AddSeparator();
l.AddLabel(L.T("mint.queue"));
foreach (var o in mine) l.AddLabel(L.T("mint.order", L.T(o.Mint ? "cra.mint" : "cra.burn"), Fmt.Num(o.Cra), o.Due), "mint_order_dim");
}
}, r =>
{
r.AddHeader(L.T("stake.ops", WalletWindow.NameOf(w)));
@@ -2242,19 +2250,35 @@ namespace Decentralized
r.AddLabel(L.T("stake.avail2", Fmt.Num(w.Avail(Assets.SPARK))), "stake_avail2_dim");
AmountRow(r);
r.AddSpace(4f);
r.AddLabel(L.T("stake.coin"));
r.BeginRow(4f);
foreach (var c in StakeCoins)
{
var coin = c;
PledgerSkin.Pick(r, coin, coin == _stakeCoin, () => { _stakeCoin = coin; Open(); }, _picked);
}
r.End();
r.BeginRow(6f);
r.AddButton(L.T("stake.do"), () => StakeCall(true));
r.AddButton(L.T("stake.undo"), () => StakeCall(false));
r.End();
r.AddSeparator();
r.AddHeader(L.T("spark.h"));
r.AddHeader(L.T("mint.h"));
if (double.TryParse((_amount ?? "").Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out double mv) && mv > 0)
{
st.Collateral(mv, out double needCrc, out double needSpark);
r.AddLabel(L.T("mint.need", Fmt.Num(needCrc), Fmt.Num(needSpark)), "mint_need_dim");
}
r.BeginRow(6f);
r.AddButton(L.T("spark.mint"), () => SparkCall(true));
r.AddButton(L.T("spark.burn"), () => SparkCall(false));
r.AddButton(L.T("cra.mint"), () => MintCall(true));
r.AddButton(L.T("cra.burn"), () => MintCall(false));
r.End();
});
}
private static readonly string[] StakeCoins = { Assets.CRA, Assets.CRC, Assets.CRT, Assets.SPARK };
private static string _stakeCoin = Assets.CRA;
/// <summary>手续费用钱包里价值最高的那种币付。</summary>
private static string BestFeeAsset(Wallet w) =>
w.Balances.Where(k => k.Value > 1e-9 && Session.Price(k.Key) > 0).OrderByDescending(k => k.Value * Session.Price(k.Key)).Select(k => k.Key).FirstOrDefault() ?? Assets.PSC;
@@ -2264,42 +2288,57 @@ namespace Decentralized
if (!ReadAmount(out double v)) return;
var d = Session.Data;
var w = d.Hot;
if (into ? w.Avail(Assets.CRA) + 1e-9 < v : (d.Staking.Of(w.Address)?.Amount ?? 0) + 1e-9 < v) { _message = L.T("msg.balance"); Open(); return; }
string coin = into ? _stakeCoin : Assets.CRA;
if (into ? w.Avail(coin) + 1e-9 < v : (d.Staking.Of(w.Address)?.Amount ?? 0) + 1e-9 < v) { _message = L.T("msg.balance"); Open(); return; }
var q = into && coin != Assets.CRA ? d.Market.Quote(coin, Assets.CRA, v) : null;
_message = L.T("hw.wait");
Open();
WalletWindow.OpenForBill(new WalletWindow.Bill
{
Contract = true, Asset = Assets.CRA, Amount = v, Spend = into ? v : 0, FeeAsset = into ? null : BestFeeAsset(w),
Summary = L.T(into ? "stake.sum.in" : "stake.sum.out", Fmt.Num(v), Tuning.CraUnlockDays),
Contract = true, Asset = coin, Amount = v, Spend = into ? v : 0, FeeAsset = into ? null : BestFeeAsset(w),
Summary = into && q != null ? L.T("stake.sum.via", Fmt.Num(v), coin, Fmt.Num(q.Out)) : L.T(into ? "stake.sum.in" : "stake.sum.out", Fmt.Num(v), Tuning.CraUnlockDays),
Execute = pw =>
{
int day = StoreStation.GetDayCounter();
bool ok = into ? d.Staking.Stake(pw, v, Session.Price) : d.Staking.RequestUnstake(pw.Address, v, day);
_message = ok ? L.T(into ? "stake.done.in" : "stake.done.out", Fmt.Num(v), day + Tuning.CraUnlockDays) : L.T("msg.balance");
double cra = v;
if (into && coin != Assets.CRA)
{
if (pw.Avail(coin) + 1e-9 < v) { _message = L.T("msg.balance"); Open(); return; }
double spent = v * Session.Price(coin);
cra = d.Market.Swap(coin, Assets.CRA, v);
pw.Add(coin, -v); pw.Add(Assets.CRA, cra); pw.RecordBuy(Assets.CRA, cra, spent);
CandleChart.Trade(coin, spent); CandleChart.Trade(Assets.CRA, spent);
}
bool ok = into ? d.Staking.Stake(pw, cra, Session.Price) : d.Staking.RequestUnstake(pw.Address, v, day);
_message = ok ? L.T(into ? "stake.done.in" : "stake.done.out", Fmt.Num(cra), day + Tuning.CraUnlockDays) : L.T("msg.balance");
Session.Save();
Open();
},
});
}
private static void SparkCall(bool mint)
/// <summary>官方一级市场:存入 CRC 和 SPARK 铸造 CRA(铸出后直接进质押),或销毁 CRA 换回两者。排队等待,官方可能不兑现。</summary>
private static void MintCall(bool mint)
{
if (!ReadAmount(out double v)) return;
var d = Session.Data;
var w = d.Hot;
string pay = mint ? Assets.CRA : Assets.SPARK, get = mint ? Assets.SPARK : Assets.CRA;
if (w.Avail(pay) + 1e-9 < v) { _message = L.T("msg.balance"); Open(); return; }
double quote = mint ? v * d.Stable.Cra / d.Stable.Spark * (1 - Tuning.SparkFee) : v * d.Stable.Spark / d.Stable.Cra * (1 - Tuning.SparkFee);
var st = d.Stable;
st.Collateral(v, out double needCrc, out double needSpark);
bool enough = mint ? w.Avail(Assets.CRC) + 1e-9 >= needCrc && w.Avail(Assets.SPARK) + 1e-9 >= needSpark : w.Avail(Assets.CRA) + 1e-9 >= v;
if (!enough) { _message = L.T("msg.balance"); Open(); return; }
int minD = Tuning.CraMintDaysMin, maxD = Tuning.CraMintDaysMax;
_message = L.T("hw.wait");
Open();
WalletWindow.OpenForBill(new WalletWindow.Bill
{
Contract = true, Asset = pay, Amount = v, Summary = L.T("hw.swap", Fmt.Num(v), pay, Fmt.Num(quote), get),
Contract = true, Asset = mint ? Assets.CRC : Assets.CRA, Amount = mint ? needCrc : v, Spend = mint ? needCrc : v,
Summary = mint ? L.T("mint.sum.in", Fmt.Num(v), Fmt.Num(needCrc), Fmt.Num(needSpark), minD, maxD) : L.T("mint.sum.out", Fmt.Num(v), Tuning.CraUnlockDays),
Execute = pw =>
{
double got = mint ? d.Stable.Mint(pw, v) : d.Stable.Burn(pw, v);
if (got >= 0) { double cr = v * Session.Price(pay); CandleChart.Trade(Assets.SPARK, cr); CandleChart.Trade(Assets.CRA, cr); }
_message = got < 0 ? L.T("msg.balance") : L.T("msg.trade", Fmt.Num(v), pay, Fmt.Num(got), get);
int day = StoreStation.GetDayCounter();
var o = mint ? st.RequestMint(pw, v, day, d.Rng) : st.RequestBurn(pw, v, day);
_message = o == null ? L.T("msg.balance") : L.T(mint ? "mint.done.in" : "mint.done.out", o.Due);
Session.Save();
Open();
},