UNPKG

blockbook-client

Version:

Client for interacting with Trezor's blockbook API

572 lines (525 loc) 17.7 kB
import * as t from 'io-ts' import { requiredOptionalCodec, extendCodec, Logger, nullable } from '@bitaccess/ts-common' export type Resolve = (value: any) => void export type Reject = (reason?: any) => void export const Paginated = t.type({ page: t.number, // 1, totalPages: t.number, // 30, itemsOnPage: t.number, // 1000, }, 'Paginated') export type Paginated = t.TypeOf<typeof Paginated> export function paginated<C extends t.Mixed>(c: C) { return t.intersection([Paginated, c]) } export const BlockbookConfig = requiredOptionalCodec( { /** * An array of blockbook nodes to query. Must not be empty. */ nodes: t.array(t.string), }, { /** Logger to use. undefined -> console, null -> disabled */ logger: nullable(Logger), /** * Set true to disable response validation for performance, or use in javascript. * * Default: `false` */ disableTypeValidation: t.boolean, /** Maximum ms to wait for an http or ws request to complete */ requestTimeoutMs: t.number, /** Time to wait before reconnecting after an unexpected disconnect */ reconnectDelayMs: t.number, }, 'BlockbookConfig', ) export type BlockbookConfig = t.TypeOf<typeof BlockbookConfig> /* * Get status */ export const BlockbookInfo = t.type({ coin: t.string, // 'Bitcoin', host: t.string, // 'blockbook', version: t.string, // '0.3.1', gitCommit: t.string, // '3d9ad91', buildTime: t.string, // '2019-05-17T14:34:00+00:00', syncMode: t.boolean, // true, initialSync: t.boolean, // false, inSync: t.boolean, // true, bestHeight: t.number, // 577261, lastBlockTime: t.string, // '2019-05-22T18:03:33.547762973+02:00', inSyncMempool: t.boolean, // true, lastMempoolTime: t.string, // '2019-05-22T18:10:10.27929383+02:00', mempoolSize: t.number, // 17348, decimals: t.number, // 8, dbSize: t.number, // 191887866502, about: t.string, // 'Blockbook - blockchain indexer for ...' }, 'BlockbookInfo') export type BlockbookInfo = t.TypeOf<typeof BlockbookInfo> export const BackendInfo = requiredOptionalCodec( { chain: t.string, // 'main', blocks: t.number, // 577261, bestBlockHash: t.string, // '0000000000000000000ca8c902aa58b3118a7f35d093e25a07f17bcacd91cabf', difficulty: t.string, // '6704632680587.417', version: t.string, // '180000', }, { protocolVersion: t.string, // '70015', subversion: t.string, // '/Satoshi:0.18.0/', sizeOnDisk: t.number, // 250504188580, headers: t.number, // 577261, timeOffset: t.number, // 0, warnings: t.string, // '' }, 'BackendInfo', ) export type BackendInfo = t.TypeOf<typeof BackendInfo> export const SystemInfo = t.type({ blockbook: BlockbookInfo, backend: BackendInfo, }, 'ApiStatus') export type SystemInfo = t.TypeOf<typeof SystemInfo> /** * ws getInfo */ export const SystemInfoWs = t.type( { name: t.string, shortcut: t.string, decimals: t.number, version: t.string, bestHeight: t.number, bestHash: t.string, block0Hash: t.string, testnet: t.boolean, }, 'SystemInfoWs', ) export type SystemInfoWs = t.TypeOf<typeof SystemInfoWs> /* * Get transaction */ /* type Vin struct { Txid string `json:"txid,omitempty"` Vout uint32 `json:"vout,omitempty"` Sequence int64 `json:"sequence,omitempty"` N int `json:"n"` AddrDesc bchain.AddressDescriptor `json:"-"` Addresses []string `json:"addresses,omitempty"` Searchable bool `json:"-"` ValueSat *Amount `json:"value,omitempty"` Hex string `json:"hex,omitempty"` Asm string `json:"asm,omitempty"` Coinbase string `json:"coinbase,omitempty"` } */ export const NormalizedTxCommonVin = requiredOptionalCodec( { n: t.number, // 0 }, { txid: t.string, vout: t.number, sequence: t.number, addresses: t.array(t.string), // ['1DjPjQq4WZwjRvCy6LwdenCu6ynS2m3ob1'] value: t.string, hex: t.string, asm: t.string, coinbase: t.string, // '044c86041b020602' isAddress: t.boolean, // true }, 'NormalizedTxCommonVin' ) /* type Vout struct { ValueSat *Amount `json:"value,omitempty"` N int `json:"n"` Spent bool `json:"spent,omitempty"` SpentTxID string `json:"spentTxId,omitempty"` SpentIndex int `json:"spentIndex,omitempty"` SpentHeight int `json:"spentHeight,omitempty"` Hex string `json:"hex,omitempty"` Asm string `json:"asm,omitempty"` AddrDesc bchain.AddressDescriptor `json:"-"` Addresses []string `json:"addresses"` Searchable bool `json:"-"` Type string `json:"type,omitempty"` } */ export const NormalizedTxCommonVout = requiredOptionalCodec( { n: t.number, // 0 addresses: nullable(t.array(t.string)), // ['362wgRYYj8ybZwuQzxE2PNykjJAwStKARz'] }, { value: t.string, // '1351072' spent: t.boolean, spentTxId: t.string, spentIndex: t.number, spentHeight: t.number, hex: t.string, asm: t.string, type: t.string, isAddress: t.boolean, // true }, 'NormalizedTxCommonVout' ) /* type EthereumSpecific struct { Status int `json:"status"` // 1 OK, 0 Fail, -1 pending Nonce uint64 `json:"nonce"` GasLimit *big.Int `json:"gasLimit"` GasUsed *big.Int `json:"gasUsed"` GasPrice *Amount `json:"gasPrice"` } */ export const EthereumSpecific = t.type({ status: t.number, // 1, nonce: t.number, // 2830, gasLimit: t.number, // 36591, gasUsed: t.number, // 36591, gasPrice: t.string, // '11000000000' }, 'EthereumSpecific') export type EthereumSpecific = t.TypeOf<typeof EthereumSpecific> /* type TokenTransfer struct { Type TokenType `json:"type"` From string `json:"from"` To string `json:"to"` Token string `json:"token"` Name string `json:"name"` Symbol string `json:"symbol"` Decimals int `json:"decimals"` Value *Amount `json:"value"` } */ export const TokenTransfer = t.type({ type: t.string, // 'ERC20', from: t.string, // '0x9c2e011c0ce0d75c2b62b9c5a0ba0a7456593803', to: t.string, // '0x583cbbb8a8443b38abcc0c956bece47340ea1367', token: t.string, // '0xc32ae45504ee9482db99cfa21066a59e877bc0e6', name: t.string, // 'Tangany Test Token', symbol: t.string, // 'TATETO', decimals: t.number, // 18, value: t.string, // '133800000' }, 'TokenTransfer') export type TokenTransfer = t.TypeOf<typeof TokenTransfer> /* type Tx struct { Txid string `json:"txid"` Version int32 `json:"version,omitempty"` Locktime uint32 `json:"lockTime,omitempty"` Vin []Vin `json:"vin"` Vout []Vout `json:"vout"` Blockhash string `json:"blockHash,omitempty"` Blockheight int `json:"blockHeight"` Confirmations uint32 `json:"confirmations"` Blocktime int64 `json:"blockTime"` Size int `json:"size,omitempty"` ValueOutSat *Amount `json:"value"` ValueInSat *Amount `json:"valueIn,omitempty"` FeesSat *Amount `json:"fees,omitempty"` Hex string `json:"hex,omitempty"` CoinSpecificData interface{} `json:"-"` CoinSpecificJSON json.RawMessage `json:"-"` TokenTransfers []TokenTransfer `json:"tokenTransfers,omitempty"` EthereumSpecific *EthereumSpecific `json:"ethereumSpecific,omitempty"` } */ export const NormalizedTxCommon = requiredOptionalCodec( { txid: t.string, // '2266ea441e3fbd144e33dc6c62c0d354d59dc267b48efe9a98a6e2fe6584cbd1' vin: t.array(NormalizedTxCommonVin), vout: t.array(NormalizedTxCommonVout), blockHeight: t.number, // 605482 confirmations: t.number, // 1 blockTime: t.number, // 1574787637 value: t.string, // '2592355' }, { version: t.number, // 2 lockTime: t.number, blockHash: t.string, // '0000000000000000000aac117ba0c0910956020b30e847154311d7d01d50476f' size: t.number, vsize: t.number, valueIn: t.string, fees: t.string, // '302808' hex: t.string, tokenTransfers: t.array(TokenTransfer), ethereumSpecific: EthereumSpecific, }, 'NormalizedTxCommon', ) export type NormalizedTxCommon = t.TypeOf<typeof NormalizedTxCommon> /* * Get block hash */ export const BlockHashResponse = t.type({ blockHash: t.string, // 'ed8f3af8c10ca70a136901c6dd3adf037f0aea8a93fbe9e80939214034300f1e' }, 'BlockHashResponse') export type BlockHashResponse = t.TypeOf<typeof BlockHashResponse> export const BlockHashResponseWs = t.type({ hash: t.string, // 'ed8f3af8c10ca70a136901c6dd3adf037f0aea8a93fbe9e80939214034300f1e' }, 'BlockHashResponseWs') export type BlockHashResponseWs = t.TypeOf<typeof BlockHashResponseWs> /** * subscribeNewBlock */ export const SubscribeNewBlockEvent = t.type({ height: t.number, hash: t.string, }, 'SubscribeNewBlockEvent') export type SubscribeNewBlockEvent = t.TypeOf<typeof SubscribeNewBlockEvent> /** * subscribeAddresses */ export const SubscribeAddressesEvent = t.type({ address: t.string, tx: NormalizedTxCommon, }, 'SubscribeAddressesEvent') export type SubscribeAddressesEvent = t.TypeOf<typeof SubscribeAddressesEvent> /** * Get address */ export const GetAddressDetailsLevels = t.keyof({ basic: null, tokens: null, tokenBalances: null, txids: null, txs: null, }) export type GetAddressDetailsLevels = t.TypeOf<typeof GetAddressDetailsLevels> export const GetAddressDetailsOptions = t.partial({ page: t.number, pageSize: t.number, from: t.number, to: t.number, details: GetAddressDetailsLevels, }) export type GetAddressDetailsOptions = t.TypeOf<typeof GetAddressDetailsOptions> export const TokenDetailsTypeERC20 = t.literal('ERC20') export type TokenDetailsTypeERC20 = t.TypeOf<typeof TokenDetailsTypeERC20> export const TokenDetailsTypeXpubAddress = t.literal('XPUBAddress') export type TokenDetailsTypeXpubAddress = t.TypeOf<typeof TokenDetailsTypeXpubAddress> export const TokenDetailsType = t.union( [ TokenDetailsTypeERC20, TokenDetailsTypeXpubAddress, ], 'TokenDetailsType', ) export type TokenDetailsType = t.TypeOf<typeof TokenDetailsType> /* type Token struct { Type TokenType `json:"type"` Name string `json:"name"` Path string `json:"path,omitempty"` Contract string `json:"contract,omitempty"` Transfers int `json:"transfers"` Symbol string `json:"symbol,omitempty"` Decimals int `json:"decimals,omitempty"` BalanceSat *Amount `json:"balance,omitempty"` TotalReceivedSat *Amount `json:"totalReceived,omitempty"` TotalSentSat *Amount `json:"totalSent,omitempty"` ContractIndex string `json:"-"` } */ export const TokenDetailsCommon = requiredOptionalCodec( { type: TokenDetailsType, name: t.string, transfers: t.number, }, { path: t.string, contract: t.string, symbol: t.string, decimals: t.number, balance: t.string, totalReceived: t.string, totalSent: t.string, }, 'TokenDetailsCommon', ) export type TokenDetailsCommon = t.TypeOf<typeof TokenDetailsCommon> export const TokenDetailsCommonBalance = extendCodec( TokenDetailsCommon, { balance: t.string, }, 'TokenDetailsCommonBalance', ) export type TokenDetailsCommonBalance = t.TypeOf<typeof TokenDetailsCommonBalance> /* type Address struct { Paging AddrStr string `json:"address"` BalanceSat *Amount `json:"balance"` TotalReceivedSat *Amount `json:"totalReceived,omitempty"` TotalSentSat *Amount `json:"totalSent,omitempty"` UnconfirmedBalanceSat *Amount `json:"unconfirmedBalance"` UnconfirmedTxs int `json:"unconfirmedTxs"` Txs int `json:"txs"` NonTokenTxs int `json:"nonTokenTxs,omitempty"` Transactions []*Tx `json:"transactions,omitempty"` Txids []string `json:"txids,omitempty"` Nonce string `json:"nonce,omitempty"` UsedTokens int `json:"usedTokens,omitempty"` Tokens []Token `json:"tokens,omitempty"` Erc20Contract *bchain.Erc20Contract `json:"erc20Contract,omitempty"` } */ export const AddressDetailsCommonBasic = requiredOptionalCodec( { address: t.string, // '1DjPjQq4WZwjRvCy6LwdenCu6ynS2m3ob1', balance: t.string, // '1436057', unconfirmedBalance: t.string, // '0', unconfirmedTxs: t.number, // 0, txs: t.number, // 3, }, { totalReceived: t.string, totalSent: t.string, nonTokenTxs: t.number, nonce: t.string, usedTokens: t.number, erc20Contract: t.any, }, 'AddressDetailsCommonBasic', ) export type AddressDetailsCommonBasic = t.TypeOf<typeof AddressDetailsCommonBasic> export const AddressDetailsCommonTokens = extendCodec( AddressDetailsCommonBasic, { tokens: t.array(TokenDetailsCommon), }, 'AddressDetailsCommonTokens', ) export type AddressDetailsCommonTokens = t.TypeOf<typeof AddressDetailsCommonTokens> export const AddressDetailsCommonTokenBalances = extendCodec( AddressDetailsCommonBasic, {}, { tokens: t.array(TokenDetailsCommonBalance), }, 'AddressDetailsCommonTokenBalances', ) export type AddressDetailsCommonTokenBalances = t.TypeOf<typeof AddressDetailsCommonTokenBalances> export const AddressDetailsCommonTxids = paginated(extendCodec( AddressDetailsCommonTokenBalances, {}, { txids: t.array(t.string), }, 'AddressDetailsCommonTxids', )) export type AddressDetailsCommonTxids = t.TypeOf<typeof AddressDetailsCommonTxids> export const AddressDetailsCommonTxs = paginated(extendCodec( AddressDetailsCommonTokenBalances, {}, { txs: t.array(NormalizedTxCommon), }, 'AddressDetailsCommonTxs', )) export type AddressDetailsCommonTxs = t.TypeOf<typeof AddressDetailsCommonTxs> /** * Get utxos */ export const GetUtxosOptions = t.partial({ confirmed: t.boolean, }, 'GetUtxosOptions') export type GetUtxosOptions = t.TypeOf<typeof GetAddressDetailsOptions> export const UtxoDetails = requiredOptionalCodec( { txid: t.string, // 'a79e396a32e10856c97b95f43da7e9d2b9a11d446f7638dbd75e5e7603128cac', vout: t.number, // 1, value: t.string, // '39748685', confirmations: t.number, // 47, }, { height: t.number, // 2648043, coinbase: t.boolean, // true, lockTime: t.number, // 2648100, }, 'UtxoDetails', ) export type UtxoDetails = t.TypeOf<typeof UtxoDetails> export const UtxoDetailsXpub = extendCodec( UtxoDetails, {}, { address: t.string, // 'DUCd1B3YBiXL5By15yXgSLZtEkvwsgEdqS', path: t.string, // `m/44'/3'/0'/0/0`, }, 'UtxoDetailsXpub', ) export type UtxoDetailsXpub = t.TypeOf<typeof UtxoDetailsXpub> /** * Get block */ export const GetBlockOptions = t.partial({ page: t.number, }, 'GetBlockOptions') export type GetBlockOptions = t.TypeOf<typeof GetBlockOptions> /* type BlockInfo struct { Hash string `json:"hash"` Prev string `json:"previousBlockHash,omitempty"` Next string `json:"nextBlockHash,omitempty"` Height uint32 `json:"height"` Confirmations int `json:"confirmations"` Size int `json:"size"` Time int64 `json:"time,omitempty"` Version json.Number `json:"version"` MerkleRoot string `json:"merkleRoot"` Nonce string `json:"nonce"` Bits string `json:"bits"` Difficulty string `json:"difficulty"` Txids []string `json:"tx,omitempty"` } */ export const BlockInfoCommon = paginated(requiredOptionalCodec( { hash: t.string, // '760f8ed32894ccce9c1ea11c8a019cadaa82bcb434b25c30102dd7e43f326217', height: t.number, // 2648059, confirmations: t.number, // 47, size: t.number, // 951, version: t.number, // 6422787, merkleRoot: t.string, // '6783f6083788c4f69b8af23bd2e4a194cf36ac34d590dfd97e510fe7aebc72c8', nonce: t.string, // '0', bits: t.string, // '1a063f3b', difficulty: t.string, // '2685605.260733312', txCount: t.number, // 2, }, { previousBlockHash: t.string, // '786a1f9f38493d32fd9f9c104d748490a070bc74a83809103bcadd93ae98288f', nextBlockHash: t.string, // '151615691b209de41dda4798a07e62db8429488554077552ccb1c4f8c7e9f57a', time: t.number, // 1553096617, txs: t.array(NormalizedTxCommon), }, 'BlockInfoCommon' )) export type BlockInfoCommon = t.TypeOf<typeof BlockInfoCommon> /** * Send transaction */ export const SendTxSuccess = t.type({ result: t.string, // '7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25' }, 'SendTransactionSuccess') export type SendTxSuccess = t.TypeOf<typeof SendTxSuccess> export const SendTxError = t.type( { error: t.type({ message: t.string, // 'error message' }) }, 'SendTxFailed' ) export type SendTxError = t.TypeOf<typeof SendTxError> export const EstimateFeeResponse = t.type({ result: t.string, }, 'EstimateFeeResponse') export type EstimateFeeResponse = t.TypeOf<typeof EstimateFeeResponse>