/* TODO - Add blockhash functionality back into getTxOutProof */ import axios, { AxiosRequestConfig, AxiosResponse } from "axios" import { BlockchainInfoResult, BlockDetailsResult, BlockHeaderResult, ChainTipResult, MempoolEntryResult, MempoolInfoResult, TxOutResult } from "bitcoin-com-rest" import { REST_URL } from "./BITBOX" export class Blockchain { public restURL: string constructor(restURL: string = REST_URL) { this.restURL = restURL } public async getBestBlockHash(): Promise { try { const response: AxiosResponse = await axios.get( `${this.restURL}blockchain/getBestBlockHash` ) return response.data } catch (error) { if (error.response && error.response.data) throw error.response.data else throw error } } public async getBlock( blockhash: string, verbose: boolean = true ): Promise { try { const response: AxiosResponse = await axios.get( `${this.restURL}blockchain/getBlock/${blockhash}?verbose=${verbose}` ) return response.data } catch (error) { if (error.response && error.response.data) throw error.response.data else throw error } } public async getBlockchainInfo(): Promise { try { const response: AxiosResponse = await axios.get( `${this.restURL}blockchain/getBlockchainInfo` ) return response.data } catch (error) { if (error.response && error.response.data) throw error.response.data else throw error } } public async getBlockCount(): Promise { try { const response: AxiosResponse = await axios.get( `${this.restURL}blockchain/getBlockCount` ) return response.data } catch (error) { if (error.response && error.response.data) throw error.response.data else throw error } } public async getBlockHash(height: number = 1): Promise { // if (typeof height !== "string") height = JSON.stringify(height) try { const response: AxiosResponse = await axios.get( `${this.restURL}blockchain/getBlockHash/${height}` ) return response.data } catch (error) { if (error.response && error.response.data) throw error.response.data else throw error } } public async getBlockHeader( hash: string | string[], verbose: boolean = true ): Promise { try { // Handle single hash. if (typeof hash === "string") { const response: AxiosResponse = await axios.get( `${this.restURL}blockchain/getBlockHeader/${hash}?verbose=${verbose}` ) return response.data // Handle array of hashes. } else if (Array.isArray(hash)) { // Dev note: must use axios.post for unit test stubbing. const response: AxiosResponse = await axios.post( `${this.restURL}blockchain/getBlockHeader`, { hashes: hash, verbose: verbose } ) return response.data } throw new Error(`Input hash must be a string or array of strings.`) } catch (error) { if (error.response && error.response.data) throw error.response.data else throw error } } public async getChainTips(): Promise { try { const response: AxiosResponse = await axios.get( `${this.restURL}blockchain/getChainTips` ) return response.data } catch (error) { if (error.response && error.response.data) throw error.response.data else throw error } } public async getDifficulty(): Promise { try { const response: AxiosResponse = await axios.get( `${this.restURL}blockchain/getDifficulty` ) return response.data } catch (error) { if (error.response && error.response.data) throw error.response.data else throw error } } // TODO: add back to REST public async getMempoolAncestors( txid: string, verbose: boolean = false ): Promise { if (typeof txid !== "string") txid = JSON.stringify(txid) try { const response: AxiosResponse = await axios.get( `${this.restURL}blockchain/getMempoolAncestors/${txid}?verbose=${verbose}` ) return response.data } catch (error) { if (error.response && error.response.data) throw error.response.data else throw error } } // TODO: add back to REST public async getMempoolDescendants( txid: string, verbose: boolean = false ): Promise { if (typeof txid !== "string") txid = JSON.stringify(txid) try { const response: AxiosResponse = await axios.get( `${this.restURL}blockchain/getMempoolDescendants/${txid}?verbose=${verbose}` ) return response.data } catch (error) { if (error.response && error.response.data) throw error.response.data else throw error } } public async getMempoolEntry( txid: string | string[] ): Promise { try { if (typeof txid === "string") { const response: AxiosResponse = await axios.get( `${this.restURL}blockchain/getMempoolEntry/${txid}` ) return response.data } else if (Array.isArray(txid)) { const options: AxiosRequestConfig = { method: "POST", url: `${this.restURL}blockchain/getMempoolEntry`, data: { txids: txid } } const response: AxiosResponse = await axios(options) return response.data } throw new Error(`Input must be a string or array of strings.`) } catch (error) { if (error.response && error.response.data) throw error.response.data else throw error } } public async getMempoolInfo(): Promise { try { const response: AxiosResponse = await axios.get( `${this.restURL}blockchain/getMempoolInfo` ) return response.data } catch (error) { if (error.response && error.response.data) throw error.response.data else throw error } } public async getRawMempool(verbose: boolean = false): Promise { // TODO fix verbose try { const response: AxiosResponse = await axios.get( `${this.restURL}blockchain/getRawMempool?vebose=${verbose}` ) return response.data } catch (error) { if (error.response && error.response.data) throw error.response.data else throw error } } // Returns details about an unspent transaction output. public async getTxOut( txid: string, n: any, include_mempool: boolean = true ): Promise { // Input validation if (typeof txid !== "string" || txid.length !== 64) throw new Error(`txid needs to be a proper transaction ID`) if (isNaN(n)) throw new Error(`n must be an integer`) if (typeof include_mempool !== "boolean") throw new Error(`include_mempool input must be of type boolean`) try { const path: string = `${this.restURL}blockchain/getTxOut/${txid}/${n}?include_mempool=${include_mempool}` // console.log(`path: ${path}`) const response: AxiosResponse = await axios.get(path) return response.data } catch (error) { if (error.response && error.response.data) throw error.response.data else throw error } } public async getTxOutProof( txids: string | string[] ): Promise { try { // Single txid. if (typeof txids === "string") { const path = `${this.restURL}blockchain/getTxOutProof/${txids}` //if (blockhash) path = `${path}?blockhash=${blockhash}` const response: AxiosResponse = await axios.get(path) return response.data // Array of txids. } else if (Array.isArray(txids)) { // Dev note: must use axios.post for unit test stubbing. const response: AxiosResponse = await axios.post( `${this.restURL}blockchain/getTxOutProof`, { txids: txids } ) return response.data } throw new Error(`Input must be a string or array of strings.`) } catch (error) { if (error.response && error.response.data) throw error.response.data else throw error } } public async preciousBlock(blockhash: string): Promise { // TODO bring this back to REST try { const response: AxiosResponse = await axios.get( `${this.restURL}blockchain/preciousBlock/${blockhash}` ) return response.data } catch (error) { if (error.response && error.response.data) throw error.response.data else throw error } } public async pruneBlockchain(height: number): Promise { // TODO bring this back to REST try { const response: AxiosResponse = await axios.post( `${this.restURL}blockchain/pruneBlockchain/${height}` ) return response.data } catch (error) { if (error.response && error.response.data) throw error.response.data else throw error } } public async verifyChain( checklevel: number = 3, nblocks: number = 6 ): Promise { try { const response: AxiosResponse = await axios.get( `${this.restURL}blockchain/verifyChain?checklevel=${checklevel}&nblocks=${nblocks}` ) return response.data } catch (error) { if (error.response && error.response.data) throw error.response.data else throw error } } public async verifyTxOutProof(proof: string | string[]): Promise { try { // Single block if (typeof proof === "string") { const response: AxiosResponse = await axios.get( `${this.restURL}blockchain/verifyTxOutProof/${proof}` ) return response.data // Array of hashes. } else if (Array.isArray(proof)) { // Dev note: must use axios.post for unit test stubbing. const response: AxiosResponse = await axios.post( `${this.restURL}blockchain/verifyTxOutProof`, { proofs: proof } ) return response.data } throw new Error(`Input must be a string or array of strings.`) } catch (error) { if (error.response && error.response.data) throw error.response.data else throw error } } }