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:
1 parent
58dd93eca6
commit
98e80412e6
12 files changed
+371
-9
No files matched your search
@@ -381,6 +381,7 @@ namespace Decentralized
|
||||
b.AddButton(tab == _web3Tab ? $"[{name}]" : name, () => { _web3Tab = tab; _message = null; _edit = null; Open(); });
|
||||
}
|
||||
b.End();
|
||||
if (_web3Tab == Web3Tab.Stake) { StakePage(b); return; }
|
||||
if (_web3Tab == Web3Tab.Mining) { ReportPage(b); return; }
|
||||
if (_web3Tab == Web3Tab.Mixer) { MixerPage(b); return; }
|
||||
if (_web3Tab == Web3Tab.Black) { BlackPage(b); return; }
|
||||
@@ -844,7 +845,7 @@ namespace Decentralized
|
||||
Open();
|
||||
}
|
||||
|
||||
private enum Web3Tab { Trade, Mining, Mixer, Black }
|
||||
private enum Web3Tab { Trade, Stake, Mining, Mixer, Black }
|
||||
private static Web3Tab _web3Tab = Web3Tab.Trade;
|
||||
private static string _mixAsset = Assets.PSC;
|
||||
private static int _mixRounds = 2;
|
||||
@@ -915,6 +916,103 @@ namespace Decentralized
|
||||
Open();
|
||||
}
|
||||
|
||||
private static readonly float[] StakeW = { 110f, 90f, 200f };
|
||||
|
||||
/// <summary>质押页:革命军 CRA 质押池(日息、解锁排队)和平衡代币 SPARK 的铸销。都是合约调用,要在钱包上签名。</summary>
|
||||
private static void StakePage(CustomUIBuilder b)
|
||||
{
|
||||
var d = Session.Data;
|
||||
var st = d.Stable;
|
||||
var w = d.Hot;
|
||||
int day = StoreStation.GetDayCounter();
|
||||
Columns(b, l =>
|
||||
{
|
||||
l.AddHeader(L.T("stake.h"));
|
||||
l.AddLabel(L.T("stake.rate", (st.CraRate * 100).ToString("0.0", CultureInfo.InvariantCulture), Tuning.CraUnlockDays) + (st.CraSubsidyLow ? " " + L.T("stake.low") : ""));
|
||||
l.AddLabel(L.T("stake.cra", Fmt.Num(st.Cra), StableStatus(st, Assets.CRA, day)));
|
||||
l.AddSeparator();
|
||||
if (d.Staking.Lots.Count == 0) l.AddLabel(L.T("stake.none"));
|
||||
else
|
||||
{
|
||||
TableHeader(l, StakeW, L.T("stake.col.wallet"), L.T("stake.col.amount"), L.T("stake.col.queue"));
|
||||
foreach (var lot in d.Staking.Lots)
|
||||
{
|
||||
var ow = d.Own(lot.Wallet);
|
||||
string queue = lot.Unlocking.Count == 0 ? "—" : string.Join(" ", lot.Unlocking.Select(u => Fmt.Num(u.Value) + L.T("stake.day", u.Key)));
|
||||
TableRow(l, StakeW, ow != null ? WalletWindow.NameOf(ow) : lot.Wallet, Fmt.Num(lot.Amount), queue);
|
||||
}
|
||||
}
|
||||
l.AddSeparator();
|
||||
l.AddLabel(L.T("spark.price", Fmt.Num(st.Spark)));
|
||||
}, r =>
|
||||
{
|
||||
r.AddHeader(L.T("stake.ops", WalletWindow.NameOf(w)));
|
||||
r.AddLabel(L.T("stake.avail", Fmt.Num(w.Avail(Assets.CRA)), Fmt.Num(d.Staking.Of(w.Address)?.Amount ?? 0)));
|
||||
r.AddLabel(L.T("stake.avail2", Fmt.Num(w.Avail(Assets.SPARK))));
|
||||
AmountRow(r);
|
||||
r.BeginRow();
|
||||
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.BeginRow();
|
||||
r.AddButton(L.T("spark.mint"), () => SparkCall(true));
|
||||
r.AddButton(L.T("spark.burn"), () => SparkCall(false));
|
||||
r.End();
|
||||
});
|
||||
}
|
||||
|
||||
/// <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;
|
||||
|
||||
private static void StakeCall(bool into)
|
||||
{
|
||||
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; }
|
||||
_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),
|
||||
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");
|
||||
Session.Save();
|
||||
Open();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private static void SparkCall(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);
|
||||
_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),
|
||||
Execute = pw =>
|
||||
{
|
||||
double got = mint ? d.Stable.Mint(pw, v) : d.Stable.Burn(pw, v);
|
||||
_message = got < 0 ? L.T("msg.balance") : L.T("msg.trade", Fmt.Num(v), pay, Fmt.Num(got), get);
|
||||
Session.Save();
|
||||
Open();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private static bool frozenPay(Wallet w, string asset) => w.Frozen.ContainsKey(asset);
|
||||
|
||||
private static string AvgText(Wallet w, string asset) => w.AvgBuy(asset) is double a ? Fmt.Num(a) : L.T("avg.none");
|
||||
|
||||
Reference in new issue
Block a user