Parse P2PK and P2MS addresses

This commit is contained in:
Mononaut 2022-04-17 12:14:06 -06:00
parent 77e0204934
commit 272c1ad829
3 changed files with 51 additions and 5 deletions

View File

@ -4,7 +4,7 @@ import { fade } from 'svelte/transition'
import { flip } from 'svelte/animate'
import Icon from './Icon.svelte'
import SearchIcon from '../assets/icon/cil-search.svg'
import CrossIcon from '../assets/icon/cil-x.svg'
import CrossIcon from '../assets/icon/cil-x-circle.svg'
import AddressIcon from '../assets/icon/cil-wallet.svg'
import TxIcon from '../assets/icon/cil-arrow-circle-right.svg'
import { fly } from 'svelte/transition'
@ -22,6 +22,10 @@ $: {
}
}
function clearInput () {
query = null
}
async function searchSubmit (e) {
e.preventDefault()
@ -58,6 +62,22 @@ async function searchSubmit (e) {
max-width: 600px;
margin: 0 1em;
.clear-button {
position: absolute;
right: 0;
bottom: .3em;
margin: 0;
color: var(--palette-bad);
font-size: 1.2em;
cursor: pointer;
opacity: 1;
transition: opacity 300ms;
&.disabled {
opacity: 0;
}
}
.input-icon {
font-size: 24px;
margin: 0 10px;
@ -130,6 +150,7 @@ async function searchSubmit (e) {
margin: 0;
color: var(--input-color);
width: 100%;
padding-right: 1.5em;
&.disabled {
color: var(--palette-e);
@ -143,6 +164,9 @@ async function searchSubmit (e) {
<div class="input-wrapper" transition:fly={{ y: -25 }}>
<form class="search-form" action="" on:submit={searchSubmit}>
<input class="search-input" type="text" bind:value={query} placeholder="Enter a txid">
<div class="clear-button" class:disabled={query == null || query === ''} on:click={clearInput} title="Clear">
<Icon icon={CrossIcon}/>
</div>
<div class="underline" />
<div class="underline active" />
<button type="submit" class="search-submit" />

View File

@ -11,6 +11,7 @@ import { searchTx } from '../utils/search.js'
function onClose () {
$detailTx = null
$highlightInOut = null
}
function formatBTC (sats) {
@ -69,9 +70,12 @@ function expandAddresses(items, truncate) {
if (item.script_pub_key) {
address = SPKToAddress(item.script_pub_key) || "unknown"
if (address === 'OP_RETURN') {
title = item.script_pub_key.substring(2).match(/../g).reduce((parsed, hexChar) => {
title = item.script_pub_key.substring(4).match(/../g).reduce((parsed, hexChar) => {
return parsed + String.fromCharCode(parseInt(hexChar, 16))
}, "")
} else if (address === 'P2PK') {
if (item.script_pub_key.length === 70) title = 'compressed pubkey: ' + item.script_pub_key.substring(2,68)
else title = 'pubkey: ' + item.script_pub_key.substring(2,132)
}
}
return {
@ -113,7 +117,7 @@ $: {
}
} else inputs = []
if ($detailTx && $detailTx.outputs) {
if ($detailTx.isCoinbase || !$detailTx.is_inflated || $detailTx.fee == null) {
if ($detailTx.isCoinbase || !$detailTx.is_inflated || !$detailTx.fee) {
outputs = expandAddresses($detailTx.outputs, truncate)
} else {
outputs = [{address: 'fee', value: $detailTx.fee, fee: true}, ...expandAddresses($detailTx.outputs, truncate)]
@ -580,7 +584,7 @@ async function clickItem (item) {
<p class="header">{$detailTx.inputs.length} input{$detailTx.inputs.length > 1 ? 's' : ''}</p>
{#each inputs as input}
<div class="entry clickable" on:click={() => clickItem(input)}>
<p class="address" title={input.address}><span class="truncatable">{input.address.slice(0,-6)}</span><span class="suffix">{input.address.slice(-6)}</span></p>
<p class="address" title={input.title || input.address}><span class="truncatable">{input.address.slice(0,-6)}</span><span class="suffix">{input.address.slice(-6)}</span></p>
<p class="amount">{ input.value == null ? '???' : formatBTC(input.value) }</p>
</div>
{/each}
@ -613,7 +617,7 @@ async function clickItem (item) {
{/if}
</div>
<div class="column outputs">
<p class="header">{$detailTx.outputs.length} output{$detailTx.outputs.length > 1 ? 's' : ''} {#if $detailTx.fee != null}+ fee{/if}</p>
<p class="header">{$detailTx.outputs.length} output{$detailTx.outputs.length > 1 ? 's' : ''} {#if $detailTx.fee}+ fee{/if}</p>
{#each outputs as output}
<div class="entry" class:clickable={output.rest || output.spend} class:unspent={!output.spend && !output.fee} class:highlight={highlight.out != null && highlight.out === output.index} on:click={() => clickItem(output)}>
<p class="address" title={output.title || output.address}><span class="truncatable">{output.address.slice(0,-6)}</span><span class="suffix">{output.address.slice(-6)}</span></p>

View File

@ -48,6 +48,24 @@ export function SPKToAddress (spk) {
} else if (spk.startsWith('6a')) {
// OP_RETURN
return 'OP_RETURN'
} else if (spk.length == 134 && spk.startsWith('41') && spk.endsWith('ac')) {
// uncompressed p2pk
return 'P2PK'
} else if (spk.length == 70 && spk.startsWith('21') && spk.endsWith('ac')) {
// compressed p2pk
return 'P2PK'
} else if (spk.endsWith('51ae') && spk.startsWith('51')) {
// possible p2ms (raw multisig)
return '1-of-1 P2MS'
} else if (spk.endsWith('52ae')) {
// possible p2ms (raw multisig)
if (spk.startsWith(51)) return '1-of-2 P2MS'
if (spk.startsWith(52)) return '2-of-2 P2MS'
} else if (spk.endsWith('53ae')) {
// possible p2ms (raw multisig)
if (spk.startsWith(51)) return '1-of-3 P2MS'
if (spk.startsWith(52)) return '2-of-3 P2MS'
if (spk.startsWith(53)) return '3-of-3 P2MS'
}
}