Skip to content

Commit

Permalink
Add wallets overview page (#272)
Browse files Browse the repository at this point in the history
  • Loading branch information
ben-kaufman authored Aug 4, 2020
1 parent 16408d4 commit 8a89c2a
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 7 deletions.
1 change: 1 addition & 0 deletions docs/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- Feature: Dynamically start and manage Specter's Tor Hidden Service from the UI (#257) (@ben-kaufman)
- Feature: Allow user to customize the Bitcoin Core data-dir path (#260) (@ben-kaufman)
- Feature: Automatically derive key origin for depth 0 and 1 (#264) (@hodlwave)
- UI: Add Wallets Overview page showing the combined balance and transactions history of all user's wallets. (#272) (@ben-kaufman)
- UI: Add Bitcoin Core node info dashboard (#267) (@ben-kaufman)
- UI: New landing page and multiple UI fixes. (#269) (@ben-kaufman)
- UI: Make sidebar wallets and devices lists foldable (#263) (@ben-kaufman)
Expand Down
17 changes: 17 additions & 0 deletions src/cryptoadvance/specter/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,7 @@ def new_wallet(wallet_type):
rand=rand
)


@app.route('/wallets/<wallet_alias>/')
@login_required
def wallet(wallet_alias):
Expand All @@ -871,11 +872,27 @@ def wallet(wallet_alias):
else:
return redirect("/wallets/%s/tx/" % wallet_alias)


@app.route('/wallets_overview/')
@login_required
def wallets_overview():
app.specter.check()
idx = int(request.args.get('idx', default=0))
return render_template(
"wallet/wallets_overview.jinja",
idx=idx,
history=True,
specter=app.specter,
rand=rand
)


@app.route('/wallets/<wallet_alias>/tx/')
@login_required
def wallet_tx(wallet_alias):
return redirect("/wallets/%s/tx/history" % wallet_alias)


@app.route('/wallets/<wallet_alias>/tx/history/')
@login_required
def wallet_tx_history(wallet_alias):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
- url_path: URL path the button should lead to (ie. 'new_wallet', 'new_device').
- text: The text of the button.
#}
{% macro sidebar_btn(url_path, text) -%}
{% macro sidebar_btn(url_path, text, icon=true) -%}
<div class="item">
<a href="/{{url_path}}/" class="btn">
<svg width="20" height="20" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>{{ text }}
{% if icon %}<svg width="20" height="20" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>{% endif %}{{ text }}
</a>
</div>
{%- endmacro %}
18 changes: 18 additions & 0 deletions src/cryptoadvance/specter/templates/includes/sidebar/sidebar.jinja
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
{% from 'includes/sidebar/components/sidebar_btn.jinja' import sidebar_btn %}
<style>
#wallets_overview_link {
text-transform: none;
text-decoration: none;
float: right;
margin-right: 10px;
}
#wallets_overview_link:hover {
text-decoration: underline;
color: #fff;
}
</style>
<div id="side-content">
<nav class="side">
{% if specter.info["initialblockdownload"] %}
Expand Down Expand Up @@ -40,6 +53,11 @@
{% endif %}
<div class="separator">
<span id="toggle_wallets_list" style="cursor: pointer;">Wallets &nbsp; &#9660;</span>
{% if (specter.wallet_manager.wallets | length) > 1 %}
<a class="note" id="wallets_overview_link" href="/wallets_overview/" style="cursor: pointer;">
Wallets overview
</a>
{% endif %}
</div>
{% if (specter.device_manager.devices | length) != 0 and specter.chain %}
{% from 'includes/sidebar/components/sidebar_wallet_list_item.jinja' import sidebar_wallet_list_item %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
{{ explorer_link('tx', tx['txid'], tx['txid'], specter.explorer) }}
</td>
<td class="tx scroll">
{{ explorer_link('address', tx['address'], wallet.get_address_name(tx['address'], -1), specter.explorer) }}
{% if wallet == none %}
{% set wallet = specter.wallet_manager.get_by_alias(tx['wallet_alias']) %}
{% endif %}
{{ explorer_link('address', tx['address'], tx['address'] if wallet == none else wallet.get_address_name(tx['address'], -1), specter.explorer) }}
</td>
<td>
{{ tx['amount'] | btcamount }}
Expand Down
55 changes: 55 additions & 0 deletions src/cryptoadvance/specter/templates/wallet/wallets_overview.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{% extends "base.jinja" %}
{% block main %}
<style>
.arrow :hover {
background-color: #ddd;
color: black;
}
.arrow {
text-decoration: none;
display: inline-block;
margin: 0px 16px 16px;
border-radius: 50%;
color: #fff;
font-size: 1.5em;
}
.disabled {
visibility: hidden;
}
</style>
<h1>Wallets Overview</h1>
<p>Here you can see the combined balance and transactions history of all your Specter wallets.</p>
<h1>
<small style="line-height:30px">Total balance:</small><br>
<span style="color: #fff">
{{ specter.wallet_manager.wallets.values() | sum(attribute='fullbalance') | btcamount }}
{% if specter.chain !='main' %}t{%endif%}BTC
</span>
{% if specter.wallet_manager.wallets.values() | sum(attribute='balance.untrusted_pending') > 0 %}<br>
<small>( {{ specter.wallet_manager.wallets.values() | sum(attribute='balance.trusted') | btcamount }} confirmed, {{ specter.wallet_manager.wallets.values() | sum(attribute='balance.untrusted_pending') | btcamount }} pending )</small>
{% endif %}
</h1>
{% set transactions = specter.wallet_manager.full_txlist(idx) %}
{% set next_transactions = specter.wallet_manager.full_txlist(idx + 1) %}
{% if idx != 0 or next_transactions|length != 0 %}
<div>
<a href="./?idx={{ idx - 1 }}" class="arrow {% if idx == 0 %}disabled{% endif %}">&#8249;</a>
{% if next_transactions|length > 0 or idx != 0 %}
Page {{ idx + 1 }}
{% endif %}
<a href="./?idx={{ idx + 1 }}" class="arrow {% if next_transactions|length == 0 %}disabled{% endif %}">&#8250;</a>
</div>
{% endif %}
<div class="table-holder">
{% from 'wallet/history/components/tx_table.jinja' import tx_table %}
{% from 'wallet/history/txs/components/full_tx_table.jinja' import full_tx_table %}
{{
tx_table(
transactions == [],
full_tx_table(transactions, none, specter)
)
}}
</div>
{% endblock %}
8 changes: 4 additions & 4 deletions src/cryptoadvance/specter/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

# a gap of 20 addresses is what many wallets do
WALLET_CHUNK = 20
WALLET_TX_BATCH = 100
wallet_tx_batch = 100

class Wallet():
def __init__(
Expand Down Expand Up @@ -301,11 +301,11 @@ def save_pending_psbt(self, psbt):
self.cli.lockunspent(False, psbt["tx"]["vin"])
self.save_to_file()

def txlist(self, idx):
def txlist(self, idx, wallet_tx_batch=100):
try:
cli_txs = self.cli.listtransactions("*", WALLET_TX_BATCH + 2, WALLET_TX_BATCH * idx, True) # get batch + 2 to make sure you have information about send
cli_txs = self.cli.listtransactions("*", wallet_tx_batch + 2, wallet_tx_batch * idx, True) # get batch + 2 to make sure you have information about send
cli_txs.reverse()
transactions = cli_txs[:WALLET_TX_BATCH]
transactions = cli_txs[:wallet_tx_batch]
except:
return []
txids = []
Expand Down
18 changes: 18 additions & 0 deletions src/cryptoadvance/specter/wallet_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,3 +268,21 @@ def rename_wallet(self, wallet, name):
if self.working_folder is not None:
wallet.save_to_file()
self.update()

def full_txlist(self, idx):
txlists = [
[
{
**tx,
'wallet_alias': wallet.alias
} for tx in wallet.txlist(
idx,
wallet_tx_batch=100 // len(self.wallets)
)
] for wallet in self.wallets.values()
]
result = []
for txlist in txlists:
for tx in txlist:
result.append(tx)
return list(reversed(sorted(result, key=lambda tx: tx["time"])))

0 comments on commit 8a89c2a

Please sign in to comment.