fedimint_server_ui/dashboard/modules/
wallet.rs
1use maud::{Markup, html};
2
3pub async fn render(wallet: &fedimint_wallet_server::Wallet) -> Markup {
5 let network = wallet.network_ui();
6 let consensus_block_count = wallet.consensus_block_count_ui().await;
7 let consensus_fee_rate = wallet.consensus_feerate_ui().await;
8 let wallet_summary = wallet.get_wallet_summary_ui().await;
9 let total_spendable = wallet_summary.total_spendable_balance().to_sat();
10 let total_unsigned_change = wallet_summary.total_unsigned_change_balance().to_sat();
11 let total_unconfirmed_change = wallet_summary.total_unconfirmed_change_balance().to_sat();
12 let total_available = total_spendable + total_unconfirmed_change + total_unsigned_change;
13 let total_unsigned_outgoing = wallet_summary.total_unsigned_peg_out_balance().to_sat();
14 let total_unconfirmed_outgoing = wallet_summary.total_unconfirmed_peg_out_balance().to_sat();
15
16 html! {
17 div class="card h-100" {
18 div class="card-header dashboard-header" { "Wallet" }
19 div class="card-body" {
20 table class="table mb-4" {
21 tr {
22 th { "Network" }
23 td { (network.to_string()) }
24 }
25 tr {
26 th { "Consensus Block Count" }
27 td { (consensus_block_count) }
28 }
29 tr {
30 th { "Consensus Fee Rate" }
31 td { (consensus_fee_rate.sats_per_kvb) " sats/kvB" }
32 }
33 tr {
34 th { "Spendable Amount" }
35 td { (total_spendable) " sats" }
36 }
37 tr {
38 th { "Unsigned Change Amount" }
39 td { (total_unsigned_change) " sats" }
40 }
41 tr {
42 th { "Unconfirmed Change Amount" }
43 td { (total_unconfirmed_change) " sats" }
44 }
45 tr {
46 th { "Total Amount in Custody" }
47 td { (total_available) " sats" }
48 }
49 tr {
50 th { "Unsigned Outgoing Amount" }
51 td { (total_unsigned_outgoing) " sats" }
52 }
53 tr {
54 th { "Unconfirmed Outgoing Amount" }
55 td { (total_unconfirmed_outgoing) " sats" }
56 }
57 }
58
59 div class="mb-4" {
61 p {
62 button class="btn btn-sm btn-outline-primary" type="button" data-bs-toggle="collapse" data-bs-target="#balanceInfo" aria-expanded="false" aria-controls="balanceInfo" {
63 "What do these amounts mean? "
64 i class="bi bi-info-circle" {}
65 }
66 }
67 div class="collapse" id="balanceInfo" {
68 div class="alert alert-info" {
69 dl class="row mb-0" {
70 dt class="col-sm-3" { "Spendable Amount" }
71 dd class="col-sm-9" { "UTXOs that are confirmed and are available to be spend by your users." }
72
73 dt class="col-sm-3" { "Change Amounts" }
74 dd class="col-sm-9" {
75 p class="mb-1" { strong { "Unsigned: " } "Change outputs from pegout transactions still waiting for guardian signatures." }
76 p class="mb-0" { strong { "Unconfirmed: " } "Change outputs with threshold of signatures, waiting for blockchain confirmations." }
77 }
78
79 dt class="col-sm-3" { "Total Amount in Custody" }
80 dd class="col-sm-9" {
81 "Sum of Spendable Amount and both unsigned and unconfirmed change amounts. This represents all funds that will eventually be available to you once all transactions are confirmed."
82 }
83
84 dt class="col-sm-3" { "Outgoing Amounts" }
85 dd class="col-sm-9" {
86 p class="mb-1" { strong { "Unsigned: " } "Pegout outputs from pegout transactions still waiting for guardian signatures." }
87 p class="mb-0" { strong { "Unconfirmed: " } "Pegout outputs with threshold of signatures, waiting for blockchain confirmations." }
88 }
89 }
90 }
91 }
92 }
93
94 div class="mb-4" {
96 @if !wallet_summary.unconfirmed_peg_out_txos.is_empty() {
97 div class="mb-4" {
98 h5 { "Unconfirmed Pegout UTXOs" }
99 div class="table-responsive" {
100 table class="table table-sm" {
101 thead {
102 tr {
103 th { "Amount (sats)" }
104 th { "Transaction" }
105 th { "Vout" }
106 }
107 }
108 tbody {
109 @for txo in &wallet_summary.unconfirmed_peg_out_txos {
110 tr {
111 td { (txo.amount.to_sat()) }
112 td {
113 a href={ "https://mempool.space/tx/" (txo.outpoint.txid) } class="btn btn-sm btn-outline-primary" target="_blank" {
114 "mempool.space"
115 }
116 }
117 td { (txo.outpoint.vout) }
118 }
119 }
120 }
121 }
122 }
123 }
124 }
125
126 @if !wallet_summary.unconfirmed_change_utxos.is_empty() {
128 div class="mb-4" {
129 h5 { "Unconfirmed Change UTXOs" }
130 div class="table-responsive" {
131 table class="table table-sm" {
132 thead {
133 tr {
134 th { "Amount (sats)" }
135 th { "Transaction" }
136 th { "Vout" }
137 }
138 }
139 tbody {
140 @for txo in &wallet_summary.unconfirmed_change_utxos {
141 tr {
142 td { (txo.amount.to_sat()) }
143 td {
144 a href={ "https://mempool.space/tx/" (txo.outpoint.txid) } class="btn btn-sm btn-outline-primary" target="_blank" {
145 "mempool.space"
146 }
147 }
148 td { (txo.outpoint.vout) }
149 }
150 }
151 }
152 }
153 }
154 }
155 }
156
157 @if !wallet_summary.spendable_utxos.is_empty() {
159 div class="mb-4" {
160 h5 { "Spendable UTXOs" }
161 div class="table-responsive" {
162 table class="table table-sm" {
163 thead {
164 tr {
165 th { "Amount (sats)" }
166 th { "Transaction" }
167 th { "Vout" }
168 }
169 }
170 tbody {
171 @for utxo in &wallet_summary.spendable_utxos {
172 tr {
173 td { (utxo.amount.to_sat()) }
174 td {
175 a href={ "https://mempool.space/tx/" (utxo.outpoint.txid) } class="btn btn-sm btn-outline-primary" target="_blank" {
176 "mempool.space"
177 }
178 }
179 td { (utxo.outpoint.vout) }
180 }
181 }
182 }
183 }
184 }
185 }
186 }
187 }
188 }
189 }
190 }
191}