mirror of
https://github.com/cryptoadvance/specter-desktop.git
synced 2026-08-13 12:33:29 +02:00
Bugfix: Missing values in tx details (#1862)
* fix missing values in tx details * cypress test * remove spaces after Address * better handling of non-wallet txids in inputs * Update zblack.yml Co-authored-by: moneymanolis <moneymanolis@protonmail.com> Co-authored-by: k9ert <kneunert@gmail.com>
This commit is contained in:
parent
e3d09f15c3
commit
9394d7993d
7 changed files with 168 additions and 78 deletions
4
.github/workflows/zblack.yml
vendored
4
.github/workflows/zblack.yml
vendored
|
|
@ -8,6 +8,4 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: psf/black@22.3.0 # the default is equivalent to `black . --diff --check`.
|
||||
with:
|
||||
args: ". --diff --check"
|
||||
- uses: psf/black@stable # https://black.readthedocs.io/en/stable/integrations/github_actions.html
|
||||
|
|
|
|||
|
|
@ -30,7 +30,38 @@ describe('Test sending transactions', () => {
|
|||
expect(n).to.be.equals(0)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
// Skipped for now, will only work reliably once the the Cypress tests run without mining loop
|
||||
it('Open up transaction details', () => {
|
||||
cy.selectWallet("Test Hot Wallet 1")
|
||||
cy.get('#btn_transactions').click()
|
||||
// Click on the txid in the first row
|
||||
cy.get('tbody.tx-tbody').find('tr').eq(0).find('#column-txid').find('.explorer-link').click()
|
||||
cy.get('.tx-data-info').contains('Input #0')
|
||||
cy.get('.tx-data-info').contains('Transaction id:')
|
||||
cy.get('.tx-data-info').contains('Output index:') // Not sure whether it is always 1 - output ordering is random in Core ...
|
||||
cy.get('.tx-data-info').contains('Address #0')
|
||||
cy.get('.tx-data-info').contains('Value: 20 tBTC')
|
||||
cy.get('.tx-data-info').contains('Output #0')
|
||||
cy.get('.tx-data-info').contains('Burn address')
|
||||
cy.get('.tx-data-info').contains('Value: 19.9999989 tBTC') // Fees should always be the same
|
||||
cy.get('#page_overlay_popup_cancel_button').click()
|
||||
// Change to sats and check amounts and units
|
||||
cy.get('[href="/settings/"]').click()
|
||||
cy.get('[name="unit"]').select('sats')
|
||||
cy.contains('Save').click()
|
||||
cy.selectWallet("Test Hot Wallet 1")
|
||||
cy.get('#btn_transactions').click()
|
||||
cy.get('tbody.tx-tbody').find('tr').eq(0).find('#column-txid').find('.explorer-link').click()
|
||||
cy.get('.tx-data-info').contains('Value: 2,000,000,000 tsat')
|
||||
cy.get('.tx-data-info').contains('Value: 1,999,999,890 tsat')
|
||||
cy.get('#page_overlay_popup_cancel_button').click()
|
||||
// Change back to btc
|
||||
cy.get('[href="/settings/"]').click()
|
||||
cy.get('[name="unit"]').select('BTC')
|
||||
cy.contains('Save').click()
|
||||
})
|
||||
|
||||
it('Adding and deleting recipients', () => {
|
||||
// We need new sats but mine2wallet only works if a wallet is selected
|
||||
cy.selectWallet("Test Hot Wallet 1")
|
||||
|
|
|
|||
|
|
@ -256,7 +256,24 @@ def decoderawtx(wallet_alias):
|
|||
wallet: Wallet = app.specter.wallet_manager.get_by_alias(wallet_alias)
|
||||
txid = request.form.get("txid", "")
|
||||
if txid:
|
||||
tx = wallet.rpc.gettransaction(txid)
|
||||
try:
|
||||
tx = wallet.rpc.gettransaction(txid)
|
||||
except RpcError as e:
|
||||
if "Invalid or non-wallet transaction id" in str(e):
|
||||
# Expected failure when looking up a txid that didn't originate from the
|
||||
# user's Wallet.
|
||||
logger.info(
|
||||
"Looking up a txid that didn't originate from the user's wallet. Can't return any tx data."
|
||||
)
|
||||
return jsonify(
|
||||
success=False,
|
||||
nonWalletTxId=True,
|
||||
)
|
||||
else:
|
||||
logger.warning(
|
||||
"Failed to fetch transaction data. Exception: {}".format(e)
|
||||
)
|
||||
return jsonify(success=False)
|
||||
# This is a fix for Bitcoin Core versions < v0.20
|
||||
# These do not return the blockheight as part of the `gettransaction` command
|
||||
# So here we check if this property is lacking and if so
|
||||
|
|
@ -310,15 +327,6 @@ def decoderawtx(wallet_alias):
|
|||
rawtx=rawtx,
|
||||
walletName=wallet.name,
|
||||
)
|
||||
except RpcError as e:
|
||||
if "Invalid or non-wallet transaction id" in str(e):
|
||||
# Expected failure when looking up a txid that didn't originate from the
|
||||
# user's Wallet.
|
||||
pass
|
||||
else:
|
||||
app.logger.warning(
|
||||
"Failed to fetch transaction data. Exception: {}".format(e)
|
||||
)
|
||||
except Exception as e:
|
||||
app.logger.warning("Failed to fetch transaction data. Exception: {}".format(e))
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
}
|
||||
</style>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='helpers.js') }}"></script>
|
||||
{% include "includes/helpers.jinja" %}
|
||||
{% include "services/inject_in_basejinja_head.jinja" %}
|
||||
{% block head %}
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
}
|
||||
.service-icon {
|
||||
margin-top: -5px;
|
||||
margin-right: 0.25em;
|
||||
height:24px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
|
@ -65,9 +64,7 @@
|
|||
}
|
||||
</style>
|
||||
<form class="address-label-form">
|
||||
<input type="hidden" class="csrf-token" name="csrf_token" value="{{ csrf_token() }}"/>
|
||||
<img class="service-icon"/>
|
||||
<a target="_blank" class="explorer-link"><span class="label" autocomplete="off" spellcheck="false">{{ _("Fetching address label...") }}</span></a>
|
||||
<input type="hidden" class="csrf-token" name="csrf_token" value="{{ csrf_token() }}"/><img class="service-icon"><a target="_blank" class="explorer-link"><span class="label" autocomplete="off" spellcheck="false">{{ _("Fetching address label...") }}</span></a>
|
||||
<button type="button" class="btn edit" title="Edit label"><img src="{{ url_for('static', filename='img/edit.svg') }}" style="width: 22px; margin-bottom:-5px;" class="svg-white"/></button>
|
||||
<button type="button" class="btn update hidden">{{ _("Update") }}</button>
|
||||
<button type="button" class="btn cancel hidden">{{ _("Cancel") }}</button>
|
||||
|
|
|
|||
75
src/cryptoadvance/specter/templates/includes/helpers.jinja
Normal file
75
src/cryptoadvance/specter/templates/includes/helpers.jinja
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
<!-- This file contains javascript helper functions that also can use jinja -->
|
||||
<script type="text/javascript">
|
||||
|
||||
// Formats an unitLabel (e.g. from a tx output) to a useful unit label
|
||||
function formatUnitLabel(unitLabel, convertToSat){
|
||||
var newLabel = unitLabel;
|
||||
if (newLabel == "" || !newLabel){
|
||||
newLabel = {% if specter.is_liquid %}"LBTC"{%else%}"BTC"{%endif%}
|
||||
}
|
||||
if (convertToSat) {
|
||||
if(newLabel == "LBTC"){
|
||||
newLabel = "Lsat";
|
||||
}
|
||||
// Liquid JSON response on testnet is already tLBTC
|
||||
else if (newLabel == "tLBTC") {
|
||||
newLabel = "tLsat";
|
||||
}
|
||||
if(newLabel == "BTC"){
|
||||
newLabel = "sat";
|
||||
}
|
||||
}
|
||||
|
||||
{% if specter.is_testnet %}
|
||||
if (!newLabel.startsWith("t")){
|
||||
newLabel = "t" + newLabel;
|
||||
}
|
||||
{%endif%}
|
||||
|
||||
return newLabel;
|
||||
}
|
||||
|
||||
// Formats the valueInBTC (e.g. from a tx output) to "formattedValue formattedUnitLabel"
|
||||
// e.g. 0.22569496 tBTC
|
||||
function formatBtcAmount(valueInBTC, unitLabel, convertToSat){
|
||||
var formattedUnitLabel = formatUnitLabel(unitLabel, convertToSat);
|
||||
var formattedValue = valueInBTC;
|
||||
if (valueInBTC) {
|
||||
value = parseFloat(valueInBTC.toFixed(8));
|
||||
// The second condition in the if clause if True if formattedUnitLabel is equal to any element of the array
|
||||
if (convertToSat && (["Lsat", "sat", "tLsat", "tsat"].indexOf(formattedUnitLabel) > -1)) {
|
||||
formattedValue = parseInt(value * 1e8)
|
||||
}
|
||||
formattedValue = `${numberWithCommas(formattedValue)}`;
|
||||
}
|
||||
else {
|
||||
formattedValue = '{{ _("Confidential") }}';
|
||||
formattedUnitLabel = '';
|
||||
}
|
||||
return `${formattedValue} ${formattedUnitLabel}`;
|
||||
}
|
||||
|
||||
// Determines if an unitLabel (e.g. from a tx output) is "BTC", "LBTC", "tBTC", "tLBTC"
|
||||
function unitLabelIsBitcoin(unitLabel){
|
||||
if (!unitLabel){
|
||||
return true
|
||||
}
|
||||
return ([null, "", "LBTC", "BTC", "tBTC", "tLBTC"].indexOf(unitLabel) > -1)
|
||||
}
|
||||
|
||||
// Calculates and formats the price as a span class="note"
|
||||
function formatPrice(valueInBTC, unitLabel, symbol, price){
|
||||
var formattedPrice = "";
|
||||
if (valueInBTC) {
|
||||
if(unitLabelIsBitcoin(unitLabel)){
|
||||
if (price && symbol) {
|
||||
formattedPrice = `<span class="note">(${symbol}${numberWithCommas((parseFloat(price) * valueInBTC).toFixed(2))})</span>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
return formattedPrice
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
|
@ -153,29 +153,6 @@
|
|||
if (isMine) {
|
||||
bgColor = '#925d07';
|
||||
}
|
||||
|
||||
|
||||
let value = "Confidential";
|
||||
let price = '';
|
||||
let assetlabel = "";
|
||||
if("assetlabel" in spentOutput){
|
||||
assetlabel = spentOutput.assetlabel;
|
||||
}
|
||||
if (spentOutput.value) {
|
||||
value = parseFloat(spentOutput.value.toFixed(8));
|
||||
if(assetlabel == "LBTC" || assetlabel == ""){
|
||||
if (this.price && this.symbol) {
|
||||
price = `<span class="note">(${this.symbol}${numberWithCommas((parseFloat(this.price) * value).toFixed(2))})</span>`;
|
||||
}
|
||||
|
||||
if (this.btcUnit == 'sat') {
|
||||
assetlabel = "sat";
|
||||
value = parseInt(value * 1e8);
|
||||
}
|
||||
}
|
||||
value = `${numberWithCommas(value.toString())}`;
|
||||
}
|
||||
|
||||
let labelAttr = "";
|
||||
if ("label" in spentOutput) {
|
||||
labelAttr = `data-label="${spentOutput.label}"`;
|
||||
|
|
@ -184,16 +161,21 @@
|
|||
if ("service_id" in spentOutput) {
|
||||
serviceIdAttr = `data-service-id="${spentOutput.service_id}"`;
|
||||
}
|
||||
// assetlabel only exists for Liquid, for BTC it is just null
|
||||
var amountAndUnit = formatBtcAmount(spentOutput.value, spentOutput.assetlabel, this.btcUnit == 'sat');
|
||||
var price = formatPrice(spentOutput.value, spentOutput.assetlabel, this.symbol, this.price);
|
||||
|
||||
addressAndValue = `<br>
|
||||
{{ _("Address:") }} <address-label
|
||||
addressAndValue = `
|
||||
{{ _("Address:") }}
|
||||
<address-label
|
||||
data-copy-hidden="true"
|
||||
data-address="${address}"
|
||||
data-wallet="${this.wallet}"
|
||||
${labelAttr}
|
||||
${serviceIdAttr}
|
||||
/><br>
|
||||
{{ _("Value:") }} ${value} ${assetlabel} ${price}`;
|
||||
${serviceIdAttr}>
|
||||
</address-label><br>
|
||||
{{ _("Value:") }} ${amountAndUnit} ${price}
|
||||
`;
|
||||
}
|
||||
|
||||
if ('coinbase' in rawtx.vin[i]) {
|
||||
|
|
@ -206,14 +188,28 @@
|
|||
`;
|
||||
continue;
|
||||
}
|
||||
rawtxHTML += `
|
||||
<p class="tx_info" style="text-align: left; background-color: ${bgColor};">
|
||||
<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}
|
||||
${addressAndValue}
|
||||
</p>
|
||||
`;
|
||||
if (jsonResponse.nonWalletTxId) {
|
||||
let nonWalletTxId = jsonResponse.nonWalletTxId ? `<span>Not known, this is a non-wallet txid.</span>` : null
|
||||
rawtxHTML += `
|
||||
<p class="tx_info" style="text-align: left; background-color: ${bgColor};">
|
||||
<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 index: ") }}${rawtx.vin[i].vout}<br>
|
||||
{{ _("Address & value:") }} ${nonWalletTxId}
|
||||
</p>
|
||||
`;
|
||||
}
|
||||
else {
|
||||
rawtxHTML += `
|
||||
<p class="tx_info" style="text-align: left; background-color: ${bgColor};">
|
||||
<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 index: ") }}${rawtx.vin[i].vout}<br>
|
||||
${addressAndValue}
|
||||
</p>
|
||||
`;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
rawtxHTML += `<h3>{{ _("Outputs") }}</h3>`;
|
||||
|
|
@ -229,26 +225,6 @@
|
|||
if (address == 'Unknown') {
|
||||
address = rawtx.vout[i].address ? rawtx.vout[i].address : 'Unknown';
|
||||
}
|
||||
let value = "Confidential";
|
||||
let price = '';
|
||||
let assetlabel = "";
|
||||
if("assetlabel" in rawtx.vout[i]){
|
||||
assetlabel = rawtx.vout[i].assetlabel;
|
||||
}
|
||||
if (rawtx.vout[i].value) {
|
||||
value = parseFloat(rawtx.vout[i].value.toFixed(8));
|
||||
if(assetlabel == "LBTC" || assetlabel == ""){
|
||||
if (this.price && this.symbol) {
|
||||
price = `<span class="note">(${this.symbol}${numberWithCommas((parseFloat(this.price) * value).toFixed(2))})</span>`;
|
||||
}
|
||||
|
||||
if (this.btcUnit == 'sat') {
|
||||
assetlabel = "sat";
|
||||
value = parseInt(value * 1e8)
|
||||
}
|
||||
}
|
||||
value = `${numberWithCommas(value.toString())}`;
|
||||
}
|
||||
|
||||
let bgColor = '#131a24';
|
||||
if ("index" in rawtx.vout[i]) {
|
||||
|
|
@ -266,18 +242,22 @@
|
|||
if ("service_id" in rawtx.vout[i]) {
|
||||
serviceIdAttr = `data-service-id="${rawtx.vout[i].service_id}"`;
|
||||
}
|
||||
// assetlabel only exists for Liquid, for BTC it is just null
|
||||
var amountAndUnit = formatBtcAmount(rawtx.vout[i].value, rawtx.vout[i].assetlabel, this.btcUnit == 'sat');
|
||||
var price = formatPrice(rawtx.vout[i].value, rawtx.vout[i].assetlabel, this.symbol, this.price);
|
||||
|
||||
rawtxHTML += `
|
||||
<p class="tx_info" style="text-align: left; background-color: ${bgColor};">
|
||||
<b>{{ _("Output #${i}") }}</b><br><br>
|
||||
{{ _("Address:") }} <address-label
|
||||
{{ _("Address:") }}
|
||||
<address-label
|
||||
data-copy-hidden="true"
|
||||
data-address="${address}"
|
||||
data-wallet="${this.wallet}"
|
||||
${labelAttr}
|
||||
${serviceIdAttr}
|
||||
/><br/>
|
||||
{{ _("Value:") }} ${value} ${assetlabel} ${price}
|
||||
${serviceIdAttr}>
|
||||
</address-label><br>
|
||||
{{ _("Value:") }} ${amountAndUnit} ${price}
|
||||
</p>
|
||||
`;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue