Haskoin
- provider
- create("haskoin")
- auth
- none
- chains
- Bitcoin Cash
- capabilities
- balance, history, tx detail, utxos, block
- endpoint
- api.haskoin.com/bch
- default chain
- bitcoincash
Address it
import { Haskoin } from "@agntn/explorers/providers/haskoin";
const bch = new Haskoin(); // or create("haskoin")
await bch.getBalance("bitcoincash:qz3yjg59ypg6jqpwhaxgvjj44jm4hdx0w5wsxw2qez", "bitcoincash");
await bch.getTxHistory("bitcoincash:qz3yjg59ypg6jqpwhaxgvjj44jm4hdx0w5wsxw2qez", "bitcoincash", {
limit: 10,
});
One chain, no key. Haskoin Store is an indexer written in Haskell, and api.haskoin.com runs a public instance of it for Bitcoin Cash. baseUrl is the network root, https://api.haskoin.com/bch by default. Before it, Bitcoin Cash had Blockchair and nothing else, and keyless Blockchair blocks an IP after a handful of reads. Now automatic selection starts on Haskoin, and with BLOCKCHAIR_API_KEY set it starts on Blockchair and falls back here. Any other chain is an UnsupportedChainError.
What it reads
| Operation | Route |
|---|---|
| balance | /address/{address}/balance |
| history | /address/{address}/transactions/full |
| one transaction | /transaction/{txid} |
| unspent outputs | /address/{address}/unspent |
| block | /block/height/{height} |
No gas and no tokens. Haskoin keeps no fee estimates at all.
Gotchas
- CashAddr only, with or without the
bitcoincash:prefix. A legacy1...address fails before a request goes out. Haskoin itself would take it, but@agntn/chainsdoesn't, and that's the check every provider here goes through. Blockchair takes the legacy form, so ask it with-p blockchair. - Every input comes with the address and the amount it spends. So the sender and the fee arrive with the transaction itself, no parent lookups like on WhatsOnChain.
- Seen from an address, a transaction is a send when one of its inputs spent from that address. Then
valueis what went to everyone else andtois the first of them. Otherwise it's a receive andvalueis what landed on the address. - History comes newest first and only that way, so
sort: "asc"throws. Haskoin bounds a listing from above only:endBlockgoes out asheight, andstartBlockthrows instead of being ignored. limitup to 100, andpageturns into anoffset. The public instance refuses an offset above 50000, so a page that deep throws before the request.- Balance splits differently from Mempool.
balanceis Haskoin'sconfirmed: confirmed outputs that nothing spends yet, and a spend still in the mempool already counts.unconfirmedis the unspent outputs still waiting in the mempool, never negative. The two add up to what the address holds once the mempool confirms.fundedis everything ever received,spentis the rest. - No block height on a balance, the endpoint doesn't send one, so
blockNumberstays null. - A transaction still in the mempool reads as
pendingat block 0. One Haskoin marks as deleted, pushed out by a double spend or a reorg, reads asfailed. - Unspent outputs come in pages of 1000, ten pages at most. The height comes along, the block hash doesn't, so
blockHashstays null. /block/height/{height}lists every block seen at that height, orphans too. The provider takes the main chain one. Past the tip the list is empty and that's aNotFoundError. The request skipsnotx, because without the list of transactions there's nothing to count.- A missing transaction or address is a 404, so
NotFoundError. A 400 carries its reason inmessage, and that reason travels in a plainExplorerError. - OP_RETURN outputs have no address and never become the recipient. Their payloads stay in
raw, not decoded intoopReturn. - A block has an empty
minerand gas fields of"0", like every other chain without gas.
Where it lives
src/providers/haskoin.ts.
Blockbook
Bitcoin Gold through the Blockbook API of btgexplorer.com. Balances, history, unspent outputs, transactions and blocks. Satoshis, no key.
Chains
The 29 chains the built-in providers serve. Which provider answers for each and which operations any of them cover. Read from the registry and not typed in.