mirror of
https://github.com/janoside/btc-rpc-explorer.git
synced 2026-08-13 12:33:13 +02:00
lots of minor frontend/code cleanup:
-mixin for txList -fee/feeRate badge on tx lists (block, address, mempool browse) -change to single "net balance change" badge on address tx list -fix minor issues with sats value display -cleanup minor issue with "time ago" display tooltip -cleanup text coloring for various badge mixins -fix display of negative large values
This commit is contained in:
parent
6d0868e8c6
commit
e8eeb184e1
6 changed files with 475 additions and 391 deletions
|
|
@ -871,7 +871,7 @@ function formatLargeNumber(n, decimalPlaces) {
|
|||
let item = exponentScales[i];
|
||||
|
||||
let fraction = new Decimal(n / item.val);
|
||||
if (fraction >= 1) {
|
||||
if (Math.abs(fraction) >= 1) {
|
||||
return [fraction.toDP(decimalPlaces), item];
|
||||
}
|
||||
}
|
||||
|
|
@ -891,7 +891,7 @@ function formatLargeNumberSignificant(n, significantDigits) {
|
|||
let item = exponentScales[i];
|
||||
|
||||
let fraction = new Decimal(n / item.val);
|
||||
if (fraction >= 1) {
|
||||
if (Math.abs(fraction) >= 1) {
|
||||
return [fraction.toDP(Math.max(0, significantDigits - `${Math.floor(fraction)}`.length)), item];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,6 +159,11 @@ mixin txList(visibleTxs, txCount, limit, offset, inputsByTxid, options={})
|
|||
|
||||
- var tx_height_param = (!global.txindexAvailable && txBlockHeight) ? `@${txBlockHeight}` : '';
|
||||
|
||||
- var txInputs = inputsByTxid[tx.txid];
|
||||
- var blockHeight = txBlockHeight != undefined ? txBlockHeight : -1;
|
||||
- var totalIOValues = utils.getTxTotalInputOutputValues(tx, txInputs, blockHeight);
|
||||
|
||||
|
||||
.border.bg-content.p-3(class=(txIndex == 0 && txCount <= limit ? "rounded-top" : false), class=(txCount <= limit && txIndex == (visibleTxs.length - 1) ? "rounded-bottom" : false))
|
||||
if (tx && tx.txid)
|
||||
.clearfix
|
||||
|
|
@ -179,6 +184,7 @@ mixin txList(visibleTxs, txCount, limit, offset, inputsByTxid, options={})
|
|||
|
||||
|
||||
- var hasInputAddresses = false;
|
||||
- var coinbaseTx = false;
|
||||
if (tx && tx.vin && inputsByTxid && inputsByTxid[tx.txid])
|
||||
- var txInputs = inputsByTxid[tx.txid];
|
||||
each txVin, txVinIndex in tx.vin
|
||||
|
|
@ -190,6 +196,9 @@ mixin txList(visibleTxs, txCount, limit, offset, inputsByTxid, options={})
|
|||
if (voutAddresses.length > 0)
|
||||
- hasInputAddresses = true;
|
||||
|
||||
else
|
||||
- coinbaseTx = true;
|
||||
|
||||
if (hasInputAddresses)
|
||||
.float-end
|
||||
.d-block.d-sm-none
|
||||
|
|
@ -199,24 +208,80 @@ mixin txList(visibleTxs, txCount, limit, offset, inputsByTxid, options={})
|
|||
|
||||
.float-start.float-sm-end.mt-n2.mt-sm-0.mb-2.mb-sm-0
|
||||
.me-5.me-sm-n2
|
||||
- let txFee = null;
|
||||
- let txFeeRate = null;
|
||||
|
||||
if (options.mempoolDetailsByTxid && options.mempoolDetailsByTxid[tx.txid])
|
||||
- var mempoolDetails = options.mempoolDetailsByTxid[tx.txid].entry;
|
||||
- var mempoolDetailsFee = ((mempoolDetails.fees && mempoolDetails.fees.modified) ? mempoolDetails.fees.modified : (mempoolDetails.fee ? mempoolDetails.fee : 0));
|
||||
- var feeRate = new Decimal(mempoolDetailsFee).times(coinConfig.baseCurrencyUnit.multiplier).dividedBy(mempoolDetails.vsize);
|
||||
|
||||
+lightBadge
|
||||
| #{parseInt(feeRate).toLocaleString()}
|
||||
span.text-tiny.ms-tiny sat/vB
|
||||
- txFee = new Decimal(mempoolDetailsFee);
|
||||
- txFeeRate = txFee.times(coinConfig.baseCurrencyUnit.multiplier).dividedBy(mempoolDetails.vsize);
|
||||
|
||||
|
||||
if (!coinbaseTx && totalIOValues.input && totalIOValues.output)
|
||||
- txFee = new Decimal(totalIOValues.input).minus(totalIOValues.output);
|
||||
- txFeeRate = txFee.dividedBy(tx.vsize).times(coinConfig.baseCurrencyUnit.multiplier);
|
||||
|
||||
|
||||
if (txFee && txFee > 0)
|
||||
+infoBadge
|
||||
span.border-dotted.fw-bold.me-1(title="The miner fee (and fee rate) paid by this transaction. The fee equals the difference between the total input value and the total output value.", data-bs-toggle="tooltip") fee
|
||||
+_valueDisplaySat(txFee, 1000)
|
||||
|
||||
span.ms-2 (
|
||||
| #{parseInt(txFee.dividedBy(tx.vsize).times(coinConfig.baseCurrencyUnit.multiplier)).toLocaleString()}
|
||||
span.text-tiny.ms-1 sat/vB
|
||||
span )
|
||||
|
||||
else if (Object.keys(txInputs).length < tx.vin.length)
|
||||
+infoBadge
|
||||
span(data-bs-toggle="tooltip", title="Data truncated by performance settings. See transaction details for fee info.")
|
||||
span.fw-light …
|
||||
|
||||
|
||||
- let addrGain = null;
|
||||
- let addrLoss = null;
|
||||
|
||||
if (options.addrGainsByTxid && options.addrGainsByTxid[tx.txid])
|
||||
+successBadge
|
||||
span.me-tiny +
|
||||
+valueDisplay(options.addrGainsByTxid[tx.txid])
|
||||
- addrGain = new Decimal(options.addrGainsByTxid[tx.txid]);
|
||||
|
||||
if (false)
|
||||
+successBadge
|
||||
span +
|
||||
+valueDisplay(options.addrGainsByTxid[tx.txid])
|
||||
|
||||
if (options.addrLossesByTxid && options.addrLossesByTxid[tx.txid])
|
||||
span.badge.bg-danger.me-2
|
||||
span.me-tiny -
|
||||
+valueDisplay(options.addrLossesByTxid[tx.txid])
|
||||
- addrLoss = new Decimal(options.addrLossesByTxid[tx.txid]);
|
||||
|
||||
if (false)
|
||||
span.badge.bg-danger.me-2
|
||||
span -
|
||||
+valueDisplay(options.addrLossesByTxid[tx.txid])
|
||||
|
||||
- let addrDelta = null;
|
||||
|
||||
if (addrGain && addrLoss)
|
||||
- addrDelta = addrGain.minus(addrLoss);
|
||||
|
||||
else if (addrGain)
|
||||
- addrDelta = addrGain;
|
||||
|
||||
else if (addrLoss)
|
||||
- addrDelta = addrLoss.times(-1);
|
||||
|
||||
if (addrDelta)
|
||||
+darkBadge
|
||||
span.border-dotted.fw-bold.me-1(title="Net change to the balance of the current address caused by this transaction", data-bs-toggle="tooltip") net
|
||||
|
||||
if (addrDelta > 0)
|
||||
span.text-success
|
||||
span +
|
||||
+valueDisplay(addrDelta)
|
||||
else
|
||||
span.text-danger
|
||||
span -
|
||||
+valueDisplay(addrDelta.times(-1))
|
||||
|
||||
if (options.addrGainsByTxid && options.addrLossesByTxid && !options.addrGainsByTxid[tx.txid] && !options.addrLossesByTxid[tx.txid])
|
||||
span.badge.bg-danger.me-2(data-bs-toggle="tooltip", title="See transaction details for spent-from-this-address amount")
|
||||
|
|
@ -249,7 +314,7 @@ mixin txList(visibleTxs, txCount, limit, offset, inputsByTxid, options={})
|
|||
+darkBadge
|
||||
i.bi-clock.me-1
|
||||
|
||||
span.fw-light(title=titleStr, data-bs-toggle="tooltip")
|
||||
span.fw-light
|
||||
+timeAgo(tx.time, {oneElement:true})
|
||||
|
||||
|
||||
|
|
@ -258,14 +323,7 @@ mixin txList(visibleTxs, txCount, limit, offset, inputsByTxid, options={})
|
|||
.d-none.d-lg-block.border-end.mt-n4.mb-2(style="border-color: currentColor !important; height: 10px; width: 50%; opacity: 0.25;")
|
||||
|
||||
div
|
||||
- var txInputs = inputsByTxid[tx.txid];
|
||||
- var blockHeight = txBlockHeight != undefined ? txBlockHeight : -1;
|
||||
- options.maxTxOutputDisplayCount = maxTxOutputDisplayCount;
|
||||
|
||||
if (options.highlightAddress)
|
||||
- var txIOHighlightAddress = options.highlightAddress;
|
||||
|
||||
include ./transaction-io-details.pug
|
||||
+txIoDetails(tx, txInputs, totalIOValues, blockHeight, {highlightAddress:options.highlightAddress, maxTxOutputDisplayCount:maxTxOutputDisplayCount})
|
||||
|
||||
if (txIndex < (visibleTxs.length - 1) || txCount > limit)
|
||||
.pb-4.pb-md-3.bg-tx-separator
|
||||
|
|
@ -336,16 +394,17 @@ mixin _valueDisplayBtc(val, options={})
|
|||
|
||||
|
||||
mixin _valueDisplaySat(val, summarizeMin=Infinity, summarizeDecimals=3)
|
||||
- var parts = utils.formatCurrencyAmount(val, localCurrencyDisplay ? userSettings.localCurrency : userSettings.displayCurrency);
|
||||
- var localCurrencyDisplay = userSettings.displayCurrency == "local";
|
||||
- var parts = utils.formatCurrencyAmount(val, "sat");
|
||||
|
||||
//span #{JSON.stringify(parts)}
|
||||
|
||||
if (parts.intVal >= summarizeMin)
|
||||
if (Math.abs(parts.intVal) >= summarizeMin)
|
||||
//span #{JSON.stringify(parts)}
|
||||
- var largeNumberData = utils.formatLargeNumberSignificant(parts.intVal, summarizeDecimals >= 0 ? summarizeDecimals : 3);
|
||||
//span #{JSON.stringify(largeNumberData)} #{parts.intVal}
|
||||
span(title=parts.intVal.toLocaleString(), data-bs-toggle="tooltip") #{largeNumberData[0]}
|
||||
span.ms-1 #{largeNumberData[1].textDesc}
|
||||
span #{largeNumberData[1].abbreviation}
|
||||
|
||||
else
|
||||
span(class=(localCurrencyDisplay ? "border-dotted" : false), title=(localCurrencyDisplay ? `${utils.formatCurrencyAmount(val, coinConfig.defaultCurrencyUnit.name.toLowerCase()).simpleVal} BTC` : false), data-bs-toggle=(localCurrencyDisplay ? "tooltip" : false)) #{parts.intVal.toLocaleString()}
|
||||
|
|
@ -368,7 +427,7 @@ mixin _valueDisplayLocal(val, summarizeMin=Infinity, summarizeDecimals=3)
|
|||
//span #{JSON.stringify(parts)}
|
||||
span.fw-light.me-tiny #{global.currencySymbols[userSettings.localCurrency]}
|
||||
|
||||
if (parts.intVal >= summarizeMin)
|
||||
if (Math.abs(parts.intVal) >= summarizeMin)
|
||||
- var largeNumberData = utils.formatLargeNumberSignificant(parts.intVal, summarizeDecimals >= 0 ? summarizeDecimals : 3);
|
||||
//span #{JSON.stringify(largeNumberData)} #{parts.intVal}
|
||||
span.border-dotted(title=`${global.currencySymbols[userSettings.localCurrency]}${parts.intVal.toLocaleString()}<br/>${utils.formatCurrencyAmount(val, coinConfig.defaultCurrencyUnit.name.toLowerCase()).simpleVal} BTC`, data-bs-toggle="tooltip", data-bs-html="true")
|
||||
|
|
@ -441,8 +500,13 @@ mixin confirmations(confirmations, abbreviated=true)
|
|||
|
||||
|
||||
|
||||
mixin bodyBgBadge(text)
|
||||
span.small.badge.bg-body.border.border-card-highlight-badge.text-reset.mb-tiny.me-1 #{text ? text : ""}
|
||||
if (block)
|
||||
block
|
||||
|
||||
mixin cardHighlightBadge(text)
|
||||
span.small.badge.bg-card-highlight-badge.border.border-card-highlight-badge.text-reset.mb-tiny.me-1 #{text ? text : ""}
|
||||
span.small.badge.card-highlight.border.border-card-highlight-badge.text-reset.mb-tiny.me-1 #{text ? text : ""}
|
||||
if (block)
|
||||
block
|
||||
|
||||
|
|
@ -454,7 +518,7 @@ mixin hexDataDisplay(hex, order="utf8,ascii,hex")
|
|||
|
||||
.d-flex.flex-row
|
||||
.d-inline-block.small.border.rounded-1.p-1.px-2.card-highlight.word-wrap
|
||||
+cardHighlightBadge(items[0])
|
||||
+bodyBgBadge(items[0])
|
||||
span.text-tiny.d-inline.d-sm-none #{utils.formatHex(hex, items[0])}
|
||||
span.small.d-none.d-sm-inline #{utils.formatHex(hex, items[0])}
|
||||
|
||||
|
|
@ -468,7 +532,7 @@ mixin hexDataDisplay(hex, order="utf8,ascii,hex")
|
|||
if (itemIndex > 1)
|
||||
br
|
||||
|
||||
+cardHighlightBadge(item)
|
||||
+bodyBgBadge(item)
|
||||
|
||||
span.text-tiny.d-inline.d-sm-none #{utils.formatHex(hex, item)}
|
||||
span.small.d-none.d-sm-inline #{utils.formatHex(hex, item)}
|
||||
|
|
@ -566,7 +630,8 @@ mixin timeAgo(timeAgoTime, options={oneElement:false, agoText:true})
|
|||
if (options && "hideHoverText" in options)
|
||||
- hideHoverText = options.hideHoverText;
|
||||
|
||||
- let timeAgo = moment.duration(moment.utc(new Date()).diff(moment.utc(new Date(parseInt(timeAgoTime) * 1000))));
|
||||
- let utcMoment = moment.utc(new Date(parseInt(timeAgoTime) * 1000));
|
||||
- let timeAgo = moment.duration(moment.utc(new Date()).diff(utcMoment));
|
||||
- let future = false;
|
||||
|
||||
if (timeAgo.asSeconds() < 0)
|
||||
|
|
@ -596,7 +661,7 @@ mixin timeAgo(timeAgoTime, options={oneElement:false, agoText:true})
|
|||
if (hideHoverText)
|
||||
span #{utils.summarizeDuration(timeAgo, options)}
|
||||
else
|
||||
span.border-dotted(title=utils.summarizeDuration(timeAgo), data-bs-toggle="tooltip") #{utils.summarizeDuration(timeAgo, options)}
|
||||
span.border-dotted(title=`${utils.summarizeDuration(timeAgo)}<br>${utcMoment.format("Y-MM-DD HH:mm:ss")} utc`, data-bs-toggle="tooltip", data-bs-html="true") #{utils.summarizeDuration(timeAgo, options)}
|
||||
else
|
||||
span #{utils.summarizeDuration(timeAgo, options)}
|
||||
|
||||
|
|
@ -606,25 +671,35 @@ mixin timeAgo(timeAgoTime, options={oneElement:false, agoText:true})
|
|||
|
||||
|
||||
mixin darkBadge(text)
|
||||
span.badge.bg-dark.border.border-dark.me-2 #{text ? text : ""}
|
||||
span.badge.text-bg-dark.border.border-dark.me-2 #{text ? text : ""}
|
||||
if (block)
|
||||
block
|
||||
|
||||
|
||||
mixin lightBadge(text)
|
||||
span.badge.bg-light.text-dark.border.me-2 #{text ? text : ""}
|
||||
span.badge.text-bg-light.text-dark.border.me-2 #{text ? text : ""}
|
||||
if (block)
|
||||
block
|
||||
|
||||
|
||||
mixin successBadge(text)
|
||||
span.badge.bg-success.me-2 #{text ? text : ""}
|
||||
span.badge.text-bg-success.me-2 #{text ? text : ""}
|
||||
if (block)
|
||||
block
|
||||
|
||||
|
||||
mixin primaryBadge(text, endMargin=true)
|
||||
span.badge.bg-primary(class=(endMargin ? "me-2" : false)) #{text ? text : ""}
|
||||
span.badge.text-bg-primary(class=(endMargin ? "me-2" : false)) #{text ? text : ""}
|
||||
if (block)
|
||||
block
|
||||
|
||||
mixin secondaryBadge(text, endMargin=true)
|
||||
span.badge.text-bg-secondary(class=(endMargin ? "me-2" : false)) #{text ? text : ""}
|
||||
if (block)
|
||||
block
|
||||
|
||||
mixin infoBadge(text, endMargin=true)
|
||||
span.badge.text-bg-info(class=(endMargin ? "me-2" : false)) #{text ? text : ""}
|
||||
if (block)
|
||||
block
|
||||
|
||||
|
|
|
|||
|
|
@ -1,356 +0,0 @@
|
|||
- var totalIOValues = utils.getTxTotalInputOutputValues(tx, txInputs, blockHeight);
|
||||
|
||||
|
||||
|
||||
mixin inputValueDisplay(tx, txVin, vout)
|
||||
if (txVin.coinbase)
|
||||
span.border-dotted.me-1(title="This is the <b>block subsidy</b> - newly created coins awarded (automatically, by the network protocol) to the miner that found this block.", data-bs-toggle="tooltip", data-bs-html="true")
|
||||
i.bi-asterisk.text-success
|
||||
|
||||
span(class=(tx.vin.length == 1 ? "fw-bold" : false))
|
||||
- var currencyValue = coinConfig.blockRewardFunction(blockHeight, activeBlockchain);
|
||||
+valueDisplay(currencyValue)
|
||||
|
||||
else
|
||||
if (vout && vout.value)
|
||||
span(class=(tx.vin.length == 1 ? "fw-bold" : "fw-light"))
|
||||
+valueDisplay(vout.value)
|
||||
|
||||
else if (!global.txindexAvailable)
|
||||
span(title="This data is unavailable. Your node must have its transaction index (txindex) setting enabled to view it.", data-bs-toggle="tooltip")
|
||||
i.bi-backspace.text-danger
|
||||
|
||||
|
||||
mixin outputValueDisplay(tx, vout, voutIndex)
|
||||
if (vout.value > 0 && vout.scriptPubKey.asm.startsWith('OP_RETURN '))
|
||||
span(title="Burned output - as an OP_RETURN output, this value is provably unspendable." data-bs-toggle="tooltip")
|
||||
i.bi-fire.text-danger.me-2
|
||||
|
||||
if (vout.value > 0)
|
||||
span(class=(nonZeroVoutValueCount == 1 ? "fw-bold" : "fw-light"))
|
||||
+valueDisplay(vout.value)
|
||||
|
||||
if (!vout.scriptPubKey.asm.startsWith('OP_RETURN '))
|
||||
if (utxos)
|
||||
if (utxos[voutIndex])
|
||||
span(title="This output remains unspent (a valid UTXO)." data-bs-toggle="tooltip")
|
||||
i.bi-check-circle.text-success.ms-2
|
||||
|
||||
else if (utxos[voutIndex] == null)
|
||||
if (tx.txid == "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")
|
||||
span(title="This output is UNSPENDABLE, and therefore these coins do not exist!" data-bs-toggle="tooltip")
|
||||
i.bi-flag.text-warning.ms-2
|
||||
|
||||
else
|
||||
span(title="This output has been spent (destroyed)." data-bs-toggle="tooltip")
|
||||
i.bi-x-circle.text-danger.ms-2
|
||||
|
||||
|
||||
.row
|
||||
.col-lg-6(class=(tx.vin.length >= tx.vout.length ? "border-lg-end" : false))
|
||||
if (txInputs || !global.txindexAvailable)
|
||||
- var extraInputCount = 0;
|
||||
each txVin, txVinIndex in tx.vin
|
||||
if (!txVin.coinbase)
|
||||
- var vout = null;
|
||||
if (txInputs && txInputs[txVinIndex])
|
||||
- var txInput = txInputs[txVinIndex];
|
||||
- var vout = txInput;
|
||||
|
||||
else if (!global.txindexAvailable)
|
||||
- var txInput = {txid:txVin.txid, vout:txVin.vout};
|
||||
- var vout = {};
|
||||
|
||||
if (txVin.coinbase || vout || !global.txindexAvailable)
|
||||
.clearfix
|
||||
a.sz-xs-hidden.d-none.d-sm-inline.badge.fw-normal.card-highlight.border.text-decoration-none.me-2(data-bs-toggle="tooltip", title=`Input #${txVinIndex.toLocaleString()}`, style="white-space: nowrap;")
|
||||
i.d-inline.bi-arrow-right.text-danger
|
||||
|
||||
span.d-none.d-sm-inline.font-monospace.ms-1 #{txVinIndex.toLocaleString()}
|
||||
|
||||
a.sz-xs-only.d-inline.d-sm-none.text-decoration-none.me-1(data-bs-toggle="tooltip", title=`Input #${txVinIndex.toLocaleString()}`, style="white-space: nowrap;")
|
||||
i.d-inline.bi-arrow-right.text-danger
|
||||
|
||||
|
||||
if (vout && vout.scriptPubKey && vout.scriptPubKey.type)
|
||||
span.d-none.d-sm-inline(title=`Input Type: ${utils.outputTypeName(vout.scriptPubKey.type)}`, data-bs-toggle="tooltip")
|
||||
+darkBadge(utils.outputTypeAbbreviation(vout.scriptPubKey.type))
|
||||
|
||||
if (vout && vout.coinbaseSpend)
|
||||
span.d-none.d-sm-inline
|
||||
+successBadge
|
||||
span(title=`This input spends a coinbase output (mining reward), meaning that this represents the first time these coins have been spent.`, data-bs-toggle="tooltip") 1<sup>st</sup> spend
|
||||
|
||||
span.ms-1.float-end
|
||||
+inputValueDisplay(tx, txVin, vout)
|
||||
|
||||
|
||||
if (txVin.coinbase)
|
||||
+successBadge
|
||||
span(title="Coinbase transactions are special transactions created by the miner of a block. They distribute the block reward (subsidy) as the miner chooses, along with all of the fees paid by transactions included in the block.", data-bs-toggle="tooltip") coinbase
|
||||
|
||||
.mt-2
|
||||
+hexDataDisplay(txVin.coinbase)
|
||||
|
||||
|
||||
else
|
||||
span.word-wrap
|
||||
if (vout.utxoTime)
|
||||
- var deltaT = tx.time - vout.utxoTime
|
||||
- var deltaTYears = deltaT / 60 / 60 / 24 / 365
|
||||
|
||||
if (deltaTYears > 5)
|
||||
span.me-2.d-none.d-sm-inline(title=`This UTXO was very old! It existed for ${parseInt(deltaTYears)}+ years - from ${moment.utc(new Date(vout.utxoTime * 1000)).format('MMM D, Y')} until ${moment.utc(new Date(tx.time * 1000)).format('MMM D, Y')} - before being spent (destroyed) in this transaction!`, data-bs-toggle="tooltip")
|
||||
+funItemIcon
|
||||
|
||||
|
||||
span.mt-1
|
||||
a.sz-xl-plus.d-none.d-xl-inline(href=`./tx/${txInput.txid}#output-${txVin.vout}`) #{utils.ellipsizeMiddle(txInput.txid, 22)}
|
||||
span.text-muted ##{txVin.vout}
|
||||
|
||||
a.sz-md-lg.d-none.d-md-inline.d-xl-none(href=`./tx/${txInput.txid}#output-${txVin.vout}`) #{utils.ellipsizeMiddle(txInput.txid, 14)}
|
||||
span.text-muted ##{txVin.vout}
|
||||
|
||||
a.sz-xs-sm.small.d-inline.d-md-none(href=`./tx/${txInput.txid}#output-${txVin.vout}`) #{utils.ellipsizeMiddle(txInput.txid, 14)}
|
||||
span.text-muted ##{txVin.vout}
|
||||
|
||||
if (vout && vout.scriptPubKey)
|
||||
- var voutAddresses = utils.getVoutAddresses(vout);
|
||||
|
||||
if (voutAddresses.length > 0)
|
||||
.word-wrap.mt-2.d-none.d-sm-block
|
||||
a.sz-md-plus.d-none.d-md-inline(href=`./address/${voutAddresses[0]}`, class=(txIOHighlightAddress == voutAddresses[0] ? "text-info" : null)) #{utils.ellipsizeMiddle(voutAddresses[0], 44)}
|
||||
a.sz-xs-sm.small.d-inline.d-md-none(href=`./address/${voutAddresses[0]}`, class=(txIOHighlightAddress == voutAddresses[0] ? "text-info" : null)) #{utils.ellipsizeMiddle(voutAddresses[0], 24)}
|
||||
|
||||
|
||||
if (txIOHighlightAddress == voutAddresses[0])
|
||||
span(title="Current address", data-bs-toggle="tooltip")
|
||||
i.bi-arrow-left.text-warning.ms-1.text-info
|
||||
|
||||
if (global.specialAddresses[voutAddresses[0]])
|
||||
- var specialAddressInfo = global.specialAddresses[voutAddresses[0]];
|
||||
if (specialAddressInfo.type == "minerPayout")
|
||||
span
|
||||
a.d-none.d-sm-inline(data-bs-toggle="tooltip", title=`Miner payout address: ${specialAddressInfo.minerInfo.name}`)
|
||||
+funItemIcon
|
||||
|
||||
.d-block.d-sm-none
|
||||
div(class=`tx-input-address-${tx.txid}`, style="display: none;")
|
||||
a.sz-xs-sm.small(href=`./address/${voutAddresses[0]}`, class=(txIOHighlightAddress == voutAddresses[0] ? "text-info" : null)) #{utils.ellipsizeMiddle(voutAddresses[0], 24)}
|
||||
|
||||
if (txIOHighlightAddress == voutAddresses[0])
|
||||
span(title="Current address", data-bs-toggle="tooltip")
|
||||
i.bi-arrow-left.text-warning.ms-1.text-info
|
||||
|
||||
if (tx.vin.length > 1 || txVinIndex > 0)
|
||||
hr.mb-1
|
||||
|
||||
if (false)
|
||||
small
|
||||
span.border-dotted(title="Transaction output", data-bs-toggle="tooltip") txo
|
||||
span.me-1 :
|
||||
a(href=`./tx/${txInput.txid}#output-${txVin.vout}`) #{utils.ellipsize(txInput.txid, 20)}[#{txVin.vout}]
|
||||
|
||||
else
|
||||
|
||||
|
||||
if (tx.vin.length > 1)
|
||||
hr.d-none.d-sm-block
|
||||
|
||||
else
|
||||
- extraInputCount = extraInputCount + 1;
|
||||
|
||||
if (extraInputCount > 0)
|
||||
.clearfix.mb-sm-2
|
||||
a.sz-md-plus.d-none.d-sm-inline.badge.fw-normal.card-highlight.border.text-decoration-none(data-bs-toggle="tooltip", title=`Input #${(tx.vin.length - extraInputCount + 1).toLocaleString()} - ${tx.vin.length.toLocaleString()}`, style="white-space: nowrap;")
|
||||
i.bi-arrow-right.text-danger.me-sm-2
|
||||
span.d-none.d-sm-inline …
|
||||
|
||||
a.sz-xs-only.d-inline.d-sm-none.text-decoration-none.me-1(data-bs-toggle="tooltip", title=`Input #${(tx.vin.length - extraInputCount + 1).toLocaleString()} - ${tx.vin.length.toLocaleString()}`, style="white-space: nowrap;")
|
||||
i.d-inline.bi-arrow-right.text-danger
|
||||
|
||||
small.text-muted.border-dotted.ms-0.ms-sm-2(data-bs-toggle="tooltip", title="The details for the remaining inputs were truncated for performance purposes. Click through to the transaction details to see all inputs.") (#{extraInputCount.toLocaleString()} truncated)
|
||||
|
||||
.float-end
|
||||
- var currencyValue = new Decimal(totalIOValues.output).minus(new Decimal(totalIOValues.input));
|
||||
span.border-dotted.me-1(title="The total amounts for other inputs are approximately equal to this value, plus the mining fee paid.", data-bs-toggle="tooltip") ~+
|
||||
+valueDisplay(currencyValue)
|
||||
|
||||
hr.d-none.d-sm-block
|
||||
|
||||
if (totalIOValues.input && totalIOValues.input > 0 && tx.vin.length > 1)
|
||||
.row.mb-0.mb-md-0
|
||||
.col
|
||||
.text-end.mt-1.mt-sm-n1
|
||||
if (totalIOValues.input > 0 && extraInputCount == 0)
|
||||
i.d-inline.d-lg-none.bi-arrow-right.text-danger.me-2
|
||||
span.fw-bold
|
||||
+valueDisplay(totalIOValues.input)
|
||||
|
||||
else if (extraInputCount > 0)
|
||||
i.d-inline.d-lg-none.bi-arrow-right.text-danger.me-2
|
||||
span.border-dotted.me-1(title="The total input amount for this transaction is approximately equal to this value, plus the mining fee paid.", data-bs-toggle="tooltip") ~+
|
||||
span.fw-bold
|
||||
+valueDisplay(totalIOValues.output)
|
||||
|
||||
|
||||
|
||||
.d-xs-block.d-sm-none
|
||||
.my-3
|
||||
hr
|
||||
|
||||
if (tx.vin.length == 1)
|
||||
.d-none.d-sm-block.d-md-block.d-lg-none
|
||||
.my-4
|
||||
hr
|
||||
|
||||
else
|
||||
.d-none.d-sm-block.d-lg-none
|
||||
.mb-4
|
||||
|
|
||||
|
||||
.col-lg-6(class=(tx.vout.length > tx.vin.length ? "border-lg-start" : false))
|
||||
- var maxRegularRowCount = maxTxOutputDisplayCount || options.maxTxOutputDisplayCount || 15;
|
||||
- var regularRowCount = 0;
|
||||
- var hiddenRowCount = 0;
|
||||
- var nonZeroVoutValueCount = tx.vout.filter(vout => { return vout.value > 0; }).length;
|
||||
|
||||
each vout, voutIndex in tx.vout
|
||||
- var voutAddresses = utils.getVoutAddresses(vout);
|
||||
|
||||
- var highlightRow = false;
|
||||
if (txIOHighlightAddress != null && voutAddresses.length > 0 && voutAddresses[0] == txIOHighlightAddress)
|
||||
- highlightRow = true;
|
||||
|
||||
if (!highlightRow)
|
||||
- regularRowCount++;
|
||||
|
||||
- var hiddenRow = false;
|
||||
if (!highlightRow && regularRowCount > maxRegularRowCount)
|
||||
- hiddenRow = true;
|
||||
- hiddenRowCount++;
|
||||
|
||||
div(data-txid=tx.txid, class=(hiddenRow ? "d-none" : ""))
|
||||
.clearfix.mb-0.mb-sm-2.mb-md-3
|
||||
a.xs-hidden.d-none.d-sm-inline.badge.card-highlight.border.text-decoration-none.fw-normal.me-2(data-bs-toggle="tooltip", title=`Output #${voutIndex.toLocaleString()}`, style="white-space: nowrap;")
|
||||
i.d-inline.bi-arrow-right.text-success
|
||||
|
||||
span.d-none.d-sm-inline.font-monospace.ms-1 #{voutIndex.toLocaleString()}
|
||||
|
||||
a.xs-only.d-inline.d-sm-none.text-decoration-none.fw-normal.me-1(data-bs-toggle="tooltip", title=`Output #${voutIndex.toLocaleString()}`, style="white-space: nowrap;")
|
||||
i.d-inline.bi-arrow-right.text-success
|
||||
|
||||
if (vout && vout.scriptPubKey)
|
||||
if (vout.scriptPubKey.hex && vout.scriptPubKey.hex.startsWith('6a24aa21a9ed'))
|
||||
span
|
||||
+primaryBadge("OP_RETURN")
|
||||
|
||||
a(href="https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#commitment-structure", data-bs-toggle="tooltip", title="Read about the SegWit Commitment", target="_blank")
|
||||
+darkBadge
|
||||
span.small SegWit
|
||||
i.bi-box-arrow-up-right.ms-1
|
||||
|
||||
.my-2
|
||||
+hexDataDisplay(vout.scriptPubKey.asm.substring("OP_RETURN ".length))
|
||||
|
||||
else if (vout.scriptPubKey.asm && vout.scriptPubKey.asm.startsWith('OP_RETURN '))
|
||||
span
|
||||
+primaryBadge("OP_RETURN")
|
||||
|
||||
.my-2
|
||||
+hexDataDisplay(vout.scriptPubKey.asm.substring("OP_RETURN ".length))
|
||||
|
||||
else if (vout.scriptPubKey.type)
|
||||
span.d-none.d-sm-inline
|
||||
+darkBadge
|
||||
span(title=`Output Type: ${utils.outputTypeName(vout.scriptPubKey.type)}`, data-bs-toggle="tooltip") #{utils.outputTypeAbbreviation(vout.scriptPubKey.type)}
|
||||
|
||||
|
||||
|
||||
if (voutAddresses.length == 0)
|
||||
// xs display only, output type when we have no address (e.g. op_return)
|
||||
|
||||
if (vout.scriptPubKey.asm && vout.scriptPubKey.asm.startsWith('OP_RETURN '))
|
||||
if (false)
|
||||
span.small.xs-only.d-inline.d-sm-none
|
||||
+primaryBadge("OP_RETURN")
|
||||
|
||||
.xs-sm.d-inline-block.d-md-none.small.border.rounded-1.px-1.card-highlight.mt-1
|
||||
- var asm = vout.scriptPubKey.asm.substring("OP_RETURN ".length);
|
||||
span.text-tiny.fw-light #{utils.formatHex(asm, "utf8")}
|
||||
|
||||
else if (vout.scriptPubKey.type)
|
||||
span.small.xs-only.d-inline.d-sm-none
|
||||
+darkBadge
|
||||
span(title=`Output Type: ${utils.outputTypeName(vout.scriptPubKey.type)}`, data-bs-toggle="tooltip") #{utils.outputTypeAbbreviation(vout.scriptPubKey.type)}
|
||||
|
||||
|
||||
span.ms-2.float-end
|
||||
+outputValueDisplay(tx, vout, voutIndex)
|
||||
|
||||
if (vout && vout.scriptPubKey.asm && !vout.scriptPubKey.asm.startsWith("OP_RETURN "))
|
||||
if (voutAddresses.length == 0)
|
||||
.my-2
|
||||
+hexDataDisplay(vout.scriptPubKey.hex)
|
||||
|
||||
|
||||
if (voutAddresses.length > 0)
|
||||
.d-inline.d-lg-block.mt-lg-2
|
||||
each addr in voutAddresses
|
||||
a.sz-lg-plus.d-none.d-lg-inline(id=`output-${voutIndex}`, href=`./address/${addr}`)
|
||||
span(class=(highlightRow ? "text-info" : null)) #{utils.ellipsizeMiddle(addr, 44)}
|
||||
|
||||
a.sz-md.d-none.d-md-inline.d-lg-none(id=`output-${voutIndex}`, href=`./address/${addr}`)
|
||||
span(class=(highlightRow ? "text-info" : null)) #{utils.ellipsizeMiddle(addr, 24)}
|
||||
|
||||
a.sz-xs-sm.d-inline.d-md-none(id=`output-${voutIndex}`, href=`./address/${addr}`)
|
||||
span.small(class=(highlightRow ? "text-info" : null)) #{utils.ellipsizeMiddle(addr, 18)}
|
||||
|
||||
if (highlightRow)
|
||||
span(title="Current address", data-bs-toggle="tooltip")
|
||||
i.bi-arrow-left.ms-1.text-warning
|
||||
|
||||
if (global.specialAddresses[addr])
|
||||
- var specialAddressInfo = global.specialAddresses[addr];
|
||||
if (specialAddressInfo.type == "minerPayout")
|
||||
span
|
||||
a.d-none.d-sm-inline(data-bs-toggle="tooltip", title=`Miner payout address: ${specialAddressInfo.minerInfo.name}`)
|
||||
+funItemIcon
|
||||
|
||||
.d-none.d-sm-block.mb-2
|
||||
|
||||
|
||||
|
||||
if (vout.scriptPubKey)
|
||||
if (voutAddresses.length > 0)
|
||||
|
||||
|
||||
else if (false)
|
||||
.mb-tiny
|
||||
span(title=`Output Type: ${utils.outputTypeName(vout.scriptPubKey.type)}`, data-bs-toggle="tooltip")
|
||||
+darkBadge(utils.outputTypeAbbreviation(vout.scriptPubKey.type))
|
||||
|
||||
+hexDataDisplay(vout.scriptPubKey.asm)
|
||||
|
||||
|
||||
if (voutIndex < (tx.vout.length - 1) || nonZeroVoutValueCount > 1)
|
||||
hr.d-none.d-md-block
|
||||
|
||||
else
|
||||
.mb-0
|
||||
|
||||
if (hiddenRowCount > 0)
|
||||
a.small(href="javascript:void(0)", onclick=("showAllTxOutputs(this, '" + tx.txid + "');"))
|
||||
i.bi-plus-square.text-card-highlight.me-1
|
||||
| Show remaining #{hiddenRowCount.toLocaleString()} outputs
|
||||
|
||||
if (nonZeroVoutValueCount > 1)
|
||||
.row.mb-0.mb-lg-0
|
||||
.col
|
||||
.text-end.mt-1.mt-sm-n1(style=(utxos ? "margin-right: 1.39rem !important;" : false))
|
||||
span.fw-bold
|
||||
i.d-inline.d-lg-none.bi-arrow-right.text-success.me-2
|
||||
+valueDisplay(totalIOValues.output)
|
||||
|
||||
|
||||
|
||||
362
views/includes/tx-mixins.pug
Normal file
362
views/includes/tx-mixins.pug
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
|
||||
|
||||
mixin inputValueDisplay(tx, txVin, vout)
|
||||
if (txVin.coinbase)
|
||||
span.border-dotted.me-1(title="This is the <b>block subsidy</b> - newly created coins awarded (automatically, by the network protocol) to the miner that found this block.", data-bs-toggle="tooltip", data-bs-html="true")
|
||||
i.bi-asterisk.text-success
|
||||
|
||||
span(class=(tx.vin.length == 1 ? "fw-bold" : false))
|
||||
- var currencyValue = coinConfig.blockRewardFunction(blockHeight, activeBlockchain);
|
||||
+valueDisplay(currencyValue)
|
||||
|
||||
else
|
||||
if (vout && vout.value)
|
||||
span(class=(tx.vin.length == 1 ? "fw-bold" : "fw-light"))
|
||||
+valueDisplay(vout.value)
|
||||
|
||||
else if (!global.txindexAvailable)
|
||||
span(title="This data is unavailable. Your node must have its transaction index (txindex) setting enabled to view it.", data-bs-toggle="tooltip")
|
||||
i.bi-backspace.text-danger
|
||||
|
||||
|
||||
mixin outputValueDisplay(tx, vout, voutIndex, nonZeroVoutValueCount)
|
||||
if (vout.value > 0 && vout.scriptPubKey.asm.startsWith('OP_RETURN '))
|
||||
span(title="Burned output - as an OP_RETURN output, this value is provably unspendable." data-bs-toggle="tooltip")
|
||||
i.bi-fire.text-danger.me-2
|
||||
|
||||
if (vout.value > 0)
|
||||
span(class=(nonZeroVoutValueCount == 1 ? "fw-bold" : "fw-light"))
|
||||
+valueDisplay(vout.value)
|
||||
|
||||
if (!vout.scriptPubKey.asm.startsWith('OP_RETURN '))
|
||||
if (utxos)
|
||||
if (utxos[voutIndex])
|
||||
span(title="This output remains unspent (a valid UTXO)." data-bs-toggle="tooltip")
|
||||
i.bi-check-circle.text-success.ms-2
|
||||
|
||||
else if (utxos[voutIndex] == null)
|
||||
if (tx.txid == "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")
|
||||
span(title="This output is UNSPENDABLE, and therefore these coins do not exist!" data-bs-toggle="tooltip")
|
||||
i.bi-flag.text-warning.ms-2
|
||||
|
||||
else
|
||||
span(title="This output has been spent (destroyed)." data-bs-toggle="tooltip")
|
||||
i.bi-x-circle.text-danger.ms-2
|
||||
|
||||
|
||||
|
||||
mixin txIoDetails(tx, txInputs, totalIOValues, blockHeight, options={})
|
||||
if (options.highlightAddress)
|
||||
- txIOHighlightAddress = options.highlightAddress
|
||||
|
||||
if (options.maxTxOutputDisplayCount)
|
||||
- maxTxOutputDisplayCount = options.maxTxOutputDisplayCount
|
||||
|
||||
.row
|
||||
.col-lg-6(class=(tx.vin.length >= tx.vout.length ? "border-lg-end" : false))
|
||||
if (txInputs || !global.txindexAvailable)
|
||||
- var extraInputCount = 0;
|
||||
each txVin, txVinIndex in tx.vin
|
||||
if (!txVin.coinbase)
|
||||
- var vout = null;
|
||||
if (txInputs && txInputs[txVinIndex])
|
||||
- var txInput = txInputs[txVinIndex];
|
||||
- var vout = txInput;
|
||||
|
||||
else if (!global.txindexAvailable)
|
||||
- var txInput = {txid:txVin.txid, vout:txVin.vout};
|
||||
- var vout = {};
|
||||
|
||||
if (txVin.coinbase || vout || !global.txindexAvailable)
|
||||
.clearfix
|
||||
a.sz-xs-hidden.d-none.d-sm-inline.badge.fw-normal.card-highlight.border.text-decoration-none.me-2(data-bs-toggle="tooltip", title=`Input #${txVinIndex.toLocaleString()}`, style="white-space: nowrap;")
|
||||
i.d-inline.bi-arrow-right.text-danger
|
||||
|
||||
span.d-none.d-sm-inline.font-monospace.ms-1 #{txVinIndex.toLocaleString()}
|
||||
|
||||
a.sz-xs-only.d-inline.d-sm-none.text-decoration-none.me-1(data-bs-toggle="tooltip", title=`Input #${txVinIndex.toLocaleString()}`, style="white-space: nowrap;")
|
||||
i.d-inline.bi-arrow-right.text-danger
|
||||
|
||||
|
||||
if (vout && vout.scriptPubKey && vout.scriptPubKey.type)
|
||||
span.d-none.d-sm-inline(title=`Input Type: ${utils.outputTypeName(vout.scriptPubKey.type)}`, data-bs-toggle="tooltip")
|
||||
+darkBadge(utils.outputTypeAbbreviation(vout.scriptPubKey.type))
|
||||
|
||||
if (vout && vout.coinbaseSpend)
|
||||
span.d-none.d-sm-inline
|
||||
+successBadge
|
||||
span(title=`This input spends a coinbase output (mining reward), meaning that this represents the first time these coins have been spent.`, data-bs-toggle="tooltip") 1<sup>st</sup> spend
|
||||
|
||||
span.ms-1.float-end
|
||||
+inputValueDisplay(tx, txVin, vout)
|
||||
|
||||
|
||||
if (txVin.coinbase)
|
||||
+successBadge
|
||||
span(title="Coinbase transactions are special transactions created by the miner of a block. They distribute the block reward (subsidy) as the miner chooses, along with all of the fees paid by transactions included in the block.", data-bs-toggle="tooltip") coinbase
|
||||
|
||||
.mt-2
|
||||
+hexDataDisplay(txVin.coinbase)
|
||||
|
||||
|
||||
else
|
||||
span.word-wrap
|
||||
if (vout.utxoTime)
|
||||
- var deltaT = tx.time - vout.utxoTime
|
||||
- var deltaTYears = deltaT / 60 / 60 / 24 / 365
|
||||
|
||||
if (deltaTYears > 5)
|
||||
span.me-2.d-none.d-sm-inline(title=`This UTXO was very old! It existed for ${parseInt(deltaTYears)}+ years - from ${moment.utc(new Date(vout.utxoTime * 1000)).format('MMM D, Y')} until ${moment.utc(new Date(tx.time * 1000)).format('MMM D, Y')} - before being spent (destroyed) in this transaction!`, data-bs-toggle="tooltip")
|
||||
+funItemIcon
|
||||
|
||||
|
||||
span.mt-1
|
||||
a.sz-xl-plus.d-none.d-xl-inline(href=`./tx/${txInput.txid}#output-${txVin.vout}`) #{utils.ellipsizeMiddle(txInput.txid, 22)}
|
||||
span.text-muted ##{txVin.vout}
|
||||
|
||||
a.sz-md-lg.d-none.d-md-inline.d-xl-none(href=`./tx/${txInput.txid}#output-${txVin.vout}`) #{utils.ellipsizeMiddle(txInput.txid, 14)}
|
||||
span.text-muted ##{txVin.vout}
|
||||
|
||||
a.sz-xs-sm.small.d-inline.d-md-none(href=`./tx/${txInput.txid}#output-${txVin.vout}`) #{utils.ellipsizeMiddle(txInput.txid, 14)}
|
||||
span.text-muted ##{txVin.vout}
|
||||
|
||||
if (vout && vout.scriptPubKey)
|
||||
- var voutAddresses = utils.getVoutAddresses(vout);
|
||||
|
||||
if (voutAddresses.length > 0)
|
||||
.word-wrap.mt-2.d-none.d-sm-block
|
||||
a.sz-md-plus.d-none.d-md-inline(href=`./address/${voutAddresses[0]}`, class=(txIOHighlightAddress == voutAddresses[0] ? "text-info" : null)) #{utils.ellipsizeMiddle(voutAddresses[0], 44)}
|
||||
a.sz-xs-sm.small.d-inline.d-md-none(href=`./address/${voutAddresses[0]}`, class=(txIOHighlightAddress == voutAddresses[0] ? "text-info" : null)) #{utils.ellipsizeMiddle(voutAddresses[0], 24)}
|
||||
|
||||
|
||||
if (txIOHighlightAddress == voutAddresses[0])
|
||||
span(title="Current address", data-bs-toggle="tooltip")
|
||||
i.bi-arrow-left.text-warning.ms-1.text-info
|
||||
|
||||
if (global.specialAddresses[voutAddresses[0]])
|
||||
- var specialAddressInfo = global.specialAddresses[voutAddresses[0]];
|
||||
if (specialAddressInfo.type == "minerPayout")
|
||||
span
|
||||
a.d-none.d-sm-inline(data-bs-toggle="tooltip", title=`Miner payout address: ${specialAddressInfo.minerInfo.name}`)
|
||||
+funItemIcon
|
||||
|
||||
.d-block.d-sm-none
|
||||
div(class=`tx-input-address-${tx.txid}`, style="display: none;")
|
||||
a.sz-xs-sm.small(href=`./address/${voutAddresses[0]}`, class=(txIOHighlightAddress == voutAddresses[0] ? "text-info" : null)) #{utils.ellipsizeMiddle(voutAddresses[0], 24)}
|
||||
|
||||
if (txIOHighlightAddress == voutAddresses[0])
|
||||
span(title="Current address", data-bs-toggle="tooltip")
|
||||
i.bi-arrow-left.text-warning.ms-1.text-info
|
||||
|
||||
if (tx.vin.length > 1 || txVinIndex > 0)
|
||||
hr.mb-1
|
||||
|
||||
if (false)
|
||||
small
|
||||
span.border-dotted(title="Transaction output", data-bs-toggle="tooltip") txo
|
||||
span.me-1 :
|
||||
a(href=`./tx/${txInput.txid}#output-${txVin.vout}`) #{utils.ellipsize(txInput.txid, 20)}[#{txVin.vout}]
|
||||
|
||||
else
|
||||
|
||||
|
||||
if (tx.vin.length > 1)
|
||||
hr.d-none.d-sm-block
|
||||
|
||||
else
|
||||
- extraInputCount = extraInputCount + 1;
|
||||
|
||||
if (extraInputCount > 0)
|
||||
.clearfix.mb-sm-2
|
||||
a.sz-md-plus.d-none.d-sm-inline.badge.fw-normal.card-highlight.border.text-decoration-none(data-bs-toggle="tooltip", title=`Input #${(tx.vin.length - extraInputCount + 1).toLocaleString()} - ${tx.vin.length.toLocaleString()}`, style="white-space: nowrap;")
|
||||
i.bi-arrow-right.text-danger.me-sm-2
|
||||
span.d-none.d-sm-inline …
|
||||
|
||||
a.sz-xs-only.d-inline.d-sm-none.text-decoration-none.me-1(data-bs-toggle="tooltip", title=`Input #${(tx.vin.length - extraInputCount + 1).toLocaleString()} - ${tx.vin.length.toLocaleString()}`, style="white-space: nowrap;")
|
||||
i.d-inline.bi-arrow-right.text-danger
|
||||
|
||||
small.text-muted.border-dotted.ms-0.ms-sm-2(data-bs-toggle="tooltip", title="The details for the remaining inputs were truncated for performance purposes. Click through to the transaction details to see all inputs.") (#{extraInputCount.toLocaleString()} truncated)
|
||||
|
||||
.float-end
|
||||
- var currencyValue = new Decimal(totalIOValues.output).minus(new Decimal(totalIOValues.input));
|
||||
span.border-dotted.me-1(title="The total amounts for other inputs are approximately equal to this value, plus the mining fee paid.", data-bs-toggle="tooltip") ~+
|
||||
+valueDisplay(currencyValue)
|
||||
|
||||
hr.d-none.d-sm-block
|
||||
|
||||
if (totalIOValues.input && totalIOValues.input > 0 && tx.vin.length > 1)
|
||||
.row.mb-0.mb-md-0
|
||||
.col
|
||||
.text-end.mt-1.mt-sm-n1
|
||||
if (totalIOValues.input > 0 && extraInputCount == 0)
|
||||
i.d-inline.d-lg-none.bi-arrow-right.text-danger.me-2
|
||||
span.fw-bold
|
||||
+valueDisplay(totalIOValues.input)
|
||||
|
||||
else if (extraInputCount > 0)
|
||||
i.d-inline.d-lg-none.bi-arrow-right.text-danger.me-2
|
||||
span.border-dotted.me-1(title="The total input amount for this transaction is approximately equal to this value, plus the mining fee paid.", data-bs-toggle="tooltip") ~+
|
||||
span.fw-bold
|
||||
+valueDisplay(totalIOValues.output)
|
||||
|
||||
|
||||
|
||||
.d-xs-block.d-sm-none
|
||||
.my-3
|
||||
hr
|
||||
|
||||
if (tx.vin.length == 1)
|
||||
.d-none.d-sm-block.d-md-block.d-lg-none
|
||||
.my-4
|
||||
hr
|
||||
|
||||
else
|
||||
.d-none.d-sm-block.d-lg-none
|
||||
.mb-4
|
||||
|
|
||||
|
||||
.col-lg-6(class=(tx.vout.length > tx.vin.length ? "border-lg-start" : false))
|
||||
- var maxRegularRowCount = maxTxOutputDisplayCount || options.maxTxOutputDisplayCount || 15;
|
||||
- var regularRowCount = 0;
|
||||
- var hiddenRowCount = 0;
|
||||
- var nonZeroVoutValueCount = tx.vout.filter(vout => { return vout.value > 0; }).length;
|
||||
|
||||
each vout, voutIndex in tx.vout
|
||||
- var voutAddresses = utils.getVoutAddresses(vout);
|
||||
|
||||
- var highlightRow = false;
|
||||
if (txIOHighlightAddress != null && voutAddresses.length > 0 && voutAddresses[0] == txIOHighlightAddress)
|
||||
- highlightRow = true;
|
||||
|
||||
if (!highlightRow)
|
||||
- regularRowCount++;
|
||||
|
||||
- var hiddenRow = false;
|
||||
if (!highlightRow && regularRowCount > maxRegularRowCount)
|
||||
- hiddenRow = true;
|
||||
- hiddenRowCount++;
|
||||
|
||||
div(data-txid=tx.txid, class=(hiddenRow ? "d-none" : ""))
|
||||
.clearfix.mb-0.mb-sm-2.mb-md-3
|
||||
a.xs-hidden.d-none.d-sm-inline.badge.card-highlight.border.text-decoration-none.fw-normal.me-2(data-bs-toggle="tooltip", title=`Output #${voutIndex.toLocaleString()}`, style="white-space: nowrap;")
|
||||
i.d-inline.bi-arrow-right.text-success
|
||||
|
||||
span.d-none.d-sm-inline.font-monospace.ms-1 #{voutIndex.toLocaleString()}
|
||||
|
||||
a.xs-only.d-inline.d-sm-none.text-decoration-none.fw-normal.me-1(data-bs-toggle="tooltip", title=`Output #${voutIndex.toLocaleString()}`, style="white-space: nowrap;")
|
||||
i.d-inline.bi-arrow-right.text-success
|
||||
|
||||
if (vout && vout.scriptPubKey)
|
||||
if (vout.scriptPubKey.hex && vout.scriptPubKey.hex.startsWith('6a24aa21a9ed'))
|
||||
span
|
||||
+primaryBadge("OP_RETURN")
|
||||
|
||||
a(href="https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#commitment-structure", data-bs-toggle="tooltip", title="Read about the SegWit Commitment", target="_blank")
|
||||
+darkBadge
|
||||
span.small SegWit
|
||||
i.bi-box-arrow-up-right.ms-1
|
||||
|
||||
.my-2
|
||||
+hexDataDisplay(vout.scriptPubKey.asm.substring("OP_RETURN ".length))
|
||||
|
||||
else if (vout.scriptPubKey.asm && vout.scriptPubKey.asm.startsWith('OP_RETURN '))
|
||||
span
|
||||
+primaryBadge("OP_RETURN")
|
||||
|
||||
.my-2
|
||||
+hexDataDisplay(vout.scriptPubKey.asm.substring("OP_RETURN ".length))
|
||||
|
||||
else if (vout.scriptPubKey.type)
|
||||
span.d-none.d-sm-inline
|
||||
+darkBadge
|
||||
span(title=`Output Type: ${utils.outputTypeName(vout.scriptPubKey.type)}`, data-bs-toggle="tooltip") #{utils.outputTypeAbbreviation(vout.scriptPubKey.type)}
|
||||
|
||||
|
||||
|
||||
if (voutAddresses.length == 0)
|
||||
// xs display only, output type when we have no address (e.g. op_return)
|
||||
|
||||
if (vout.scriptPubKey.asm && vout.scriptPubKey.asm.startsWith('OP_RETURN '))
|
||||
if (false)
|
||||
span.small.xs-only.d-inline.d-sm-none
|
||||
+primaryBadge("OP_RETURN")
|
||||
|
||||
.xs-sm.d-inline-block.d-md-none.small.border.rounded-1.px-1.card-highlight.mt-1
|
||||
- var asm = vout.scriptPubKey.asm.substring("OP_RETURN ".length);
|
||||
span.text-tiny.fw-light #{utils.formatHex(asm, "utf8")}
|
||||
|
||||
else if (vout.scriptPubKey.type)
|
||||
span.small.xs-only.d-inline.d-sm-none
|
||||
+darkBadge
|
||||
span(title=`Output Type: ${utils.outputTypeName(vout.scriptPubKey.type)}`, data-bs-toggle="tooltip") #{utils.outputTypeAbbreviation(vout.scriptPubKey.type)}
|
||||
|
||||
|
||||
span.ms-2.float-end
|
||||
+outputValueDisplay(tx, vout, voutIndex, nonZeroVoutValueCount)
|
||||
|
||||
if (vout && vout.scriptPubKey.asm && !vout.scriptPubKey.asm.startsWith("OP_RETURN "))
|
||||
if (voutAddresses.length == 0)
|
||||
.my-2
|
||||
+hexDataDisplay(vout.scriptPubKey.hex)
|
||||
|
||||
|
||||
if (voutAddresses.length > 0)
|
||||
.d-inline.d-lg-block.mt-lg-2
|
||||
each addr in voutAddresses
|
||||
a.sz-lg-plus.d-none.d-lg-inline(id=`output-${voutIndex}`, href=`./address/${addr}`)
|
||||
span(class=(highlightRow ? "text-info" : null)) #{utils.ellipsizeMiddle(addr, 44)}
|
||||
|
||||
a.sz-md.d-none.d-md-inline.d-lg-none(id=`output-${voutIndex}`, href=`./address/${addr}`)
|
||||
span(class=(highlightRow ? "text-info" : null)) #{utils.ellipsizeMiddle(addr, 24)}
|
||||
|
||||
a.sz-xs-sm.d-inline.d-md-none(id=`output-${voutIndex}`, href=`./address/${addr}`)
|
||||
span.small(class=(highlightRow ? "text-info" : null)) #{utils.ellipsizeMiddle(addr, 18)}
|
||||
|
||||
if (highlightRow)
|
||||
span(title="Current address", data-bs-toggle="tooltip")
|
||||
i.bi-arrow-left.ms-1.text-warning
|
||||
|
||||
if (global.specialAddresses[addr])
|
||||
- var specialAddressInfo = global.specialAddresses[addr];
|
||||
if (specialAddressInfo.type == "minerPayout")
|
||||
span
|
||||
a.d-none.d-sm-inline(data-bs-toggle="tooltip", title=`Miner payout address: ${specialAddressInfo.minerInfo.name}`)
|
||||
+funItemIcon
|
||||
|
||||
.d-none.d-sm-block.mb-2
|
||||
|
||||
|
||||
|
||||
if (vout.scriptPubKey)
|
||||
if (voutAddresses.length > 0)
|
||||
|
||||
|
||||
else if (false)
|
||||
.mb-tiny
|
||||
span(title=`Output Type: ${utils.outputTypeName(vout.scriptPubKey.type)}`, data-bs-toggle="tooltip")
|
||||
+darkBadge(utils.outputTypeAbbreviation(vout.scriptPubKey.type))
|
||||
|
||||
+hexDataDisplay(vout.scriptPubKey.asm)
|
||||
|
||||
|
||||
if (voutIndex < (tx.vout.length - 1) || nonZeroVoutValueCount > 1)
|
||||
hr.d-none.d-md-block
|
||||
|
||||
else
|
||||
.mb-0
|
||||
|
||||
if (hiddenRowCount > 0)
|
||||
a.small(href="javascript:void(0)", onclick=("showAllTxOutputs(this, '" + tx.txid + "');"))
|
||||
i.bi-plus-square.text-card-highlight.me-1
|
||||
| Show remaining #{hiddenRowCount.toLocaleString()} outputs
|
||||
|
||||
if (nonZeroVoutValueCount > 1)
|
||||
.row.mb-0.mb-lg-0
|
||||
.col
|
||||
.text-end.mt-1.mt-sm-n1(style=(utxos ? "margin-right: 1.39rem !important;" : false))
|
||||
span.fw-bold
|
||||
i.d-inline.d-lg-none.bi-arrow-right.text-success.me-2
|
||||
+valueDisplay(totalIOValues.output)
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
include ./includes/shared-mixins.pug
|
||||
include ./includes/tx-mixins.pug
|
||||
|
||||
doctype html
|
||||
html(lang="en")
|
||||
|
|
|
|||
|
|
@ -273,7 +273,9 @@ block content
|
|||
if (result && result.getblock)
|
||||
- blockHeight = result.getblock.height;
|
||||
|
||||
include includes/transaction-io-details.pug
|
||||
- var totalIOValues = utils.getTxTotalInputOutputValues(tx, txInputs, blockHeight);
|
||||
|
||||
+txIoDetails(tx, txInputs, totalIOValues, blockHeight)
|
||||
|
||||
|
||||
if (mempoolDetails)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue