mirror of
https://github.com/Retropex/bitfeed.git
synced 2025-05-12 19:20:46 +02:00
Add output address highlighting
This commit is contained in:
parent
8f03a9056c
commit
0cce3ca92f
@ -1,13 +1,17 @@
|
||||
<script>
|
||||
import SearchIcon from '../assets/icon/cil-search.svg'
|
||||
import { matchQuery } from '../utils/search.js'
|
||||
import { highlight } from '../stores.js'
|
||||
|
||||
let query
|
||||
|
||||
$: {
|
||||
$highlight = [{
|
||||
id: query
|
||||
}]
|
||||
if (query) {
|
||||
const matchedQuery = matchQuery(query.trim())
|
||||
if (matchedQuery) {
|
||||
$highlight = [matchedQuery]
|
||||
} else $highlight = []
|
||||
} else $highlight = []
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -28,6 +32,6 @@ $: {
|
||||
|
||||
<div class="search tab-content">
|
||||
<div class="input-wrapper">
|
||||
<input class="search-input" type="text" bind:value={query} placeholder="Enter a txid...">
|
||||
<input class="search-input" type="text" bind:value={query} placeholder="Enter an address or txid...">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -30,16 +30,6 @@ export default class BitcoinTx {
|
||||
this.time = time
|
||||
this.highlight = false
|
||||
|
||||
// Highlight transactions to the static donation address
|
||||
// if (config.donationHash && this.outputs) {
|
||||
// this.outputs.forEach(output => {
|
||||
// if (output.script_pub_key.includes(config.donationHash)) {
|
||||
// console.log('donation!', this)
|
||||
// this.highlight = true
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
// is a coinbase transaction?
|
||||
if (this.inputs && this.inputs.length === 1 && this.inputs[0].prev_txid === "0000000000000000000000000000000000000000000000000000000000000000") {
|
||||
const cbInfo = this.inputs[0].script_sig
|
||||
@ -101,8 +91,14 @@ export default class BitcoinTx {
|
||||
applyHighlighting (criteria, color = highlightColor) {
|
||||
this.highlight = false
|
||||
criteria.forEach(criterion => {
|
||||
if (criterion.id === this.id) {
|
||||
if (criterion.txid === this.id) {
|
||||
this.highlight = true
|
||||
} else if (criterion.address && criterion.scriptPubKey) {
|
||||
this.outputs.forEach(output => {
|
||||
if (output.script_pub_key === criterion.scriptPubKey) {
|
||||
this.highlight = true
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
this.view.setHighlight(this.highlight, color)
|
||||
|
27
client/src/utils/encodings.js
Normal file
27
client/src/utils/encodings.js
Normal file
@ -0,0 +1,27 @@
|
||||
import { Buffer } from 'buffer/'
|
||||
window.Buffer = Buffer
|
||||
import bech32 from 'bech32-buffer'
|
||||
import { base58_to_binary } from 'base58-js'
|
||||
|
||||
// Extract a raw script hash from an address
|
||||
export function addressToSPK (address) {
|
||||
if (address.startsWith('bc1')) {
|
||||
const result = bech32.BitcoinAddress.decode(address)
|
||||
let prefix
|
||||
if (result.scriptVersion == 1) prefix = '5120' // taproot (OP_PUSHNUM_1 OP_PUSHBYTES_32)
|
||||
else if (address.length == 62) prefix = '0020' // p2wsh (OP_0 OP_PUSHBYTES_32)
|
||||
else prefix = '0014' // p2wpkh (OP_0 OP_PUSHBYTES_20)
|
||||
return prefix + Buffer.from(result.data).toString('hex')
|
||||
} else {
|
||||
const result = base58_to_binary(address)
|
||||
let prefix, postfix
|
||||
if (address.charAt(0) === '1') {
|
||||
prefix = '76a914' // p2pkh (OP_DUP OP_HASH160 OP_PUSHBYTES_20)
|
||||
postfix = '88ac' // p2pkh (OP_EQUALVERIFY OP_CHECKSIG)
|
||||
} else {
|
||||
prefix = 'a914' // p2sh (OP_HASH160 OP_PUSHBYTES_20)
|
||||
postfix = '87' // p2sh (OP_EQUAL)
|
||||
}
|
||||
return prefix + Buffer.from(result).toString('hex').slice(2, -8) + postfix
|
||||
}
|
||||
}
|
76
client/src/utils/search.js
Normal file
76
client/src/utils/search.js
Normal file
@ -0,0 +1,76 @@
|
||||
import { addressToSPK } from './encodings.js'
|
||||
|
||||
// Quick heuristic matching to guess what kind of search a query is for
|
||||
// ***does not validate that a given address/txid/block is valid***
|
||||
export function matchQuery (query) {
|
||||
if (!query || !query.length) return
|
||||
|
||||
const q = query.toLowerCase()
|
||||
|
||||
// Looks like a block height?
|
||||
const asInt = parseInt(q)
|
||||
// Remember to update the bounds in
|
||||
if (!isNaN(asInt) && asInt >= 0 && `${asInt}` === q) {
|
||||
return {
|
||||
query: 'blockheight',
|
||||
height: asInt
|
||||
}
|
||||
}
|
||||
|
||||
// Looks like a block hash?
|
||||
if (/^0{8}[a-f0-9]{56}$/.test(q)) {
|
||||
return {
|
||||
query: 'blockhash',
|
||||
hash: q
|
||||
}
|
||||
}
|
||||
|
||||
// Looks like a transaction id?
|
||||
if (/^[a-f0-9]{64}$/.test(q)) {
|
||||
return {
|
||||
query: 'txid',
|
||||
txid: q
|
||||
}
|
||||
}
|
||||
|
||||
// Looks like an address
|
||||
if ((q.length >= 26 && q.length <= 34) || q.length === 42 || q.length === 62) {
|
||||
// Looks like a legacy address
|
||||
if (/^[13]\w{24,33}$/.test(q)) {
|
||||
let addressType
|
||||
if (q[0] === '1') addressType = 'p2pkh'
|
||||
else if (q[0] === '3') addressType = 'p2sh'
|
||||
else return null
|
||||
|
||||
return {
|
||||
query: 'address',
|
||||
encoding: 'base58',
|
||||
addressType,
|
||||
address: query,
|
||||
scriptPubKey: addressToSPK(query)
|
||||
}
|
||||
}
|
||||
|
||||
// Looks like a bech32 address
|
||||
if (/^bc1\w{39}(\w{20})?$/.test(q)) {
|
||||
let addressType
|
||||
if (q.startsWith('bc1q')) {
|
||||
if (q.length === 42) addressType = 'p2wpkh'
|
||||
else if (q.length === 62) addressType = 'p2wsh'
|
||||
else return null
|
||||
} else if (q.startsWith('bc1p') && q.length === 62) {
|
||||
addressType = 'p2tr'
|
||||
} else return null
|
||||
|
||||
return {
|
||||
query: 'address',
|
||||
encoding: 'bech32',
|
||||
addressType,
|
||||
address: query,
|
||||
scriptPubKey: addressToSPK(query)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
Loading…
Reference in New Issue
Block a user