@mr-zwets/bchn-api-wrapper 1.0.1

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.
Files changed (60) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +129 -0
  3. package/dist/index.d.ts +4 -0
  4. package/dist/index.js +4 -0
  5. package/dist/interfaces/interfaces.d.ts +70 -0
  6. package/dist/interfaces/interfaces.js +1 -0
  7. package/dist/interfaces/restInterfaces/interfaces.d.ts +109 -0
  8. package/dist/interfaces/restInterfaces/interfaces.js +1 -0
  9. package/dist/interfaces/rpcInterfaces/blockchain.d.ts +692 -0
  10. package/dist/interfaces/rpcInterfaces/blockchain.js +3 -0
  11. package/dist/interfaces/rpcInterfaces/control.d.ts +54 -0
  12. package/dist/interfaces/rpcInterfaces/control.js +3 -0
  13. package/dist/interfaces/rpcInterfaces/generating.d.ts +17 -0
  14. package/dist/interfaces/rpcInterfaces/generating.js +3 -0
  15. package/dist/interfaces/rpcInterfaces/index.d.ts +9 -0
  16. package/dist/interfaces/rpcInterfaces/index.js +12 -0
  17. package/dist/interfaces/rpcInterfaces/mining.d.ts +131 -0
  18. package/dist/interfaces/rpcInterfaces/mining.js +3 -0
  19. package/dist/interfaces/rpcInterfaces/network.d.ts +179 -0
  20. package/dist/interfaces/rpcInterfaces/network.js +3 -0
  21. package/dist/interfaces/rpcInterfaces/rawtransactions.d.ts +283 -0
  22. package/dist/interfaces/rpcInterfaces/rawtransactions.js +3 -0
  23. package/dist/interfaces/rpcInterfaces/util.d.ts +44 -0
  24. package/dist/interfaces/rpcInterfaces/util.js +3 -0
  25. package/dist/interfaces/rpcInterfaces/wallet.d.ts +620 -0
  26. package/dist/interfaces/rpcInterfaces/wallet.js +3 -0
  27. package/dist/interfaces/rpcInterfaces/zmq.d.ts +8 -0
  28. package/dist/interfaces/rpcInterfaces/zmq.js +3 -0
  29. package/dist/restClient.d.ts +17 -0
  30. package/dist/restClient.js +100 -0
  31. package/dist/rpcClient.d.ts +12 -0
  32. package/dist/rpcClient.js +85 -0
  33. package/dist/utils/errors.d.ts +3 -0
  34. package/dist/utils/errors.js +6 -0
  35. package/dist/utils/utils.d.ts +11 -0
  36. package/dist/utils/utils.js +49 -0
  37. package/package.json +40 -0
  38. package/src/index.ts +4 -0
  39. package/src/interfaces/interfaces.ts +87 -0
  40. package/src/interfaces/restInterfaces/interfaces.ts +117 -0
  41. package/src/interfaces/rpcInterfaces/blockchain.ts +759 -0
  42. package/src/interfaces/rpcInterfaces/control.ts +62 -0
  43. package/src/interfaces/rpcInterfaces/generating.ts +21 -0
  44. package/src/interfaces/rpcInterfaces/index.ts +14 -0
  45. package/src/interfaces/rpcInterfaces/mining.ts +143 -0
  46. package/src/interfaces/rpcInterfaces/network.ts +195 -0
  47. package/src/interfaces/rpcInterfaces/rawtransactions.ts +314 -0
  48. package/src/interfaces/rpcInterfaces/util.ts +52 -0
  49. package/src/interfaces/rpcInterfaces/wallet.ts +674 -0
  50. package/src/interfaces/rpcInterfaces/zmq.ts +11 -0
  51. package/src/restClient.ts +119 -0
  52. package/src/rpcClient.ts +93 -0
  53. package/src/utils/errors.ts +6 -0
  54. package/src/utils/utils.ts +55 -0
  55. package/test/restClient.test.ts +32 -0
  56. package/test/rpcClient.test.ts +115 -0
  57. package/test/setupTests.ts +54 -0
  58. package/test/tsconfig.json +4 -0
  59. package/tsconfig.json +13 -0
  60. package/vitest.config.ts +9 -0
@@ -0,0 +1,100 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { validateUrl } from "./utils/utils.js";
11
+ export class BchnRestClient {
12
+ constructor(config) {
13
+ var _a, _b;
14
+ this.baseUrl = validateUrl(config.url);
15
+ this.timeoutMs = (_a = config.timeoutMs) !== null && _a !== void 0 ? _a : 5000;
16
+ this.logger = (_b = config.logger) !== null && _b !== void 0 ? _b : console;
17
+ }
18
+ fetchFromNode(endpoint, format) {
19
+ return __awaiter(this, void 0, void 0, function* () {
20
+ try {
21
+ const response = yield fetch(`${this.baseUrl}/rest/${endpoint}`, {
22
+ signal: AbortSignal.timeout(this.timeoutMs),
23
+ });
24
+ if (!response.ok) {
25
+ throw new Error(`Error fetching data from ${endpoint}: ${response.statusText}`);
26
+ }
27
+ if (format === 'json') {
28
+ return yield response.json();
29
+ }
30
+ else {
31
+ return yield response.text(); // For 'bin' and 'hex', return raw text
32
+ }
33
+ }
34
+ catch (error) {
35
+ let errorMessage;
36
+ // Check if the error is due to timeout or other fetch-related issues
37
+ if (typeof error === 'string') {
38
+ errorMessage = error;
39
+ this.logger.error(error);
40
+ }
41
+ else if (error instanceof DOMException && error.name === 'TimeoutError') {
42
+ // If error is an instance DOMException TimeoutError
43
+ errorMessage = 'Request timed out';
44
+ this.logger.error(`Request to ${endpoint} timed out after ${this.timeoutMs} ms`);
45
+ }
46
+ else {
47
+ this.logger.error(`Unknown error occurred during request to ${endpoint}`);
48
+ throw new Error(`Unknown error: ${error}`);
49
+ }
50
+ // Always rethrow the error after logging
51
+ throw new Error(errorMessage);
52
+ }
53
+ });
54
+ }
55
+ // Get transaction details by transaction hash
56
+ getTransaction(txid_1) {
57
+ return __awaiter(this, arguments, void 0, function* (txid, format = 'json') {
58
+ return this.fetchFromNode(`tx/${txid}.${format}`, format);
59
+ });
60
+ }
61
+ // getBlock Implementation
62
+ getBlock(blockhash_1, includeTxDetails_1) {
63
+ return __awaiter(this, arguments, void 0, function* (blockhash, includeTxDetails, format = 'json') {
64
+ const path = includeTxDetails ? 'block' : 'block/notxdetails';
65
+ return this.fetchFromNode(`${path}/${blockhash}.${format}`, format);
66
+ });
67
+ }
68
+ // Get block headers starting from a specific block hash
69
+ getBlockHeaders(count_1, blockhash_1) {
70
+ return __awaiter(this, arguments, void 0, function* (count, blockhash, format = 'json') {
71
+ return this.fetchFromNode(`headers/${count}/${blockhash}.${format}`, format);
72
+ });
73
+ }
74
+ // Get chain info (chain state details)
75
+ getChainInfo() {
76
+ return __awaiter(this, void 0, void 0, function* () {
77
+ return this.fetchFromNode('chaininfo.json', 'json');
78
+ });
79
+ }
80
+ // Query UTXO set based on specific outpoints (txid and vout)
81
+ getUTXOs(checkmempool_1, outpoints_1) {
82
+ return __awaiter(this, arguments, void 0, function* (checkmempool, outpoints, format = 'json') {
83
+ const path = (checkmempool ? 'checkmempool/' : '') + outpoints.join('/');
84
+ const endpoint = `getutxos/${path}.${format}`;
85
+ return this.fetchFromNode(endpoint, format);
86
+ });
87
+ }
88
+ // Get mempool information (basic)
89
+ getMempoolInfo() {
90
+ return __awaiter(this, void 0, void 0, function* () {
91
+ return this.fetchFromNode('mempool/info.json', 'json');
92
+ });
93
+ }
94
+ // Get mempool contents (transactions currently in the mempool)
95
+ getMempoolContents() {
96
+ return __awaiter(this, void 0, void 0, function* () {
97
+ return this.fetchFromNode('mempool/contents.json', 'json');
98
+ });
99
+ }
100
+ }
@@ -0,0 +1,12 @@
1
+ import type { RpcClientConfig, RpcRequest } from "./interfaces/interfaces.js";
2
+ export declare class BchnRpcClient {
3
+ private url;
4
+ private rpcUser;
5
+ private rpcPassword;
6
+ private maxRetries;
7
+ private retryDelayMs;
8
+ private logger;
9
+ private timeoutMs;
10
+ constructor(config: RpcClientConfig);
11
+ request<T extends RpcRequest>(endpoint: T['method'], ...params: T['params']): Promise<T['response']>;
12
+ }
@@ -0,0 +1,85 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { getRandomId, validateAndConstructUrl } from "./utils/utils.js";
11
+ import { RetryLimitExceededError } from "./utils/errors.js";
12
+ export class BchnRpcClient {
13
+ constructor(config) {
14
+ var _a, _b, _c, _d;
15
+ this.url = validateAndConstructUrl(config);
16
+ if (!config.rpcUser)
17
+ throw new Error('Need to provide rpcUser in config');
18
+ if (!config.rpcPassword)
19
+ throw new Error('Need to provide rpcPassword in config');
20
+ this.rpcUser = config.rpcUser;
21
+ this.rpcPassword = config.rpcPassword;
22
+ // optional config
23
+ this.maxRetries = (_a = config.maxRetries) !== null && _a !== void 0 ? _a : 0;
24
+ this.retryDelayMs = (_b = config.retryDelayMs) !== null && _b !== void 0 ? _b : 100;
25
+ this.logger = (_c = config.logger) !== null && _c !== void 0 ? _c : console;
26
+ this.timeoutMs = (_d = config.timeoutMs) !== null && _d !== void 0 ? _d : 5000;
27
+ }
28
+ request(endpoint, ...params) {
29
+ return __awaiter(this, void 0, void 0, function* () {
30
+ var _a;
31
+ const auth = Buffer.from(`${this.rpcUser}:${this.rpcPassword}`).toString('base64');
32
+ // Retry logic
33
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
34
+ try {
35
+ // Send the request with a timeout and retries
36
+ const response = yield fetch(this.url, {
37
+ method: 'POST',
38
+ headers: {
39
+ 'Content-Type': 'application/json',
40
+ 'Authorization': `Basic ${auth}`
41
+ },
42
+ body: JSON.stringify({ jsonrpc: '2.0', method: endpoint, params, id: getRandomId() }),
43
+ signal: AbortSignal.timeout(this.timeoutMs),
44
+ });
45
+ const result = yield response.json();
46
+ // Handle response errors
47
+ if (!response.ok || result.error) {
48
+ throw new Error(`Error: ${((_a = result.error) === null || _a === void 0 ? void 0 : _a.message) || response.statusText}`);
49
+ }
50
+ return result.result; // Return the result if successful
51
+ }
52
+ catch (error) {
53
+ let errorMessage;
54
+ // Check if the error is due to timeout or other fetch-related issues
55
+ if (typeof error == 'string') {
56
+ errorMessage = error;
57
+ this.logger.error(error);
58
+ }
59
+ else if (error instanceof DOMException && error.name === 'TimeoutError') {
60
+ // If error is an instance DOMException TimeoutError
61
+ errorMessage = error.message;
62
+ this.logger.error(`Request timed out after ${this.timeoutMs} ms`);
63
+ }
64
+ else if (error instanceof Error) {
65
+ // If error is an instance of Error, you can safely access its properties
66
+ errorMessage = error.message;
67
+ this.logger.error(`Request failed with error: ${error.message}`);
68
+ }
69
+ // Retry if allowed
70
+ if (attempt < this.maxRetries) {
71
+ this.logger.warn(`Retrying request... (${attempt + 1}/${this.maxRetries})`);
72
+ yield new Promise(res => setTimeout(res, this.retryDelayMs)); // Wait before retrying
73
+ }
74
+ else {
75
+ // If no retries are left, throw the final error
76
+ throw new RetryLimitExceededError(`Request failed after ${this.maxRetries + 1} attempts: ${errorMessage}`);
77
+ }
78
+ }
79
+ }
80
+ // This line ensures TypeScript is satisfied that a value will always be returned, but
81
+ // it should never be reached if the retries fail, as the last attempt should throw an error.
82
+ throw new Error('Request failed unexpectedly');
83
+ });
84
+ }
85
+ }
@@ -0,0 +1,3 @@
1
+ export declare class RetryLimitExceededError extends Error {
2
+ constructor(message: string);
3
+ }
@@ -0,0 +1,6 @@
1
+ export class RetryLimitExceededError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = 'RetryLimitExceededError';
5
+ }
6
+ }
@@ -0,0 +1,11 @@
1
+ import type { RpcClientConfig } from "../interfaces/interfaces.js";
2
+ export declare function getRandomId(): number;
3
+ export declare function validateAndConstructUrl(config: RpcClientConfig): string;
4
+ export declare function validateUrl(url: string): string;
5
+ export declare enum BchnNetworkPort {
6
+ Mainnet = 8332,
7
+ Testnet = 18332,
8
+ Testnet4 = 28332,
9
+ Scalenet = 38332,
10
+ Regtest = 18443
11
+ }
@@ -0,0 +1,49 @@
1
+ export function getRandomId() {
2
+ return Math.floor(Math.random() * 100000);
3
+ }
4
+ // A utility function to validate and construct the URL from the RpcClientConfig object
5
+ export function validateAndConstructUrl(config) {
6
+ let url;
7
+ if (isUrlConfig(config)) {
8
+ url = validateUrl(config.url);
9
+ }
10
+ else if (isHostConfig(config)) {
11
+ const { protocol, host, port } = config;
12
+ if (protocol !== 'http' && protocol !== 'https') {
13
+ throw new Error("Protocol should be 'http' or 'https'");
14
+ }
15
+ url = validateUrl(`${protocol}://${host}:${port}`);
16
+ }
17
+ else {
18
+ throw new Error('Invalid configuration: Either provide the url or protocol/host/port');
19
+ }
20
+ return url;
21
+ }
22
+ // A utility function to validate a URL
23
+ export function validateUrl(url) {
24
+ if (!url)
25
+ throw new Error('URL is required');
26
+ try {
27
+ new URL(url);
28
+ }
29
+ catch (err) {
30
+ throw new Error('Invalid URL format');
31
+ }
32
+ return url;
33
+ }
34
+ // Type guard to check if the config is RpcClientUrlConfig
35
+ function isUrlConfig(config) {
36
+ return 'url' in config;
37
+ }
38
+ // Type guard to check if the config is RpcClientHostConfig
39
+ function isHostConfig(config) {
40
+ return 'protocol' in config && 'hostname' in config && 'port' in config;
41
+ }
42
+ export var BchnNetworkPort;
43
+ (function (BchnNetworkPort) {
44
+ BchnNetworkPort[BchnNetworkPort["Mainnet"] = 8332] = "Mainnet";
45
+ BchnNetworkPort[BchnNetworkPort["Testnet"] = 18332] = "Testnet";
46
+ BchnNetworkPort[BchnNetworkPort["Testnet4"] = 28332] = "Testnet4";
47
+ BchnNetworkPort[BchnNetworkPort["Scalenet"] = 38332] = "Scalenet";
48
+ BchnNetworkPort[BchnNetworkPort["Regtest"] = 18443] = "Regtest";
49
+ })(BchnNetworkPort || (BchnNetworkPort = {}));
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@mr-zwets/bchn-api-wrapper",
3
+ "version": "1.0.1",
4
+ "description": "a Typescript wrapper for interacting with the Bitcoin Cash Node (BCHN) API ",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "author": "mr-zwets",
8
+ "scripts": {
9
+ "build": "tsc",
10
+ "test": "vitest"
11
+ },
12
+ "license": "ISC",
13
+ "devDependencies": {
14
+ "@types/node": "^22.7.7",
15
+ "cross-env": "^7.0.3",
16
+ "msw": "^2.5.1",
17
+ "tsc": "^2.0.4",
18
+ "typescript": "^5.6.3",
19
+ "vitest": "^2.1.3"
20
+ },
21
+ "directories": {
22
+ "test": "test"
23
+ },
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/mr-zwets/bchn-api-wrapper.git"
27
+ },
28
+ "keywords": [
29
+ "bitcoin-cash",
30
+ "bitcoincash",
31
+ "bchn",
32
+ "bitcoind",
33
+ "rpc"
34
+ ],
35
+ "types": "./dist/index.d.ts",
36
+ "bugs": {
37
+ "url": "https://github.com/mr-zwets/bchn-api-wrapper/issues"
38
+ },
39
+ "homepage": "https://github.com/mr-zwets/bchn-api-wrapper#readme"
40
+ }
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from './interfaces/interfaces.js'
2
+ export * from './interfaces/rpcInterfaces/index.js'
3
+ export { BchnRpcClient } from './rpcClient.js'
4
+ export { BchnRestClient } from './restClient.js'
@@ -0,0 +1,87 @@
1
+ export interface BaseRpcClientConfig {
2
+ rpcUser: string;
3
+ rpcPassword: string;
4
+ maxRetries?: number;
5
+ retryDelayMs?: number;
6
+ logger?: typeof console ;
7
+ timeoutMs?: number;
8
+ }
9
+
10
+ export interface RpcClientUrlConfig extends BaseRpcClientConfig {
11
+ url: string;
12
+ }
13
+
14
+ export interface RpcClientHostConfig extends BaseRpcClientConfig {
15
+ protocol: 'http' | 'https';
16
+ host: string;
17
+ port: number;
18
+ }
19
+
20
+ export type RpcClientConfig = RpcClientUrlConfig | RpcClientHostConfig
21
+
22
+ export type RPCParameter = string | number | boolean | undefined | object;
23
+ declare type RequestResponse = object | string | number | boolean | null | RequestResponse[];
24
+
25
+ export interface RpcRequest {
26
+ method: string;
27
+ params: Array<RPCParameter>;
28
+ response: RequestResponse;
29
+ }
30
+
31
+ export interface RestClientConfig {
32
+ url: string;
33
+ logger?: typeof console ;
34
+ timeoutMs?: number;
35
+ }
36
+
37
+
38
+ export type formatOptions = 'bin' | 'hex' | 'json'
39
+
40
+ // Conditional type to return the appropriate data type based on format
41
+ export type ResponseType<TFormat extends formatOptions, TJson> =
42
+ TFormat extends 'json' ? TJson :
43
+ TFormat extends 'hex' | 'bin' ? string :
44
+ never;
45
+
46
+ // General interfaces used in both REST & RPC endpoints
47
+ export interface Transaction {
48
+ txid: string;
49
+ hash: string;
50
+ size: number;
51
+ version: number;
52
+ locktime: number;
53
+ vin: TransactionInput[];
54
+ vout: TransactionOutput[];
55
+ }
56
+
57
+ export interface TransactionInput {
58
+ txid: string;
59
+ vout: number;
60
+ scriptSig: {
61
+ asm: string;
62
+ hex: string;
63
+ };
64
+ sequence: number;
65
+ }
66
+
67
+ export interface TransactionOutput {
68
+ value: number;
69
+ n: number;
70
+ scriptPubKey: {
71
+ asm: string;
72
+ hex: string;
73
+ reqSigs: number;
74
+ type: string;
75
+ addresses: string[];
76
+ tokenData: TokenData;
77
+ }
78
+ }
79
+
80
+ export interface TokenData {
81
+ category : string;
82
+ amount: string;
83
+ nft?: {
84
+ capability: 'none' | 'mutable' | 'minting';
85
+ commitment: string;
86
+ }
87
+ }
@@ -0,0 +1,117 @@
1
+ import type { Transaction } from "../interfaces.js";
2
+
3
+ export interface BlockInfoNoTxDetails {
4
+ hash: string;
5
+ confirmations: number;
6
+ size: number;
7
+ height: number;
8
+ version: number;
9
+ versionHex: string;
10
+ merkleroot: string;
11
+ tx : string[]
12
+ time: number;
13
+ mediantime: number;
14
+ nonce: number;
15
+ bits: string;
16
+ difficulty: number;
17
+ chainwork: string;
18
+ nTx: number;
19
+ previousblockhash: string;
20
+ nextblockhash: string;
21
+ ablastate: {
22
+ epsilon: number;
23
+ beta: number;
24
+ blocksize: number;
25
+ blocksizelimit: number;
26
+ nextblocksizelimit: number;
27
+ }
28
+ }
29
+
30
+ export interface BlockInfoTxDetails extends Omit<BlockInfoNoTxDetails, 'tx'>{
31
+ tx: Transaction[]
32
+ }
33
+
34
+ export interface HeaderInfo {
35
+ hash: string;
36
+ confirmations: number;
37
+ height: number;
38
+ version: number;
39
+ versionHex: string;
40
+ merkleroot: string;
41
+ time: number;
42
+ mediantime: number;
43
+ nonce: number;
44
+ bits: string;
45
+ difficulty: number;
46
+ chainwork: string;
47
+ nTx: number;
48
+ previousblockhash: string;
49
+ nextblockhash: string;
50
+ ablastate: {
51
+ epsilon: number;
52
+ beta: number;
53
+ blocksize: number;
54
+ blocksizelimit: number;
55
+ nextblocksizelimit: number;
56
+ }
57
+ }
58
+
59
+ export interface ChainInfo {
60
+ chain: 'main' | 'test' | 'regtest';
61
+ blocks: number;
62
+ headers: number;
63
+ bestblockhash: string;
64
+ difficulty: number;
65
+ mediantime: number;
66
+ verificationprogress: number;
67
+ initialblockdownload: boolean,
68
+ chainwork: string;
69
+ size_on_disk: number;
70
+ pruned: boolean;
71
+ warnings: string;
72
+ }
73
+
74
+ export interface UtxosInfo {
75
+ chaintipHash: string;
76
+ chainHeight: number;
77
+ utxos: {
78
+ scriptPubKey: {
79
+ addresses: string[];
80
+ type: string;
81
+ hex: string;
82
+ reqSigs: number;
83
+ asm: string;
84
+ },
85
+ value: number
86
+ height: number
87
+ txvers: number
88
+ }[]
89
+ bitmap: string;
90
+ }
91
+
92
+ export interface MempoolInfo {
93
+ loaded: boolean;
94
+ size: number;
95
+ bytes: number;
96
+ usage: number;
97
+ maxmempool: number;
98
+ mempoolminfee: number;
99
+ minrelaytxfee: number;
100
+ }
101
+
102
+ export interface MempoolContent {
103
+ [txid: string]: {
104
+ fees: {
105
+ base: number;
106
+ modified: number;
107
+ },
108
+ size: number;
109
+ time: number;
110
+ depends: string[];
111
+ spentby: string[];
112
+ }
113
+ }
114
+
115
+ export interface TxDetails extends Transaction {
116
+ blockhash: string;
117
+ }