第十阶段 stage 1(三):钱包物品化、连接钱包、空投逐个授权、矿机收款地址

This commit is contained in:
ZHU MINCHAO committed 2026-11-05 01:37:23 +08:00
1 parent f732304f38
commit 59dd3c05bc
20 files changed
+462 -55

No files matched your search

+74 -9
View File
@@ -513,7 +513,10 @@ namespace Decentralized
{
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));
bool authed = d.Connected && Scams.Authorized(a, w);
l.AddLabel(authed ? L.T("air.authed", WalletWindow.NameOf(w)) : L.T("air.unauth"), authed ? "air_authed_dim" : "air_unauth_dim");
if (authed) l.AddButton(L.T("air.claim"), () => ClaimAirdrop(ad));
else l.AddButton(L.T("air.auth"), () => AuthorizeAirdrop(ad));
l.AddSpace(4f);
}
}, r =>
@@ -534,9 +537,33 @@ namespace Decentralized
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));
/// <summary>为这个空投授权当前连接的钱包:在钱包上签授权合约,摘要里写明授权范围(钓鱼空投的范围会写得很大)。</summary>
private static void AuthorizeAirdrop(Airdrop a)
{
var d = Session.Data;
if (!d.Connected) { _message = L.T("web3.err.noconn"); Open(); return; }
_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.auth.sum", a.Name, ApproveText(a.Approve, a.Asset)),
Execute = pw =>
{
Scams.Authorize(a, pw, StoreStation.GetDayCounter());
_message = L.T("air.authed.msg", a.Name);
Log.Info($"授权空投 {a.Name}:钱包 {pw.Address}");
Session.Save();
Open();
},
});
}
private static void ClaimAirdrop(Airdrop a)
{
var d = Session.Data;
if (!d.Connected || !Scams.Authorized(a, d.Hot)) { _message = L.T("air.err.unauth"); Open(); return; }
_message = L.T("hw.wait");
Open();
var w = d.Hot;
@@ -1009,6 +1036,7 @@ namespace Decentralized
{
var d = Session.Data;
b.AddLabel(L.T("wallets.count", d.Wallets.Count, Tuning.WalletMax), "wallets_count_dim");
if (d.Wallets.Count == 0) { b.AddLabel(L.T("wallets.none"), "wallets_none_dim"); return; }
bool wide = L.Wide && Ext < 100f;
float k = Ext < 100f ? 1f : (ScreenW - 70f) / 740f;
bool big = Ext >= 100f;
@@ -1044,7 +1072,7 @@ namespace Decentralized
RowKey(b, L.T("wallets.open"), () => WalletWindow.Open(w));
RowKey(b, L.T("hw.copy"), () => { Clipboard.Copy(w.Address); _message = L.T("hw.copied.addr", w.Address); Open(); });
RowKey(b, L.T("wallets.rename"), () => { _renamePick = w.Address; _renameText = w.Label ?? ""; _message = null; Open(); });
if (idx > 0) RowKey(b, _destroyPick == w.Address ? L.T("wallets.destroy.sure") : L.T("wallets.destroy"), () => DestroyWallet(w));
RowKey(b, _destroyPick == w.Address ? L.T("wallets.destroy.sure") : L.T("wallets.destroy"), () => DestroyWallet(w));
b.End();
b.End();
b.BeginPanel(statW * k, 32f * F, TextAnchor.MiddleRight, 0f, 0f);
@@ -1096,20 +1124,19 @@ namespace Decentralized
b.End();
}
/// <summary>销毁钱包(主钱包不能销毁):要先把币转走;点两次确认。之后回到这个地址的退款、回款、混币提回改进当前钱包。</summary>
/// <summary>销毁钱包:里面的币永久丢失;点两次确认。之后回到这个地址的退款、回款、混币提回都丢了(发给不存在的地址)。销毁的是当前连接的钱包时,变成没有连接。</summary>
private static void DestroyWallet(Wallet w)
{
var d = Session.Data;
int idx = d.Wallets.IndexOf(w);
if (idx <= 0) return;
if (w.Balances.Values.Any(v => v > 1e-9) || w.Frozen.Values.Any(v => v > 1e-9)) { _destroyPick = null; _message = L.T("wallets.destroy.notempty", WalletWindow.NameOf(w)); Open(); return; }
if (_destroyPick != w.Address) { _destroyPick = w.Address; _message = null; Open(); return; }
if (idx < 0) return;
if (_destroyPick != w.Address) { _destroyPick = w.Address; _message = L.T("wallets.destroy.warn", WalletWindow.NameOf(w)); Open(); return; }
_destroyPick = null;
string name = WalletWindow.NameOf(w);
WalletWindow.Close(w);
var current = d.Hot;
var current = d.Connected ? d.Hot : null;
d.Wallets.RemoveAt(idx);
d.Current = Math.Max(0, d.Wallets.IndexOf(current));
d.Current = current == null || current == w ? -1 : d.Wallets.IndexOf(current);
Log.Info($"销毁硬件钱包 {w.Address}{(w.Poisoned ? "(被投毒)" : "")}");
Session.Save();
_message = L.T("wallets.destroyed", name, w.Address);
@@ -1146,7 +1173,11 @@ namespace Decentralized
string name = L.T("web3.sub." + t.ToString().ToLowerInvariant());
PledgerSkin.Pick(b, name, tab == _web3Tab, () => { _web3Tab = tab; _message = null; _edit = null; Open(); }, _picked);
}
b.AddFlexibleSpace();
ConnectWidget(b);
b.End();
ConnectPicker(b);
if (!Session.Data.Connected) b.AddLabel(L.T("web3.err.noconn"), "term_note");
if (_web3Tab == Web3Tab.Stake) { StakePage(b); return; }
if (_web3Tab == Web3Tab.Predict) { PredictPage(b); return; }
if (_web3Tab == Web3Tab.Ponzi) { YieldPage(b); return; }
@@ -1157,7 +1188,7 @@ namespace Decentralized
}
Columns(b, l =>
{
l.AddHeader(L.T("web3.wallet.h") + " " + WalletWindow.NameOf(w));
l.AddHeader(L.T("web3.wallet.h") + (Session.Data.Connected ? " " + WalletWindow.NameOf(w) : ""));
Holdings(l, w, a => true);
l.AddSeparator();
l.AddLabel(L.T("wallet.total", Fmt.Credits(w.Value(Session.Price))));
@@ -1174,6 +1205,40 @@ namespace Decentralized
});
}
private static bool _connectOpen;
/// <summary>Web3 页标签栏最右:已连接显示钱包名、地址和"断开连接",没有连接显示"连接钱包"。状态和钱包页的"已连接"是同一份。</summary>
private static void ConnectWidget(CustomUIBuilder b)
{
var d = Session.Data;
if (d.Connected)
{
var w = d.Hot;
b.AddLabel(L.T("web3.conn", WalletWindow.NameOf(w), ChainAddress.Short(w.Address)));
PledgerSkin.Pick(b, L.T("web3.disconnect"), false, () => { d.Current = -1; _connectOpen = false; WalletWindow.Reset(); Session.Save(); Open(); }, _picked);
}
else PledgerSkin.Pick(b, L.T("web3.connect"), _connectOpen, () =>
{
if (d.Wallets.Count == 0) { _message = L.T("wallets.none"); Open(); return; }
if (d.Wallets.Count == 1) { d.Current = 0; Session.Save(); Open(); return; }
_connectOpen = !_connectOpen; Open();
}, _picked);
}
/// <summary>有多个钱包时,点"连接钱包"在标签栏下面列出钱包,选一个连接。</summary>
private static void ConnectPicker(CustomUIBuilder b)
{
var d = Session.Data;
if (!_connectOpen || d.Connected) { _connectOpen = false; return; }
b.BeginRow(4f);
for (int i = 0; i < d.Wallets.Count; i++)
{
int idx = i; var w = d.Wallets[i];
PledgerSkin.Pick(b, WalletWindow.NameOf(w) + " " + ChainAddress.Short(w.Address), false, () => { d.Current = idx; _connectOpen = false; Session.Save(); Open(); }, _picked);
}
b.End();
}
private enum BlackTab { Buy, Sell, Orders }
private static BlackTab _blackTab = BlackTab.Buy;
private static PayMode _mode = PayMode.Escrow;