bitbox-sdk
Version:
BITBOX SDK for Bitcoin Cash
368 lines (324 loc) • 10.6 kB
text/typescript
/*
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<string> {
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<BlockDetailsResult> {
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<BlockchainInfoResult> {
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<number> {
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<string> {
// 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<BlockHeaderResult | BlockHeaderResult[]> {
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<ChainTipResult[]> {
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<number> {
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<string[] | MempoolEntryResult[]> {
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<string[] | MempoolEntryResult[]> {
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<MempoolEntryResult> {
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<MempoolInfoResult> {
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<string[]> {
// 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<TxOutResult | null> {
// 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<string | string[]> {
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<any> {
// 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<number> {
// 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<boolean> {
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<string[]> {
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
}
}
}