@atomicfinance/bitcoin-esplora-api-provider 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/BitcoinEsploraApiProvider.d.ts +52 -0
- package/dist/BitcoinEsploraApiProvider.js +150 -0
- package/dist/BitcoinEsploraApiProvider.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +74 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/lib/BitcoinEsploraApiProvider.ts +226 -0
- package/lib/index.ts +6 -0
- package/lib/types.ts +79 -0
- package/package.json +46 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# @atomicfinance/bitcoin-esplora-api-provider
|
|
2
|
+
|
|
3
|
+
## 3.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- a06082e: Create unified standalone `bitcoin-abstraction-layer` package
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [a06082e]
|
|
12
|
+
- @atomicfinance/types@3.0.0
|
|
13
|
+
- @atomicfinance/bitcoin-utils@3.0.0
|
|
14
|
+
- @atomicfinance/crypto@3.0.0
|
|
15
|
+
- @atomicfinance/errors@3.0.0
|
|
16
|
+
- @atomicfinance/node-provider@3.0.0
|
|
17
|
+
- @atomicfinance/utils@3.0.0
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { NodeProvider } from '@atomicfinance/node-provider';
|
|
2
|
+
import { Address, BigNumber, bitcoin, ChainProvider } from '@atomicfinance/types';
|
|
3
|
+
import { BitcoinNetwork } from 'bitcoin-networks';
|
|
4
|
+
import * as esplora from './types';
|
|
5
|
+
export interface EsploraApiProviderOptions {
|
|
6
|
+
url: string;
|
|
7
|
+
network: BitcoinNetwork;
|
|
8
|
+
numberOfBlockConfirmation?: number;
|
|
9
|
+
defaultFeePerByte?: number;
|
|
10
|
+
}
|
|
11
|
+
export default class BitcoinEsploraApiProvider extends NodeProvider implements Partial<ChainProvider> {
|
|
12
|
+
_network: BitcoinNetwork;
|
|
13
|
+
_numberOfBlockConfirmation: number;
|
|
14
|
+
_defaultFeePerByte: number;
|
|
15
|
+
_usedAddressCache: {
|
|
16
|
+
[index: string]: boolean;
|
|
17
|
+
};
|
|
18
|
+
constructor(options: EsploraApiProviderOptions);
|
|
19
|
+
getFeePerByte(numberOfBlocks?: number): Promise<number>;
|
|
20
|
+
getMinRelayFee(): Promise<number>;
|
|
21
|
+
getBalance(_addresses: (string | Address)[]): Promise<BigNumber>;
|
|
22
|
+
_getUnspentTransactions(address: string): Promise<bitcoin.UTXO[]>;
|
|
23
|
+
getUnspentTransactions(_addresses: (Address | string)[]): Promise<bitcoin.UTXO[]>;
|
|
24
|
+
_getAddressTransactionCount(address: string): Promise<number>;
|
|
25
|
+
getAddressTransactionCounts(_addresses: (Address | string)[]): Promise<any>;
|
|
26
|
+
getTransactionHex(transactionHash: string): Promise<string>;
|
|
27
|
+
getTransaction(transactionHash: string): Promise<import("@atomicfinance/types").Transaction<bitcoin.Transaction>>;
|
|
28
|
+
formatTransaction(tx: esplora.Transaction, currentHeight: number): Promise<import("@atomicfinance/types").Transaction<bitcoin.Transaction>>;
|
|
29
|
+
getBlockByHash(blockHash: string): Promise<{
|
|
30
|
+
hash: any;
|
|
31
|
+
number: any;
|
|
32
|
+
timestamp: any;
|
|
33
|
+
size: any;
|
|
34
|
+
parentHash: any;
|
|
35
|
+
difficulty: any;
|
|
36
|
+
nonce: any;
|
|
37
|
+
}>;
|
|
38
|
+
getBlockHash(blockNumber: number): Promise<string>;
|
|
39
|
+
getBlockByNumber(blockNumber: number): Promise<{
|
|
40
|
+
hash: any;
|
|
41
|
+
number: any;
|
|
42
|
+
timestamp: any;
|
|
43
|
+
size: any;
|
|
44
|
+
parentHash: any;
|
|
45
|
+
difficulty: any;
|
|
46
|
+
nonce: any;
|
|
47
|
+
}>;
|
|
48
|
+
getBlockHeight(): Promise<number>;
|
|
49
|
+
getTransactionByHash(transactionHash: string): Promise<import("@atomicfinance/types").Transaction<bitcoin.Transaction>>;
|
|
50
|
+
getRawTransactionByHash(transactionHash: string): Promise<string>;
|
|
51
|
+
sendRawTransaction(rawTransaction: string): Promise<string>;
|
|
52
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const bitcoin_utils_1 = require("@atomicfinance/bitcoin-utils");
|
|
4
|
+
const errors_1 = require("@atomicfinance/errors");
|
|
5
|
+
const node_provider_1 = require("@atomicfinance/node-provider");
|
|
6
|
+
const types_1 = require("@atomicfinance/types");
|
|
7
|
+
const utils_1 = require("@atomicfinance/utils");
|
|
8
|
+
const lodash_1 = require("lodash");
|
|
9
|
+
class BitcoinEsploraApiProvider extends node_provider_1.NodeProvider {
|
|
10
|
+
constructor(options) {
|
|
11
|
+
const { url, network, numberOfBlockConfirmation = 1, defaultFeePerByte = 3, } = options;
|
|
12
|
+
super({
|
|
13
|
+
baseURL: url,
|
|
14
|
+
responseType: 'text',
|
|
15
|
+
transformResponse: undefined,
|
|
16
|
+
});
|
|
17
|
+
this._network = network;
|
|
18
|
+
this._numberOfBlockConfirmation = numberOfBlockConfirmation;
|
|
19
|
+
this._defaultFeePerByte = defaultFeePerByte;
|
|
20
|
+
this._usedAddressCache = {};
|
|
21
|
+
}
|
|
22
|
+
async getFeePerByte(numberOfBlocks = this._numberOfBlockConfirmation) {
|
|
23
|
+
try {
|
|
24
|
+
const feeEstimates = await this.nodeGet('/fee-estimates');
|
|
25
|
+
const blockOptions = Object.keys(feeEstimates).map((block) => parseInt(block));
|
|
26
|
+
const closestBlockOption = blockOptions.reduce((prev, curr) => {
|
|
27
|
+
return Math.abs(prev - numberOfBlocks) < Math.abs(curr - numberOfBlocks)
|
|
28
|
+
? prev
|
|
29
|
+
: curr;
|
|
30
|
+
});
|
|
31
|
+
const rate = Math.round(feeEstimates[closestBlockOption]);
|
|
32
|
+
return rate;
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
return this._defaultFeePerByte;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async getMinRelayFee() {
|
|
39
|
+
return 1;
|
|
40
|
+
}
|
|
41
|
+
async getBalance(_addresses) {
|
|
42
|
+
const addresses = _addresses.map(utils_1.addressToString);
|
|
43
|
+
const _utxos = await this.getUnspentTransactions(addresses);
|
|
44
|
+
const utxos = lodash_1.flatten(_utxos);
|
|
45
|
+
return utxos.reduce((acc, utxo) => acc.plus(utxo.value), new types_1.BigNumber(0));
|
|
46
|
+
}
|
|
47
|
+
async _getUnspentTransactions(address) {
|
|
48
|
+
const data = await this.nodeGet(`/address/${address}/utxo`);
|
|
49
|
+
return data.map((utxo) => ({
|
|
50
|
+
...utxo,
|
|
51
|
+
address,
|
|
52
|
+
value: utxo.value,
|
|
53
|
+
blockHeight: utxo.status.block_height,
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
async getUnspentTransactions(_addresses) {
|
|
57
|
+
const addresses = _addresses.map(utils_1.addressToString);
|
|
58
|
+
const utxoSets = await Promise.all(addresses.map((addr) => this._getUnspentTransactions(addr)));
|
|
59
|
+
const utxos = lodash_1.flatten(utxoSets);
|
|
60
|
+
return utxos;
|
|
61
|
+
}
|
|
62
|
+
async _getAddressTransactionCount(address) {
|
|
63
|
+
const data = await this.nodeGet(`/address/${address}`);
|
|
64
|
+
return data.chain_stats.tx_count + data.mempool_stats.tx_count;
|
|
65
|
+
}
|
|
66
|
+
async getAddressTransactionCounts(_addresses) {
|
|
67
|
+
const addresses = _addresses.map(utils_1.addressToString);
|
|
68
|
+
const transactionCountsArray = await Promise.all(addresses.map(async (addr) => {
|
|
69
|
+
const txCount = await this._getAddressTransactionCount(addr);
|
|
70
|
+
return { [addr]: txCount };
|
|
71
|
+
}));
|
|
72
|
+
const transactionCounts = Object.assign({}, ...transactionCountsArray);
|
|
73
|
+
return transactionCounts;
|
|
74
|
+
}
|
|
75
|
+
async getTransactionHex(transactionHash) {
|
|
76
|
+
return this.nodeGet(`/tx/${transactionHash}/hex`);
|
|
77
|
+
}
|
|
78
|
+
async getTransaction(transactionHash) {
|
|
79
|
+
let data;
|
|
80
|
+
try {
|
|
81
|
+
data = await this.nodeGet(`/tx/${transactionHash}`);
|
|
82
|
+
}
|
|
83
|
+
catch (e) {
|
|
84
|
+
if (e.name === 'NodeError' &&
|
|
85
|
+
e.message.includes('Transaction not found')) {
|
|
86
|
+
const { name, message, ...attrs } = e;
|
|
87
|
+
throw new errors_1.TxNotFoundError(`Transaction not found: ${transactionHash}`, attrs);
|
|
88
|
+
}
|
|
89
|
+
throw e;
|
|
90
|
+
}
|
|
91
|
+
const currentHeight = await this.getBlockHeight();
|
|
92
|
+
return this.formatTransaction(data, currentHeight);
|
|
93
|
+
}
|
|
94
|
+
async formatTransaction(tx, currentHeight) {
|
|
95
|
+
const hex = await this.getTransactionHex(tx.txid);
|
|
96
|
+
const confirmations = tx.status.confirmed
|
|
97
|
+
? currentHeight - tx.status.block_height + 1
|
|
98
|
+
: 0;
|
|
99
|
+
const decodedTx = bitcoin_utils_1.decodeRawTransaction(hex, this._network);
|
|
100
|
+
decodedTx.confirmations = confirmations;
|
|
101
|
+
return bitcoin_utils_1.normalizeTransactionObject(decodedTx, tx.fee, {
|
|
102
|
+
hash: tx.status.block_hash,
|
|
103
|
+
number: tx.status.block_height,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
async getBlockByHash(blockHash) {
|
|
107
|
+
let data;
|
|
108
|
+
try {
|
|
109
|
+
data = await this.nodeGet(`/block/${blockHash}`);
|
|
110
|
+
}
|
|
111
|
+
catch (e) {
|
|
112
|
+
if (e.name === 'NodeError' && e.message.includes('Block not found')) {
|
|
113
|
+
const { name, message, ...attrs } = e;
|
|
114
|
+
throw new errors_1.BlockNotFoundError(`Block not found: ${blockHash}`, attrs);
|
|
115
|
+
}
|
|
116
|
+
throw e;
|
|
117
|
+
}
|
|
118
|
+
const { id: hash, height: number, timestamp, mediantime, size, previousblockhash: parentHash, difficulty, nonce, } = data;
|
|
119
|
+
return {
|
|
120
|
+
hash,
|
|
121
|
+
number,
|
|
122
|
+
timestamp: mediantime || timestamp,
|
|
123
|
+
size,
|
|
124
|
+
parentHash,
|
|
125
|
+
difficulty,
|
|
126
|
+
nonce,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
async getBlockHash(blockNumber) {
|
|
130
|
+
return this.nodeGet(`/block-height/${blockNumber}`);
|
|
131
|
+
}
|
|
132
|
+
async getBlockByNumber(blockNumber) {
|
|
133
|
+
return this.getBlockByHash(await this.getBlockHash(blockNumber));
|
|
134
|
+
}
|
|
135
|
+
async getBlockHeight() {
|
|
136
|
+
const data = await this.nodeGet('/blocks/tip/height');
|
|
137
|
+
return parseInt(data);
|
|
138
|
+
}
|
|
139
|
+
async getTransactionByHash(transactionHash) {
|
|
140
|
+
return this.getTransaction(transactionHash);
|
|
141
|
+
}
|
|
142
|
+
async getRawTransactionByHash(transactionHash) {
|
|
143
|
+
return this.getTransactionHex(transactionHash);
|
|
144
|
+
}
|
|
145
|
+
async sendRawTransaction(rawTransaction) {
|
|
146
|
+
return this.nodePost('/tx', rawTransaction);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
exports.default = BitcoinEsploraApiProvider;
|
|
150
|
+
//# sourceMappingURL=BitcoinEsploraApiProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BitcoinEsploraApiProvider.js","sourceRoot":"","sources":["../lib/BitcoinEsploraApiProvider.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
10
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
11
|
+
}) : function(o, v) {
|
|
12
|
+
o["default"] = v;
|
|
13
|
+
});
|
|
14
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
15
|
+
if (mod && mod.__esModule) return mod;
|
|
16
|
+
var result = {};
|
|
17
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
18
|
+
__setModuleDefault(result, mod);
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
22
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
|
+
};
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.esplora = exports.BitcoinEsploraApiProvider = void 0;
|
|
26
|
+
const BitcoinEsploraApiProvider_1 = __importDefault(require("./BitcoinEsploraApiProvider"));
|
|
27
|
+
exports.BitcoinEsploraApiProvider = BitcoinEsploraApiProvider_1.default;
|
|
28
|
+
const esplora = __importStar(require("./types"));
|
|
29
|
+
exports.esplora = esplora;
|
|
30
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA,4FAEqC;AAG5B,oCALF,mCAAyB,CAKE;AAFlC,iDAAmC;AAEC,0BAAO"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export declare type FeeEstimates = {
|
|
2
|
+
[index: string]: number;
|
|
3
|
+
};
|
|
4
|
+
export declare type TxStatus = {
|
|
5
|
+
confirmed: boolean;
|
|
6
|
+
block_hash?: string;
|
|
7
|
+
block_height?: number;
|
|
8
|
+
block_time?: number;
|
|
9
|
+
};
|
|
10
|
+
export declare type UTXO = {
|
|
11
|
+
txid: string;
|
|
12
|
+
vout: number;
|
|
13
|
+
status: TxStatus;
|
|
14
|
+
value: number;
|
|
15
|
+
};
|
|
16
|
+
export declare type Address = {
|
|
17
|
+
address: string;
|
|
18
|
+
chain_stats: {
|
|
19
|
+
funded_txo_count: number;
|
|
20
|
+
funded_txo_sum: number;
|
|
21
|
+
spent_txo_count: number;
|
|
22
|
+
spent_txo_sum: number;
|
|
23
|
+
tx_count: number;
|
|
24
|
+
};
|
|
25
|
+
mempool_stats: {
|
|
26
|
+
funded_txo_count: number;
|
|
27
|
+
funded_txo_sum: number;
|
|
28
|
+
spent_txo_count: number;
|
|
29
|
+
spent_txo_sum: number;
|
|
30
|
+
tx_count: number;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
export declare type Vout = {
|
|
34
|
+
scriptpubkey: string;
|
|
35
|
+
scriptpubkey_asm: string;
|
|
36
|
+
scriptpubkey_type: string;
|
|
37
|
+
scriptpubkey_address?: string;
|
|
38
|
+
value: number;
|
|
39
|
+
};
|
|
40
|
+
export declare type Vin = {
|
|
41
|
+
txid: string;
|
|
42
|
+
vout: number;
|
|
43
|
+
prevout: Vout;
|
|
44
|
+
scriptsig: string;
|
|
45
|
+
scriptsig_asm: string;
|
|
46
|
+
is_coinbase: boolean;
|
|
47
|
+
sequence: number;
|
|
48
|
+
};
|
|
49
|
+
export declare type Transaction = {
|
|
50
|
+
txid: string;
|
|
51
|
+
version: number;
|
|
52
|
+
locktime: number;
|
|
53
|
+
vin: Vin[];
|
|
54
|
+
vout: Vout[];
|
|
55
|
+
size: number;
|
|
56
|
+
weight: number;
|
|
57
|
+
fee: number;
|
|
58
|
+
status: TxStatus;
|
|
59
|
+
};
|
|
60
|
+
export declare type Block = {
|
|
61
|
+
id: string;
|
|
62
|
+
height: number;
|
|
63
|
+
version: number;
|
|
64
|
+
timestamp: number;
|
|
65
|
+
tx_count: number;
|
|
66
|
+
size: number;
|
|
67
|
+
weight: number;
|
|
68
|
+
merlke_root: string;
|
|
69
|
+
previousblockhash: string;
|
|
70
|
+
mediantime: number;
|
|
71
|
+
nonce: number;
|
|
72
|
+
bits: number;
|
|
73
|
+
difficulty: number;
|
|
74
|
+
};
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../lib/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import {
|
|
2
|
+
decodeRawTransaction,
|
|
3
|
+
normalizeTransactionObject,
|
|
4
|
+
} from '@atomicfinance/bitcoin-utils';
|
|
5
|
+
import { BlockNotFoundError, TxNotFoundError } from '@atomicfinance/errors';
|
|
6
|
+
import { NodeProvider } from '@atomicfinance/node-provider';
|
|
7
|
+
import {
|
|
8
|
+
Address,
|
|
9
|
+
BigNumber,
|
|
10
|
+
bitcoin,
|
|
11
|
+
ChainProvider,
|
|
12
|
+
} from '@atomicfinance/types';
|
|
13
|
+
import { addressToString } from '@atomicfinance/utils';
|
|
14
|
+
import { BitcoinNetwork } from 'bitcoin-networks';
|
|
15
|
+
import { flatten } from 'lodash';
|
|
16
|
+
|
|
17
|
+
import * as esplora from './types';
|
|
18
|
+
|
|
19
|
+
export interface EsploraApiProviderOptions {
|
|
20
|
+
url: string;
|
|
21
|
+
network: BitcoinNetwork;
|
|
22
|
+
// Default 1
|
|
23
|
+
numberOfBlockConfirmation?: number;
|
|
24
|
+
// Default 3
|
|
25
|
+
defaultFeePerByte?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default class BitcoinEsploraApiProvider
|
|
29
|
+
extends NodeProvider
|
|
30
|
+
implements Partial<ChainProvider> {
|
|
31
|
+
_network: BitcoinNetwork;
|
|
32
|
+
_numberOfBlockConfirmation: number;
|
|
33
|
+
_defaultFeePerByte: number;
|
|
34
|
+
_usedAddressCache: { [index: string]: boolean };
|
|
35
|
+
|
|
36
|
+
constructor(options: EsploraApiProviderOptions) {
|
|
37
|
+
const {
|
|
38
|
+
url,
|
|
39
|
+
network,
|
|
40
|
+
numberOfBlockConfirmation = 1,
|
|
41
|
+
defaultFeePerByte = 3,
|
|
42
|
+
} = options;
|
|
43
|
+
super({
|
|
44
|
+
baseURL: url,
|
|
45
|
+
responseType: 'text',
|
|
46
|
+
transformResponse: undefined, // https://github.com/axios/axios/issues/907,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
this._network = network;
|
|
50
|
+
this._numberOfBlockConfirmation = numberOfBlockConfirmation;
|
|
51
|
+
this._defaultFeePerByte = defaultFeePerByte;
|
|
52
|
+
this._usedAddressCache = {};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async getFeePerByte(numberOfBlocks = this._numberOfBlockConfirmation) {
|
|
56
|
+
try {
|
|
57
|
+
const feeEstimates: esplora.FeeEstimates = await this.nodeGet(
|
|
58
|
+
'/fee-estimates',
|
|
59
|
+
);
|
|
60
|
+
const blockOptions = Object.keys(feeEstimates).map((block) =>
|
|
61
|
+
parseInt(block),
|
|
62
|
+
);
|
|
63
|
+
const closestBlockOption = blockOptions.reduce((prev, curr) => {
|
|
64
|
+
return Math.abs(prev - numberOfBlocks) < Math.abs(curr - numberOfBlocks)
|
|
65
|
+
? prev
|
|
66
|
+
: curr;
|
|
67
|
+
});
|
|
68
|
+
const rate = Math.round(feeEstimates[closestBlockOption]);
|
|
69
|
+
return rate;
|
|
70
|
+
} catch (e) {
|
|
71
|
+
return this._defaultFeePerByte;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async getMinRelayFee() {
|
|
76
|
+
return 1;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async getBalance(_addresses: (string | Address)[]) {
|
|
80
|
+
const addresses = _addresses.map(addressToString);
|
|
81
|
+
const _utxos = await this.getUnspentTransactions(addresses);
|
|
82
|
+
const utxos = flatten(_utxos);
|
|
83
|
+
|
|
84
|
+
return utxos.reduce((acc, utxo) => acc.plus(utxo.value), new BigNumber(0));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async _getUnspentTransactions(address: string): Promise<bitcoin.UTXO[]> {
|
|
88
|
+
const data: esplora.UTXO[] = await this.nodeGet(`/address/${address}/utxo`);
|
|
89
|
+
return data.map((utxo) => ({
|
|
90
|
+
...utxo,
|
|
91
|
+
address,
|
|
92
|
+
value: utxo.value,
|
|
93
|
+
blockHeight: utxo.status.block_height,
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async getUnspentTransactions(
|
|
98
|
+
_addresses: (Address | string)[],
|
|
99
|
+
): Promise<bitcoin.UTXO[]> {
|
|
100
|
+
const addresses = _addresses.map(addressToString);
|
|
101
|
+
const utxoSets = await Promise.all(
|
|
102
|
+
addresses.map((addr) => this._getUnspentTransactions(addr)),
|
|
103
|
+
);
|
|
104
|
+
const utxos = flatten(utxoSets);
|
|
105
|
+
return utxos;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async _getAddressTransactionCount(address: string) {
|
|
109
|
+
const data: esplora.Address = await this.nodeGet(`/address/${address}`);
|
|
110
|
+
return data.chain_stats.tx_count + data.mempool_stats.tx_count;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async getAddressTransactionCounts(_addresses: (Address | string)[]) {
|
|
114
|
+
const addresses = _addresses.map(addressToString);
|
|
115
|
+
const transactionCountsArray = await Promise.all(
|
|
116
|
+
addresses.map(async (addr) => {
|
|
117
|
+
const txCount = await this._getAddressTransactionCount(addr);
|
|
118
|
+
return { [addr]: txCount };
|
|
119
|
+
}),
|
|
120
|
+
);
|
|
121
|
+
const transactionCounts = Object.assign({}, ...transactionCountsArray);
|
|
122
|
+
return transactionCounts;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async getTransactionHex(transactionHash: string): Promise<string> {
|
|
126
|
+
return this.nodeGet(`/tx/${transactionHash}/hex`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async getTransaction(transactionHash: string) {
|
|
130
|
+
let data: esplora.Transaction;
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
data = await this.nodeGet(`/tx/${transactionHash}`);
|
|
134
|
+
} catch (e) {
|
|
135
|
+
if (
|
|
136
|
+
e.name === 'NodeError' &&
|
|
137
|
+
e.message.includes('Transaction not found')
|
|
138
|
+
) {
|
|
139
|
+
const { name, message, ...attrs } = e;
|
|
140
|
+
throw new TxNotFoundError(
|
|
141
|
+
`Transaction not found: ${transactionHash}`,
|
|
142
|
+
attrs,
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
throw e;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const currentHeight = await this.getBlockHeight();
|
|
150
|
+
return this.formatTransaction(data, currentHeight);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async formatTransaction(tx: esplora.Transaction, currentHeight: number) {
|
|
154
|
+
const hex = await this.getTransactionHex(tx.txid);
|
|
155
|
+
const confirmations = tx.status.confirmed
|
|
156
|
+
? currentHeight - tx.status.block_height + 1
|
|
157
|
+
: 0;
|
|
158
|
+
const decodedTx = decodeRawTransaction(hex, this._network);
|
|
159
|
+
decodedTx.confirmations = confirmations;
|
|
160
|
+
return normalizeTransactionObject(decodedTx, tx.fee, {
|
|
161
|
+
hash: tx.status.block_hash,
|
|
162
|
+
number: tx.status.block_height,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async getBlockByHash(blockHash: string) {
|
|
167
|
+
let data;
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
data = await this.nodeGet(`/block/${blockHash}`);
|
|
171
|
+
} catch (e) {
|
|
172
|
+
if (e.name === 'NodeError' && e.message.includes('Block not found')) {
|
|
173
|
+
const { name, message, ...attrs } = e;
|
|
174
|
+
throw new BlockNotFoundError(`Block not found: ${blockHash}`, attrs);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
throw e;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const {
|
|
181
|
+
id: hash,
|
|
182
|
+
height: number,
|
|
183
|
+
timestamp,
|
|
184
|
+
mediantime,
|
|
185
|
+
size,
|
|
186
|
+
previousblockhash: parentHash,
|
|
187
|
+
difficulty,
|
|
188
|
+
nonce,
|
|
189
|
+
} = data;
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
hash,
|
|
193
|
+
number,
|
|
194
|
+
timestamp: mediantime || timestamp,
|
|
195
|
+
size,
|
|
196
|
+
parentHash,
|
|
197
|
+
difficulty,
|
|
198
|
+
nonce,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async getBlockHash(blockNumber: number): Promise<string> {
|
|
203
|
+
return this.nodeGet(`/block-height/${blockNumber}`);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
async getBlockByNumber(blockNumber: number) {
|
|
207
|
+
return this.getBlockByHash(await this.getBlockHash(blockNumber));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async getBlockHeight(): Promise<number> {
|
|
211
|
+
const data = await this.nodeGet('/blocks/tip/height');
|
|
212
|
+
return parseInt(data);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async getTransactionByHash(transactionHash: string) {
|
|
216
|
+
return this.getTransaction(transactionHash);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
async getRawTransactionByHash(transactionHash: string) {
|
|
220
|
+
return this.getTransactionHex(transactionHash);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
async sendRawTransaction(rawTransaction: string): Promise<string> {
|
|
224
|
+
return this.nodePost('/tx', rawTransaction);
|
|
225
|
+
}
|
|
226
|
+
}
|
package/lib/index.ts
ADDED
package/lib/types.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export type FeeEstimates = { [index: string]: number };
|
|
2
|
+
|
|
3
|
+
export type TxStatus = {
|
|
4
|
+
confirmed: boolean;
|
|
5
|
+
block_hash?: string;
|
|
6
|
+
block_height?: number;
|
|
7
|
+
block_time?: number;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type UTXO = {
|
|
11
|
+
txid: string;
|
|
12
|
+
vout: number;
|
|
13
|
+
status: TxStatus;
|
|
14
|
+
value: number;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type Address = {
|
|
18
|
+
address: string;
|
|
19
|
+
chain_stats: {
|
|
20
|
+
funded_txo_count: number;
|
|
21
|
+
funded_txo_sum: number;
|
|
22
|
+
spent_txo_count: number;
|
|
23
|
+
spent_txo_sum: number;
|
|
24
|
+
tx_count: number;
|
|
25
|
+
};
|
|
26
|
+
mempool_stats: {
|
|
27
|
+
funded_txo_count: number;
|
|
28
|
+
funded_txo_sum: number;
|
|
29
|
+
spent_txo_count: number;
|
|
30
|
+
spent_txo_sum: number;
|
|
31
|
+
tx_count: number;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type Vout = {
|
|
36
|
+
scriptpubkey: string;
|
|
37
|
+
scriptpubkey_asm: string;
|
|
38
|
+
scriptpubkey_type: string;
|
|
39
|
+
scriptpubkey_address?: string;
|
|
40
|
+
value: number;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export type Vin = {
|
|
44
|
+
txid: string;
|
|
45
|
+
vout: number;
|
|
46
|
+
prevout: Vout;
|
|
47
|
+
scriptsig: string;
|
|
48
|
+
scriptsig_asm: string;
|
|
49
|
+
is_coinbase: boolean;
|
|
50
|
+
sequence: number;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export type Transaction = {
|
|
54
|
+
txid: string;
|
|
55
|
+
version: number;
|
|
56
|
+
locktime: number;
|
|
57
|
+
vin: Vin[];
|
|
58
|
+
vout: Vout[];
|
|
59
|
+
size: number;
|
|
60
|
+
weight: number;
|
|
61
|
+
fee: number;
|
|
62
|
+
status: TxStatus;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export type Block = {
|
|
66
|
+
id: string;
|
|
67
|
+
height: number;
|
|
68
|
+
version: number;
|
|
69
|
+
timestamp: number;
|
|
70
|
+
tx_count: number;
|
|
71
|
+
size: number;
|
|
72
|
+
weight: number;
|
|
73
|
+
merlke_root: string;
|
|
74
|
+
previousblockhash: string;
|
|
75
|
+
mediantime: number;
|
|
76
|
+
nonce: number;
|
|
77
|
+
bits: number;
|
|
78
|
+
difficulty: number;
|
|
79
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@atomicfinance/bitcoin-esplora-api-provider",
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"module": "dist/index.js",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"directories": {
|
|
8
|
+
"dist": "dist",
|
|
9
|
+
"src": "lib"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"lib"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "../../node_modules/.bin/tsc --project tsconfig.json",
|
|
17
|
+
"test": "../../node_modules/.bin/nyc --reporter=lcov --reporter=text --extension=.ts ../../node_modules/.bin/mocha --recursive \"tests/**/*.test.*\"",
|
|
18
|
+
"lint": "../../node_modules/.bin/eslint --ignore-path ../../.eslintignore -c ../../.eslintrc.js .",
|
|
19
|
+
"lint:fix": "../../node_modules/.bin/eslint --fix --ignore-path ../../.eslintignore -c ../../.eslintrc.js ."
|
|
20
|
+
},
|
|
21
|
+
"author": "Atomic Finance <info@atomic.finance>",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=14"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@atomicfinance/bitcoin-utils": "^3.0.0",
|
|
28
|
+
"@atomicfinance/crypto": "^3.0.0",
|
|
29
|
+
"@atomicfinance/errors": "^3.0.0",
|
|
30
|
+
"@atomicfinance/node-provider": "^3.0.0",
|
|
31
|
+
"@atomicfinance/types": "^3.0.0",
|
|
32
|
+
"@atomicfinance/utils": "^3.0.0",
|
|
33
|
+
"@babel/runtime": "^7.12.1",
|
|
34
|
+
"bignumber.js": "^9.0.0",
|
|
35
|
+
"bitcoin-networks": "^1.0.0",
|
|
36
|
+
"lodash": "^4.17.20"
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/lodash": "^4.14.168",
|
|
43
|
+
"nock": "^13.0.11"
|
|
44
|
+
},
|
|
45
|
+
"sideEffects": false
|
|
46
|
+
}
|