diff --git a/config.json b/config.json index 754088b..56912c1 100644 --- a/config.json +++ b/config.json @@ -2,8 +2,8 @@ "name": "Onchain Wallet", "short_description": "Onchain watch only wallets", "tile": "/watchonly/static/bitcoin-wallet.png", - "version": "0.4.0", - "min_lnbits_version": "1.5.0", + "version": "0.5.0", + "min_lnbits_version": "1.6.0", "contributors": [ { "name": "motorina0", diff --git a/static/components/history.js b/static/components/history.js index c1ff3dd..3b84e53 100644 --- a/static/components/history.js +++ b/static/components/history.js @@ -41,10 +41,10 @@ window.app.component('history', { sortable: true }, { - name: 'date', + name: 'height', align: 'left', - label: this.$t('watchonly.date'), - field: 'date', + label: this.$t('watchonly.block_height'), + field: 'height', sortable: true }, { @@ -60,8 +60,8 @@ window.app.component('history', { field: 'action' }, { - label: this.$t('watchonly.date_time'), - field: 'date' + label: this.$t('watchonly.block_height'), + field: 'height' }, { label: this.$t('watchonly.amount'), diff --git a/static/components/utxo-list.js b/static/components/utxo-list.js index 7d3e161..bda4597 100644 --- a/static/components/utxo-list.js +++ b/static/components/utxo-list.js @@ -66,10 +66,10 @@ window.app.component('utxo-list', { sortable: true }, { - name: 'date', + name: 'height', align: 'left', - label: this.$t('watchonly.date'), - field: 'date', + label: this.$t('watchonly.block_height'), + field: 'height', sortable: true }, { diff --git a/static/index.js b/static/index.js index 9d5dde7..422654e 100644 --- a/static/index.js +++ b/static/index.js @@ -1,7 +1,6 @@ window.PageWatchonly = Vue.defineAsyncComponent(async () => { await Promise.all([ LNbits.utils.loadScript('https://connect.trezor.io/9/trezor-connect.js'), - LNbits.utils.loadScript('https://mempool.space/mempool.js'), LNbits.utils.loadScript('/watchonly/static/js/tables.js'), LNbits.utils.loadScript('/watchonly/static/js/map.js'), LNbits.utils.loadScript('/watchonly/static/js/utils.js'), @@ -141,18 +140,35 @@ window.PageWatchonly = Vue.defineAsyncComponent(async () => { }, //################### ADDRESS HISTORY ################### - addressHistoryFromTxs: function (addressData, txs) { + addressHistoryFromTxs: function (addressData, txs, historyEntries = []) { + const txsByTxid = {} + txs.forEach(tx => { + txsByTxid[tx.txid] = tx + }) + const metaByTxid = {} + historyEntries.forEach(h => { + metaByTxid[h.tx_hash] = h + }) + const addressHistory = [] txs.forEach(tx => { + const meta = metaByTxid[tx.txid] || {} + const sent = tx.vin - .filter( - vin => vin.prevout.scriptpubkey_address === addressData.address - ) - .map(vin => mapInputToSentHistory(tx, addressData, vin)) + .map(vin => { + const prevTx = txsByTxid[vin.txid] + const prevOut = prevTx && prevTx.vout.find(v => v.n === vin.vout) + return prevOut && + prevOut.scriptPubKey.address === addressData.address + ? mapInputToSentHistory(tx, addressData, prevOut, meta) + : null + }) + .filter(Boolean) const received = tx.vout - .filter(vout => vout.scriptpubkey_address === addressData.address) - .map(vout => mapOutputToReceiveHistory(tx, addressData, vout)) + .filter(vout => vout.scriptPubKey.address === addressData.address) + .map(vout => mapOutputToReceiveHistory(tx, addressData, vout, meta)) + addressHistory.push(...sent, ...received) }) return addressHistory @@ -297,7 +313,7 @@ window.PageWatchonly = Vue.defineAsyncComponent(async () => { try { for (addrData of addresses) { - const addressHistory = await this.getAddressTxsDelayed(addrData) + const addressHistory = await this.getAddressHistoryDelayed(addrData) // remove old entries this.history = this.history.filter( h => h.address !== addrData.address @@ -310,9 +326,7 @@ window.PageWatchonly = Vue.defineAsyncComponent(async () => { if (addressHistory.length) { // search only if it ever had any activity - const utxos = await this.getAddressTxsUtxoDelayed( - addrData.address - ) + const utxos = await this.getAddressUtxosDelayed(addrData.address) this.updateUtxosForAddress(addrData, utxos) } @@ -356,39 +370,38 @@ window.PageWatchonly = Vue.defineAsyncComponent(async () => { this.updateAmountForAddress(addressData, addressTotal) }, - //################### MEMPOOL API ################### - getAddressTxsDelayed: async function (addrData) { + //################### BLOCKEXPLORER API ################### + getAddressHistoryDelayed: async function (addrData) { const accounts = this.walletAccounts - const { - bitcoin: {addresses: addressesAPI} - } = mempoolJS({ - hostname: this.mempoolHostname - }) const fn = async () => { - if (!accounts.find(w => w.id === addrData.wallet)) return [] - return addressesAPI.getAddressTxs({ - address: addrData.address - }) + if (!accounts.find(w => w.id === addrData.wallet)) { + return {history: []} + } + const {data} = await LNbits.api.getBlockexplorerAddress( + addrData.address + ) + if (data.history_error) throw new Error(data.history_error) + return data } - const addressTxs = await retryWithDelay(fn) - return this.addressHistoryFromTxs(addrData, addressTxs) + const {history} = await retryWithDelay(fn) + if (!history.length) return [] + + const txs = await Promise.all( + history.map(async h => { + const {data} = await LNbits.api.getBlockexplorerTransaction( + h.tx_hash + ) + return data + }) + ) + return this.addressHistoryFromTxs(addrData, txs, history) }, - getAddressTxsUtxoDelayed: async function (address) { - const endpoint = this.mempoolHostname - const { - bitcoin: {addresses: addressesAPI} - } = mempoolJS({ - hostname: endpoint + getAddressUtxosDelayed: async function (address) { + return retryWithDelay(async () => { + const {data} = await LNbits.api.getBlockexplorerUtxos(address) + return data }) - - const fn = async () => { - if (endpoint !== this.mempoolHostname) return [] - return addressesAPI.getAddressTxsUtxo({ - address - }) - } - return retryWithDelay(fn) }, openQrCodeDialog: function (addressData) { diff --git a/static/index.vue b/static/index.vue index fa6b4cd..9da72cb 100644 --- a/static/index.vue +++ b/static/index.vue @@ -609,7 +609,7 @@ >
-