diff --git a/backend/src/api/bitcoin/bitcoin-api.interface.ts b/backend/src/api/bitcoin/bitcoin-api.interface.ts index 018d30223..6f23fdb4d 100644 --- a/backend/src/api/bitcoin/bitcoin-api.interface.ts +++ b/backend/src/api/bitcoin/bitcoin-api.interface.ts @@ -98,12 +98,15 @@ export namespace IBitcoinApi { export interface AddressInformation { isvalid: boolean; // (boolean) If the address is valid or not. If not, this is the only property returned. + isvalid_parent?: boolean; // (boolean) Elements only address: string; // (string) The bitcoin address validated scriptPubKey: string; // (string) The hex-encoded scriptPubKey generated by the address isscript: boolean; // (boolean) If the key is a script iswitness: boolean; // (boolean) If the address is a witness witness_version?: boolean; // (numeric, optional) The version number of the witness program witness_program: string; // (string, optional) The hex value of the witness program + confidential_key?: string; // (string) Elements only + unconfidential?: string; // (string) Elements only } export interface ChainTips { diff --git a/backend/src/api/bitcoin/bitcoin-api.ts b/backend/src/api/bitcoin/bitcoin-api.ts index 2110dc659..4b5448255 100644 --- a/backend/src/api/bitcoin/bitcoin-api.ts +++ b/backend/src/api/bitcoin/bitcoin-api.ts @@ -60,13 +60,12 @@ class BitcoinApi implements AbstractBitcoinApi { return this.bitcoindClient.getBlock(hash, 0); } - $getBlockHash(height: number): Promise { return this.bitcoindClient.getBlockHash(height); } $getBlockHeader(hash: string): Promise { - return this.bitcoindClient.getBlockHeader(hash,false); + return this.bitcoindClient.getBlockHeader(hash, false); } async $getBlock(hash: string): Promise { @@ -238,10 +237,6 @@ class BitcoinApi implements AbstractBitcoinApi { }); } - protected $validateAddress(address: string): Promise { - return this.bitcoindClient.validateAddress(address); - } - private $getMempoolEntry(txid: string): Promise { return this.bitcoindClient.getMempoolEntry(txid); } diff --git a/backend/src/api/bitcoin/bitcoin-base.api.ts b/backend/src/api/bitcoin/bitcoin-base.api.ts index a447da5fe..c544e5225 100644 --- a/backend/src/api/bitcoin/bitcoin-base.api.ts +++ b/backend/src/api/bitcoin/bitcoin-base.api.ts @@ -44,6 +44,10 @@ class BitcoinBaseApi { $getBlockchainInfo(): Promise { return this.bitcoindClient.getBlockchainInfo(); } + + $validateAddress(address: string): Promise { + return this.bitcoindClient.validateAddress(address); + } } export default new BitcoinBaseApi(); diff --git a/backend/src/api/bitcoin/electrum-api.ts b/backend/src/api/bitcoin/electrum-api.ts index 38597c0cf..2f3d4c7eb 100644 --- a/backend/src/api/bitcoin/electrum-api.ts +++ b/backend/src/api/bitcoin/electrum-api.ts @@ -11,6 +11,7 @@ import * as sha256 from 'crypto-js/sha256'; import * as hexEnc from 'crypto-js/enc-hex'; import loadingIndicators from '../loading-indicators'; import memoryCache from '../memory-cache'; +import bitcoinBaseApi from './bitcoin-base.api'; class BitcoindElectrsApi extends BitcoinApi implements AbstractBitcoinApi { private electrumClient: any; @@ -44,7 +45,7 @@ class BitcoindElectrsApi extends BitcoinApi implements AbstractBitcoinApi { } async $getAddress(address: string): Promise { - const addressInfo = await this.$validateAddress(address); + const addressInfo = await bitcoinBaseApi.$validateAddress(address); if (!addressInfo || !addressInfo.isvalid) { return ({ 'address': address, @@ -98,7 +99,7 @@ class BitcoindElectrsApi extends BitcoinApi implements AbstractBitcoinApi { } async $getAddressTransactions(address: string, lastSeenTxId: string): Promise { - const addressInfo = await this.$validateAddress(address); + const addressInfo = await bitcoinBaseApi.$validateAddress(address); if (!addressInfo || !addressInfo.isvalid) { return []; } diff --git a/backend/src/index.ts b/backend/src/index.ts index e71931e83..f8e30414c 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -251,6 +251,7 @@ class Server { .get(config.MEMPOOL.API_URL_PREFIX + 'address/:address/txs', routes.getAddressTransactions) .get(config.MEMPOOL.API_URL_PREFIX + 'address/:address/txs/chain/:txId', routes.getAddressTransactions) .get(config.MEMPOOL.API_URL_PREFIX + 'address-prefix/:prefix', routes.getAddressPrefix) + .get(config.MEMPOOL.API_URL_PREFIX + 'validate-address/:address', routes.validateAddress) ; } } diff --git a/backend/src/routes.ts b/backend/src/routes.ts index 3b374f788..849fe76b0 100644 --- a/backend/src/routes.ts +++ b/backend/src/routes.ts @@ -17,6 +17,7 @@ import transactionUtils from './api/transaction-utils'; import blocks from './api/blocks'; import loadingIndicators from './api/loading-indicators'; import { Common } from './api/common'; +import bitcoinBaseApi from './api/bitcoin/bitcoin-base.api'; class Routes { constructor() {} @@ -687,6 +688,15 @@ class Routes { } } + public async validateAddress(req: Request, res: Response) { + try { + const result = await bitcoinBaseApi.$validateAddress(req.params.address); + res.json(result); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + public getTransactionOutspends(req: Request, res: Response) { res.status(501).send('Not implemented'); } @@ -727,7 +737,7 @@ class Routes { const timeAvg = timeAvgMins * 60; const remainingTime = remainingBlocks * timeAvg; const estimatedRetargetDate = remainingTime + now; - + const result = { progressPercent, difficultyChange, @@ -737,7 +747,7 @@ class Routes { previousRetarget, nextRetargetHeight, timeAvg, - } + }; res.json(result); } catch (e) { diff --git a/frontend/src/app/components/address/address.component.html b/frontend/src/app/components/address/address.component.html index e20279656..b4e5d27d2 100644 --- a/frontend/src/app/components/address/address.component.html +++ b/frontend/src/app/components/address/address.component.html @@ -18,6 +18,10 @@
+ + + + diff --git a/frontend/src/app/components/address/address.component.ts b/frontend/src/app/components/address/address.component.ts index ca0198c8f..c6e229a1d 100644 --- a/frontend/src/app/components/address/address.component.ts +++ b/frontend/src/app/components/address/address.component.ts @@ -9,6 +9,7 @@ import { AudioService } from 'src/app/services/audio.service'; import { ApiService } from 'src/app/services/api.service'; import { of, merge, Subscription, Observable } from 'rxjs'; import { SeoService } from 'src/app/services/seo.service'; +import { AddressInformation } from 'src/app/interfaces/node-api.interface'; @Component({ selector: 'app-address', @@ -27,6 +28,7 @@ export class AddressComponent implements OnInit, OnDestroy { error: any; mainSubscription: Subscription; addressLoadingStatus$: Observable; + addressInfo: null | AddressInformation = null; totalConfirmedTxCount = 0; loadedConfirmedTxCount = 0; @@ -67,6 +69,7 @@ export class AddressComponent implements OnInit, OnDestroy { this.address = null; this.isLoadingTransactions = true; this.transactions = null; + this.addressInfo = null; document.body.scrollTo(0, 0); this.addressString = params.get('id') || ''; this.seoService.setTitle($localize`:@@address.component.browser-title:Address: ${this.addressString}:INTERPOLATION:`); @@ -92,10 +95,20 @@ export class AddressComponent implements OnInit, OnDestroy { ) .pipe( filter((address) => !!address), + tap((address: Address) => { + if (this.stateService.network === 'liquid' && /^([m-zA-HJ-NP-Z1-9]{26,35}|[a-z]{2,5}1[ac-hj-np-z02-9]{8,100}|[a-km-zA-HJ-NP-Z1-9]{80})$/.test(address.address)) { + this.apiService.validateAddress$(address.address) + .subscribe((addressInfo) => { + this.addressInfo = addressInfo; + this.websocketService.startTrackAddress(addressInfo.unconfidential); + }); + } else { + this.websocketService.startTrackAddress(address.address); + } + }), switchMap((address) => { this.address = address; this.updateChainStats(); - this.websocketService.startTrackAddress(address.address); this.isLoadingAddress = false; this.isLoadingTransactions = true; return this.electrsApiService.getAddressTransactions$(address.address); diff --git a/frontend/src/app/interfaces/node-api.interface.ts b/frontend/src/app/interfaces/node-api.interface.ts index 190aa08ab..2a4bce0e8 100644 --- a/frontend/src/app/interfaces/node-api.interface.ts +++ b/frontend/src/app/interfaces/node-api.interface.ts @@ -34,3 +34,16 @@ export interface DifficultyAdjustment { remainingBlocks: number; remainingTime: number; } + +export interface AddressInformation { + isvalid: boolean; // (boolean) If the address is valid or not. If not, this is the only property returned. + isvalid_parent?: boolean; // (boolean) Elements only + address: string; // (string) The bitcoin address validated + scriptPubKey: string; // (string) The hex-encoded scriptPubKey generated by the address + isscript: boolean; // (boolean) If the key is a script + iswitness: boolean; // (boolean) If the address is a witness + witness_version?: boolean; // (numeric, optional) The version number of the witness program + witness_program: string; // (string, optional) The hex value of the witness program + confidential_key?: string; // (string) Elements only + unconfidential?: string; // (string) Elements only +} diff --git a/frontend/src/app/services/api.service.ts b/frontend/src/app/services/api.service.ts index 0c543e786..d38cdf8f4 100644 --- a/frontend/src/app/services/api.service.ts +++ b/frontend/src/app/services/api.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { HttpClient, HttpParams } from '@angular/common/http'; -import { CpfpInfo, OptimizedMempoolStats, DifficultyAdjustment } from '../interfaces/node-api.interface'; +import { CpfpInfo, OptimizedMempoolStats, DifficultyAdjustment, AddressInformation } from '../interfaces/node-api.interface'; import { Observable } from 'rxjs'; import { StateService } from './state.service'; import { WebsocketResponse } from '../interfaces/websocket.interface'; @@ -96,4 +96,8 @@ export class ApiService { getDifficultyAdjustment$(): Observable { return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/difficulty-adjustment'); } + + validateAddress$(address: string): Observable { + return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/validate-address/' + address); + } }
Unconfidential{{ addressInfo.unconfidential }}
Total received