import axios from "axios" ; import { BitcoinAPI , DEFAULT_TIMEOUT , sortUTXOs , UTXO } from "./API" ; export class Blockstream implements BitcoinAPI { public testnet : boolean ; public apiKey : string | undefined ; public constructor ( { testnet = false , apiKey = undefined } = { } ) { this . testnet = testnet ; this . apiKey = apiKey ; } public getAPIUrl ( path ) { return `https://blockstream.info/${ this . testnet ? "testnet/" : "" }api${ path }${ this . apiKey ? `?key=${ this . apiKey }` : "" }` ; } public async fetchHeight ( ) { return ( await axios . get < string > ( this . getAPIUrl ( `/blocks/tip/height` ) , { timeout : DEFAULT_TIMEOUT , } ) ) . data . toString ( ) ; } public async fetchUTXO ( txid , txindex ) { const utxo = ( await axios . get < BlockstreamTX > ( this . getAPIUrl ( `/tx/${ txid }` ) , { timeout : DEFAULT_TIMEOUT , } ) ) . data ; return { txid , amount : utxo . vout [ parseInt ( txindex , 10 ) ] . value . toString ( ) , txindex , height : utxo . status . confirmed ? utxo . status . block_height . toString ( ) : null , } ; } public async fetchUTXOs ( address ) { const response = await axios . get < BlockstreamUTXO [ ] > ( this . getAPIUrl ( `/address/${ address }/utxo` ) , { timeout : DEFAULT_TIMEOUT } ) ; return response . data . map ( ( utxo ) => ( { txid : utxo . txid , amount : utxo . value . toString ( ) , txindex : utxo . vout . toString ( ) , height : utxo . status . confirmed ? utxo . status . block_height . toString ( ) : null , } ) ) . sort ( sortUTXOs ) ; } public async fetchTXs ( address ) { const response = await axios . get < BlockstreamTX [ ] > ( this . getAPIUrl ( `/address/${ address }/txs` ) , { timeout : DEFAULT_TIMEOUT } ) ; const received = [ ] ; for ( const tx of response . data ) { for ( let i = 0 ; i < tx . vout . length ; i ++ ) { const vout = tx . vout [ i ] ; if ( vout . scriptpubkey_address === address ) { received . push ( { txid : tx . txid , amount : vout . value . toString ( ) , txindex : i . toString ( ) , height : tx . status . confirmed ? tx . status . block_height . toString ( ) : null , } ) ; } } } return received . sort ( sortUTXOs ) ; } public async broadcastTransaction ( txHex ) { const response = await axios . post < string > ( this . getAPIUrl ( `/tx` ) , txHex , { timeout : DEFAULT_TIMEOUT , } ) ; return response . data ; } } interface BlockstreamUTXO < vout = number > { status : { confirmed : false ; } | { confirmed : true ; block_height : number ; block_hash : string ; block_time : number ; } ; txid : string ; value : number ; vout : vout ; } interface BlockstreamTX extends BlockstreamUTXO < Array < { scriptpubkey : string ; scriptpubkey_asm : string ; scriptpubkey_type : string ; scriptpubkey_address : string ; value : number ; } > > { version : number ; locktime : number ; vin : Array < { txid : string ; vout : number ; prevout : unknown ; scriptsig : string ; scriptsig_asm : string ; is_coinbase : false ; sequence : number ; } > ; size : number ; weight : number ; fee : number ; }