Phase 2: mixer (Web3 tab in the network, terminal page, sanctions, night return), unlock registration per upgrade
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
133367b58d
commit
09a5cae69c
11 files changed
+290
-16
No files matched your search
@@ -13,7 +13,7 @@ namespace Decentralized
|
||||
public static class TerminalWindow
|
||||
{
|
||||
public const string Id = "pd_terminal";
|
||||
private enum Page { Home, Bank, Poinbase, Web3, Report }
|
||||
private enum Page { Home, Bank, Poinbase, Web3, Mixer, Report }
|
||||
|
||||
private static Page _page = Page.Home;
|
||||
private static string _amount = "";
|
||||
@@ -28,6 +28,7 @@ namespace Decentralized
|
||||
b.BeginRow();
|
||||
foreach (Page p in Enum.GetValues(typeof(Page)))
|
||||
{
|
||||
if (p == Page.Mixer && !Unlock.MixerUnlocked) continue;
|
||||
var page = p;
|
||||
string name = L.T("tab." + p.ToString().ToLowerInvariant());
|
||||
b.AddButton(page == _page ? $"[{name}]" : name, () => { _page = page; _message = null; Open(); });
|
||||
@@ -41,6 +42,7 @@ namespace Decentralized
|
||||
case Page.Bank: BankPage(b); break;
|
||||
case Page.Poinbase: ExchangePage(b, Venue.Exchange); break;
|
||||
case Page.Web3: Web3Page(b); break;
|
||||
case Page.Mixer: MixerPage(b); break;
|
||||
default: ReportPage(b); break;
|
||||
}
|
||||
b.End();
|
||||
@@ -252,6 +254,72 @@ namespace Decentralized
|
||||
});
|
||||
}
|
||||
|
||||
private static string _mixAsset = Assets.PSC;
|
||||
private static int _mixRounds = 2;
|
||||
private static readonly float[] MixW = { 70f, 100f, 100f, 80f };
|
||||
|
||||
/// <summary>混币器:把币存进去,几轮之后提回同一个地址,污点降低,每轮扣手续费。</summary>
|
||||
private static void MixerPage(CustomUIBuilder b)
|
||||
{
|
||||
var d = Session.Data;
|
||||
var w = d.Hot;
|
||||
int day = StoreStation.GetDayCounter();
|
||||
Columns(b, l =>
|
||||
{
|
||||
l.AddHeader(L.T("mixer.h"));
|
||||
l.AddLabel(d.Mixer.Sanctioned(day) ? L.T("mixer.sanctioned", d.Mixer.SanctionedUntil - day + 1) : L.T("mixer.ok"));
|
||||
if (w.Taint > 0.5) l.AddLabel(L.T("wallet.taint", Fmt.Credits(w.Taint)));
|
||||
l.AddSeparator();
|
||||
l.AddHeader(L.T("mixer.pending"));
|
||||
if (d.Mixer.Pending.Count == 0) l.AddLabel(L.T("mixer.none"));
|
||||
else
|
||||
{
|
||||
TableHeader(l, MixW, L.T("col.asset"), L.T("col.amount"), L.T("mixer.col.taint"), L.T("mixer.col.ready"));
|
||||
foreach (var p in d.Mixer.Pending)
|
||||
TableRow(l, MixW, p.Asset, Fmt.Num(p.Amount), Fmt.Credits(p.Taint), L.T("mixer.day", p.ReadyDay));
|
||||
}
|
||||
}, r =>
|
||||
{
|
||||
r.AddHeader(L.T("mixer.deposit"));
|
||||
foreach (var line in L.T("mixer.hint").Split('|')) r.AddLabel(line);
|
||||
r.BeginRow();
|
||||
foreach (var a in new[] { Assets.PSC, Assets.CRC, Assets.CRT, Assets.CRA })
|
||||
{
|
||||
var asset = a;
|
||||
r.AddButton(asset == _mixAsset ? $"[{asset}]" : asset, () => { _mixAsset = asset; Open(); });
|
||||
}
|
||||
r.End();
|
||||
r.AddLabel(L.T("mixer.balance", _mixAsset, Fmt.Num(w.Get(_mixAsset))));
|
||||
AmountRow(r);
|
||||
r.AddLabel(L.T("mixer.rounds"));
|
||||
r.BeginRow();
|
||||
for (int n = 1; n <= Tuning.MixerMaxRounds; n++)
|
||||
{
|
||||
int rounds = n;
|
||||
r.AddButton(rounds == _mixRounds ? $"[{rounds}]" : rounds.ToString(), () => { _mixRounds = rounds; Open(); });
|
||||
}
|
||||
r.End();
|
||||
if (double.TryParse((_amount ?? "").Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out double v) && v > 0)
|
||||
{
|
||||
double rate = Mixer.RoundRate(v * Session.Price(_mixAsset));
|
||||
r.AddLabel(L.T("mixer.preview", Fmt.Num(v * Math.Pow(1 - Tuning.MixerFee, _mixRounds)), _mixAsset, (int)Math.Round((1 - Math.Pow(1 - rate, _mixRounds)) * 100), day + _mixRounds));
|
||||
}
|
||||
r.AddButton(L.T("mixer.go"), MixDeposit);
|
||||
});
|
||||
}
|
||||
|
||||
private static void MixDeposit()
|
||||
{
|
||||
if (!ReadAmount(out double v)) return;
|
||||
var d = Session.Data;
|
||||
int day = StoreStation.GetDayCounter();
|
||||
if (d.Hot.Get(_mixAsset) + 1e-9 < v) { _message = L.T("msg.balance"); Open(); return; }
|
||||
var dep = d.Mixer.Deposit(d.Hot, _mixAsset, v, _mixRounds, day, Session.Price);
|
||||
_message = dep == null ? L.T("mixer.min", Tuning.MixerMin) : L.T("mixer.done", Fmt.Num(v), _mixAsset, dep.ReadyDay);
|
||||
Session.Save();
|
||||
Open();
|
||||
}
|
||||
|
||||
private static string AvgText(Wallet w, string asset) => w.AvgBuy(asset) is double a ? Fmt.Num(a) : L.T("avg.none");
|
||||
|
||||
private static void ReportPage(CustomUIBuilder b)
|
||||
@@ -299,7 +367,7 @@ namespace Decentralized
|
||||
if (!ReadAmount(out double v)) return;
|
||||
var d = Session.Data;
|
||||
if (d.Hot.Get(Assets.CRC) + 1e-9 < v) { _message = L.T("msg.balance"); Open(); return; }
|
||||
var r = d.Exchange.Cashout(d.Hot, v, Session.Price, StoreStation.GetDayCounter(), Session.Rent(), false, d.Rng);
|
||||
var r = d.Exchange.Cashout(d.Hot, v, Session.Price, StoreStation.GetDayCounter(), Session.Rent(), d.Mixer.RecentlyMixed(StoreStation.GetDayCounter()), d.Rng);
|
||||
int got = (int)Math.Floor(r.Received - r.Tax);
|
||||
ModHelper.AddCredit(got, true);
|
||||
_message = L.T("msg.cashout", got, Fmt.Credits(r.Tax));
|
||||
|
||||
Reference in new issue
Block a user