Skip to content

Commit

Permalink
Feature: TX data popup (#692)
Browse files Browse the repository at this point in the history
* Add tx data popup

* Fix for coinbasse txs

* Fix mobile info amount price
  • Loading branch information
ben-kaufman committed Nov 24, 2020
1 parent 6b6e067 commit 2b47a44
Show file tree
Hide file tree
Showing 8 changed files with 232 additions and 3 deletions.
15 changes: 15 additions & 0 deletions src/cryptoadvance/specter/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from threading import Thread
from .key import Key
from .device_manager import get_device_class
from .util.tx import decoderawtransaction

from functools import wraps
from flask import g, request, redirect, url_for
Expand Down Expand Up @@ -248,6 +249,20 @@ def setprice():
return {"success": False}


@app.route("/wallets/<wallet_alias>/decoderawtx/", methods=["GET", "POST"])
@login_required
def decoderawtx(wallet_alias):
try:
wallet = app.specter.wallet_manager.get_by_alias(wallet_alias)
txid = request.form.get("txid", "")
if txid:
tx = wallet.rpc.gettransaction(txid)
return {"success": True, "tx": tx, "rawtx": decoderawtransaction(tx["hex"])}
except Exception as e:
app.logger.warning("Failed to update price settings. Exception: {}".format(e))
return {"success": False}


@app.route("/")
@login_required
def index():
Expand Down
48 changes: 48 additions & 0 deletions src/cryptoadvance/specter/templates/includes/explorer-link.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<template id="explorer-link">
<style>
.explorer-link {
color: inherit;
text-decoration: none;
}
.explorer-link:hover {
color: #fff !important;
text-decoration: underline !important;
cursor: pointer;
}
</style>
{% if specter.explorer %}
<a class="explorer-link" target="blank"></a>
{% else %}
<span class="explorer-link"></span>
{% endif %}
</template>

<script type="text/javascript">
class ExplorerLinkElement extends HTMLElement {
constructor() {
super();
// Create a shadow root
var shadow = this.attachShadow({mode: 'open'});
var style = document.getElementById('explorer-link').content;
var clone = style.cloneNode(true);

this.explorerLink = clone.querySelector(".explorer-link");
this.explorer = '{{specter.explorer}}'
this.type = this.getAttribute('data-type');
this.value = this.getAttribute('data-value');
if (this.explorer) {
this.explorerLink.href = `${ this.explorer }${ this.type }/${ this.value }`
} else {
this.explorerLink.addEventListener('click', () => {
copyText(this.value, `Copied ${ this.type }: ${ this.value }`);
});
}
this.explorerLink.innerText = this.value;

// Attach the created element to the shadow dom
shadow.appendChild(clone);
}
}

customElements.define('explorer-link', ExplorerLinkElement);
</script>
146 changes: 146 additions & 0 deletions src/cryptoadvance/specter/templates/includes/tx-data.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<template id="tx-data">
<style>
.tx-data-table td {
text-align: left;
padding: 10px;
overflow: auto;
max-width: 100%;
}
.tx-data-table tr {
margin-bottom: 10px;
border-bottom: 1px solid #aaa;
}
.tx_info {
padding: 1em;
border: 1px solid #506072;
border-radius: 4px;
text-align: center;
margin-bottom: 2em;
}
</style>
<div class="tx-data">
<h2>Transaction details</h2>
<div class="tx-data-info"></div>
<div class="note"></div>
</div>
</template>

<script type="text/javascript">
class TxDataElement extends HTMLElement {
constructor() {
super();
// Create a shadow root
var shadow = this.attachShadow({mode: 'open'});
var style = document.getElementById('tx-data').content;
var clone = style.cloneNode(true);
var txidHeader = clone.querySelector(".txid");

this.el = clone.querySelector(".tx-data");
this.note = clone.querySelector(".note");
this.info = clone.querySelector(".tx-data-info");
this.txid = this.getAttribute('data-txid');
this.wallet = this.getAttribute('data-tx-wallet');
this.note.innerText = `Loading transaction details...\n\nTransaction ID: ${this.txid}`;
fetchTxData(this);

// Attach the created element to the shadow dom
shadow.appendChild(clone);
}
}
async function fetchTxData(self) {
let url = `{{ url_for('decoderawtx', wallet_alias='WALLET_ALIAS') }}`.replace("WALLET_ALIAS", self.wallet);
var formData = new FormData();
formData.append('txid', self.txid)
try {
const response = await fetch(
url,
{
method: 'POST',
body: formData
}
);
if(response.status != 200){
showError(await response.text());
return;
}
const jsonResponse = await response.json();
if (jsonResponse.success) {
console.log(jsonResponse);
let rawtx = jsonResponse.rawtx;
let tx = jsonResponse.tx;
let rawtxHTML = `
<table class="tx-data-table">
<tbody>
<tr><td>Transaction id:</td><td style="word-break: break-all;"><explorer-link data-type="tx" data-value="${self.txid}"></explorer-link></td></tr>
<tr><td>Size:</td><td>${rawtx.vsize} vbytes <span class="note">(${rawtx.size} bytes)</span></td></tr>
`;
if (tx.fee) {
rawtxHTML += `
<tr><td>Fee:</td><td>${parseInt(-1e8 * tx.fee)} sats</td></tr>
<tr><td>Fee rate:</td><td>${parseFloat((-1e8 * tx.fee / rawtx.vsize).toFixed(2)).toString()} sat/vbyte</td></tr>
`;
}
if (tx.confirmations) {
rawtxHTML += `
<tr><td>Mine at block:</td><td>${tx.blockheight}</td></tr>
<tr><td>Block hash:</td><td style="word-break: break-all;">${tx.blockhash}</td></tr>
<tr><td>Block time:</td><td>${new Date(tx.blocktime * 1000)} <span style="font-size: 0.9em;color: #ccc;">(${tx.blocktime})</span></td></tr>
`;
}
rawtxHTML += `
<tr><td>Inputs count:</td><td>${rawtx.vin.length}</td></tr>
<tr><td>Outputs count:</td><td>${rawtx.vout.length}</td></tr>
`;
rawtxHTML += `
</tbody>
</table>
`;
rawtxHTML += `<h3>Inputs</h3>`;
for (let i in rawtx.vin) {
if ('coinbase' in rawtx.vin[i]) {
rawtxHTML += `
<p class="tx_info" style="text-align: left; background-color: #131a24;">
<b>Input #${i}</b><br><br>
<b>Coinbase transaction</b>
<br>
</p>
`;
continue;
}
rawtxHTML += `
<p class="tx_info" style="text-align: left; background-color: #131a24;">
<b>Input #${i}</b><br><br>
Transaction id: <explorer-link style="word-break: break-all;" data-type="tx" data-value="${rawtx.vin[i].txid}"></explorer-link><br>
Output # ${rawtx.vin[i].vout}
</p>
`;
}

rawtxHTML += `<h3>Outputs</h3>`;
for (let i in rawtx.vout) {
let address = ('addresses' in rawtx.vout[i] && rawtx.vout[i].addresses.length == 1) ? rawtx.vout[i].addresses[0] : 'Unknown';
if (address == 'Unknown') {
address = ('addresses' in rawtx.vout[i].scriptPubKey && rawtx.vout[i].scriptPubKey.addresses.length == 1) ? rawtx.vout[i].scriptPubKey.addresses[0] : 'Unknown';
}
rawtxHTML += `
<p class="tx_info" style="text-align: left; background-color: #131a24;">
<b>Output #${i}</b><br><br>
Address: <explorer-link style="word-break: break-all;" data-type="address" data-value="${address}"></explorer-link><br>
Value: ${rawtx.vout[i].value}
</p>
`;
}

self.info.innerHTML = rawtxHTML;
self.note.innerText = "";
return

};
self.note.innerText = "Failed to load transaction details...";
} catch(e) {
self.note.innerText = "Failed to load transaction details...";
showError(e);
}
}
customElements.define('tx-data', TxDataElement);
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
{% endif %}
</td>
<td class="tx scroll optional">
{{ explorer_link('tx', tx['txid'], tx['txid'], specter.explorer) }}
<span class="explorer-link" onclick="showTxData('{{txid}}', '{{wallet.alias}}')">{{ txid }}</span>
{# {{ explorer_link('tx', tx['txid'], tx['txid'], specter.explorer) }} #}
</td>
<td class="tx scroll optional">
{% if wallet == none %}
Expand Down Expand Up @@ -81,7 +82,7 @@
{% endif %}
{{ explorer_link('address', tx['address'], tx['address'] if wallet == none else wallet.get_address_name(tx['address'], -1), specter.explorer) }}
</p>
<p>Amount: {{ tx['amount'] | btcunitamount }}{% if specter.price_check %}<span class="note">{{ tx['amount'] | altunit }}{% endif %}</span></p>
<p>Amount: {{ tx['amount'] | btcunitamount }} {% if specter.price_check %}<span class="note">({{ tx['amount'] | altunit }}){% endif %}</span></p>
<p>Status:
{%if tx['confirmations'] == 0 %}
Pending.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
{#
tx_table - Empty table component
Parameters:
- specter: Specter instance
- isEmpty: Boolean, true if should show an item indicating empty list, false if should show the list contents.
- content: The content of the table (its rows).
- includeValidatedBlockhash: boolean
#}
{% macro tx_table(isEmpty, content, includeValidatedBlockhash) -%}
{% macro tx_table(specter, isEmpty, content, includeValidatedBlockhash) -%}
<table>
<thead>
<tr>
Expand Down Expand Up @@ -37,4 +38,19 @@
{% endif %}
</tbody>
</table>
{% include "includes/tx-data.html" %}
{% include "includes/explorer-link.html" %}
<div id="tx-data-popup" class="hidden">
</div>
<script>
function showTxData(txid, wallet) {
if (wallet) {
let txDataPopup = document.getElementById('tx-data-popup');
txDataPopup.innerHTML = `<tx-data data-txid="${txid}" data-tx-wallet="${wallet}"></tx-data>`;
showPageOverlay('tx-data-popup')
} else {
copyText(txid, `Copied transaction: ${ txid }`);
}
}
</script>
{%- endmacro %}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
{% from 'wallet/history/txs/components/full_tx_table.jinja' import full_tx_table %}
{{
tx_table(
specter,
transactions == [],
full_tx_table(transactions=transactions, wallet=wallet, specter=specter, includeValidatedBlockhash=validate_merkle_proofs),
includeValidatedBlockhash=validate_merkle_proofs,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
<br><br>
{{
tx_table(
specter,
not (wallet.utxo_on_address(account) if is_address_view else wallet.utxo_on_label(account) > 0),
account_utxo_table(account, viewtype, wallet, specter)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
{% from 'wallet/history/txs/components/full_tx_table.jinja' import full_tx_table %}
{{
tx_table(
specter,
transactions == [],
full_tx_table(transactions=transactions, wallet=none, specter=specter, includeValidatedBlockhash=validate_merkle_proofs),
includeValidatedBlockhash=validate_merkle_proofs,
Expand Down

0 comments on commit 2b47a44

Please sign in to comment.