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