1f857ddf52
SPV is the only verification method the wallet uses, so showing it as a badge adds no information — if a transaction appears confirmed, it has already passed Merkle verification. - Remove the SPV chip from the transaction detail overlay - Remove the Verificata column from the history list (desktop and mobile) - Drop VerifiedText property from TransactionDetailsViewModel - Drop the Verificata field from HistoryRow - Remove the orphaned tx.verified loc key
115 lines
4.2 KiB
C#
115 lines
4.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Linq;
|
|
using PalladiumWallet.App.Localization;
|
|
using PalladiumWallet.Core.Wallet;
|
|
|
|
namespace PalladiumWallet.App.ViewModels;
|
|
|
|
/// <summary>Input/output row for the transaction detail tables.</summary>
|
|
public sealed record TxIoRow(string Position, string Address, string Amount, bool IsMine);
|
|
|
|
/// <summary>
|
|
/// ViewModel for the transaction detail view: takes a
|
|
/// <see cref="TransactionDetails"/> (assembled from server data) and produces
|
|
/// all strings already formatted and localised for the view. Read-only.
|
|
/// </summary>
|
|
public sealed class TransactionDetailsViewModel
|
|
{
|
|
private readonly string _unit;
|
|
|
|
public Loc Loc { get; }
|
|
|
|
public TransactionDetailsViewModel(TransactionDetails d, Loc loc, string unit)
|
|
{
|
|
Loc = loc;
|
|
_unit = unit;
|
|
|
|
Txid = d.Txid;
|
|
IsCoinbase = d.IsCoinbase;
|
|
StatusText = BuildStatus(d, loc);
|
|
DateText = d.BlockTime is { } t
|
|
? t.ToLocalTime().ToString("dd/MM/yyyy HH:mm")
|
|
: loc["tx.mempool"];
|
|
|
|
var counterparties = d.CounterpartyAddresses;
|
|
CounterpartyHeader = d.IsIncoming ? loc["tx.from"] : loc["tx.to"];
|
|
// Coinbase has no sender: coins are newly generated by mining.
|
|
CounterpartyText = d.IsCoinbase
|
|
? loc["tx.coinbase.newcoins"]
|
|
: counterparties.Count > 0
|
|
? string.Join(Environment.NewLine, counterparties)
|
|
: "—";
|
|
|
|
// Debit (outflow to third parties) or Credit (net inflow on our outputs).
|
|
AmountHeader = d.IsIncoming ? loc["tx.credit"] : loc["tx.debit"];
|
|
AmountText = d.IsIncoming
|
|
? Signed(d.ReceivedSats)
|
|
: Signed(-d.SentToOthersSats);
|
|
|
|
FeeText = d.FeeSats is { } fee
|
|
? (d.IsIncoming ? Abs(fee) : Signed(-fee))
|
|
: "—";
|
|
|
|
NetText = Signed(d.NetSats);
|
|
|
|
TotalSizeText = $"{d.TotalSize} byte";
|
|
VirtualSizeText = $"{d.VirtualSize} byte";
|
|
FeeRateText = d.FeeRateSatPerVb is { } r
|
|
? r.ToString("0.0", System.Globalization.CultureInfo.InvariantCulture) + " sat/vB"
|
|
: "—";
|
|
VersionText = d.Version.ToString();
|
|
LockTimeText = d.LockTime.ToString();
|
|
RbfText = loc[d.RbfSignaled ? "tx.yes" : "tx.no"];
|
|
Inputs = new ObservableCollection<TxIoRow>(d.Inputs.Select((i, n) => new TxIoRow(
|
|
i.IsCoinbase ? loc["tx.coinbase"] : $"{Shorten(i.PrevTxid)}:{i.PrevIndex}",
|
|
i.IsCoinbase ? loc["tx.coinbase.newcoins"] : i.Address ?? "—",
|
|
i.AmountSats is { } a ? CoinAmount.FormatIn(a, unit) : "—",
|
|
i.IsMine)));
|
|
|
|
Outputs = new ObservableCollection<TxIoRow>(d.Outputs.Select(o => new TxIoRow(
|
|
$"#{o.Index}",
|
|
o.Address ?? $"({o.ScriptType})",
|
|
CoinAmount.FormatIn(o.AmountSats, unit),
|
|
o.IsMine)));
|
|
}
|
|
|
|
public string Txid { get; }
|
|
public bool IsCoinbase { get; }
|
|
public string StatusText { get; }
|
|
public string DateText { get; }
|
|
public string CounterpartyHeader { get; }
|
|
public string CounterpartyText { get; }
|
|
public string AmountHeader { get; }
|
|
public string AmountText { get; }
|
|
public string FeeText { get; }
|
|
public string NetText { get; }
|
|
public string TotalSizeText { get; }
|
|
public string VirtualSizeText { get; }
|
|
public string FeeRateText { get; }
|
|
public string VersionText { get; }
|
|
public string LockTimeText { get; }
|
|
public string RbfText { get; }
|
|
public ObservableCollection<TxIoRow> Inputs { get; }
|
|
public ObservableCollection<TxIoRow> Outputs { get; }
|
|
|
|
private static string BuildStatus(TransactionDetails d, Loc loc)
|
|
{
|
|
if (d.Confirmations <= 0)
|
|
return loc["tx.status.mempool"];
|
|
return $"{d.Confirmations} {loc["tx.status.confirmations"]} ({loc["tx.status.block"]} {d.Height})";
|
|
}
|
|
|
|
private string Signed(long sats)
|
|
{
|
|
var sign = sats > 0 ? "+" : sats < 0 ? "-" : "";
|
|
return sign + CoinAmount.FormatIn(Math.Abs(sats), _unit);
|
|
}
|
|
|
|
private string Abs(long sats) => CoinAmount.FormatIn(Math.Abs(sats), _unit);
|
|
|
|
private static string Shorten(string txid) =>
|
|
txid.Length > 16 ? $"{txid[..8]}…{txid[^4..]}" : txid;
|
|
}
|