├── .gitignore ├── LICENSE ├── README.md ├── dist ├── api-client.d.ts ├── api-client.js ├── basic.html ├── browserdemo.html ├── index.d.ts ├── index.js └── mattercloud.js ├── gulpfile.js ├── header.png ├── lib ├── api-client.ts ├── examples │ └── browserdemo.html └── index.ts ├── package-lock.json ├── package.json ├── test ├── address.js ├── mapi.js ├── minercraft.js ├── mocha.opts ├── script.js ├── sse.js └── transaction.js └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | npm-debug.log* 4 | yarn-debug.log* 5 | yarn-error.log* 6 | /test/e2e/reports/ 7 | selenium-debug.log 8 | 9 | # Editor directories and files 10 | .idea 11 | .vscode 12 | *.suo 13 | *.ntvs* 14 | *.njsproj 15 | *.sln 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Open BSV License 2 | Copyright (c) 2019 MatterCloud (Matter Web Services Inc.) 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | 1 - The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 2 - The Software, and any software that is derived from the Software or parts thereof, 14 | can only be used on the Bitcoin SV blockchains. The Bitcoin SV blockchains are defined, 15 | for purposes of this license, as the Bitcoin blockchain containing block height #556767 16 | with the hash "000000000000000001d956714215d96ffc00e0afda4cd0a96c96f8d802b1662b" and 17 | the test blockchains that are supported by the un-modified Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MatterCloud Javascript Library 2 | > Bitcoin SV and Metanet API for Developers 3 | > [MatterCloud.net](https://www.MatterCloud.net) 4 | 5 | *Replaces [BitIndex SDK](https://github.com/bitindex/bitindex-sdk)* 6 | 7 | ![header](header.png) 8 | 9 | [VIEW COMPLETE DEVELOPER DOCUMENTATION](https://developers.mattercloud.net) 10 | 11 | --- 12 | 13 | ## Quick Start 14 | 15 | _Small < 24KB library size_ 16 | **Installation** 17 | ```sh 18 | npm install mattercloudjs --save 19 | ``` 20 | 21 | **Include** 22 | 23 | [Generate an API key](https://www.mattercloud.net/#get-api-key) 24 | 25 | ```javascript 26 | // NodeJS 27 | var options = { 28 | api_key: "your api key", 29 | } 30 | var mattercloud = require('mattercloudjs').instance(options); 31 | 32 | // Or set API key later 33 | mattercloud.setApiKey("your api key"); 34 | ``` 35 | 36 | ## Preview 37 | 38 | Easily query balances, utxos, and transactions on the Bitcoin SV Blockchain. 39 | 40 | #### Get balance 41 | 42 | ```javascript 43 | var result = await mattercloud.getBalance('12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX'); 44 | ``` 45 | 46 | GET https://api.mattercloud.net/api/v3/main/address/12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX/balance 47 | 48 | Response: 49 | ``` 50 | { 51 | "address": "12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX", 52 | "confirmed": 30055, 53 | "unconfirmed": 0 54 | } 55 | ``` 56 | #### Get utxos 57 | 58 | ```javascript 59 | var result = await mattercloud.getUtxos('12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX'); 60 | ``` 61 | 62 | GET https://api.mattercloud.net/api/v3/main/address/12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX/utxo 63 | 64 | Response: 65 | ``` 66 | [ 67 | { 68 | "address": "12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX", 69 | "txid": "5e3014372338f079f005eedc85359e4d96b8440e7dbeb8c35c4182e0c19a1a12", 70 | "vout": 0, 71 | "amount": 0.00015399, 72 | "satoshis": 15399, 73 | "value": 15399, 74 | "height": 576168, 75 | "confirmations": 34730, 76 | "scriptPubKey": "76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac", 77 | "script": "76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac", 78 | "outputIndex": 0 79 | } 80 | ] 81 | ``` 82 | 83 | [VIEW COMPLETE DEVELOPER DOCUMENTATION](https://developers.mattercloud.net) 84 | 85 | ## Detailed Installation and Usage 86 | 87 | **Installation** 88 | ```sh 89 | npm install mattercloudjs --save 90 | ``` 91 | 92 | **Include** 93 | ```javascript 94 | // Node 95 | var options = { 96 | api_key: "your api key", 97 | } 98 | var mattercloud = require('mattercloudjs').instance(options); 99 | 100 | ``` 101 | 102 | ```html 103 | 104 | 105 | 110 | ``` 111 | See browser usage examples: https://github.com/MatterCloud/mattercloudjs/blob/master/dist/basic.html 112 | 113 | ### Promises vs. Callback 114 | 115 | Both `await` and callback styles are supported for all methods. 116 | 117 | Example: 118 | 119 | ```javascript 120 | 121 | // Await style with promises 122 | var result = await mattercloud.getUtxos('12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX'); 123 | 124 | // Callback style 125 | mattercloud.getUtxos('12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX', function(result) { 126 | // ... 127 | }); 128 | 129 | ``` 130 | 131 | ## Detailed Documentation 132 | 133 | [VIEW COMPLETE DEVELOPER DOCUMENTATION](https://developers.mattercloud.net) 134 | 135 | 136 | ## Build and Test 137 | 138 | ``` 139 | npm install 140 | npm run build 141 | npm run test 142 | ``` 143 | 144 | ----------- 145 | 146 | 147 | ## Any questions or ideas? 148 | 149 | We would love to hear from you! 150 | 151 | https://www.mattercloud.net 152 | 153 | https://twitter.com/MatterCloud 154 | 155 | 156 | -------------------------------------------------------------------------------- /dist/api-client.d.ts: -------------------------------------------------------------------------------- 1 | export interface MatterCloudApiClientOptions { 2 | api_url: string; 3 | merchantapi_url: string; 4 | api_key?: string; 5 | network: string; 6 | version_path: string; 7 | } 8 | /** 9 | * API Client 10 | */ 11 | export declare class APIClient { 12 | options: MatterCloudApiClientOptions; 13 | fullUrl: any; 14 | minerFullUrl: any; 15 | constructor(options: any); 16 | getHeaders(): any; 17 | /** 18 | * Resolve a promise and/or invoke a callback 19 | * @param resolve Resolve function to call when done 20 | * @param data Data to pass forward 21 | * @param callback Invoke an optional callback first 22 | */ 23 | private resolveOrCallback; 24 | /** 25 | * Resolve a promise and/or invoke a callback 26 | * @param reject Reject function to call when done 27 | * @param data Data to pass forward 28 | * @param callback Invoke an optional callback first 29 | */ 30 | private rejectOrCallback; 31 | private formatErrorResponse; 32 | tx_getTransaction(txid: string, callback?: Function): Promise; 33 | tx_getRawTransaction(txid: string, callback?: Function): Promise; 34 | tx_getTransactionsBatch(txids: string[], callback?: Function): Promise; 35 | address_getBalance(addr: any, callback?: Function): Promise; 36 | address_getHistory(addr: any, options?: { 37 | from?: number; 38 | to?: number; 39 | }, callback?: Function): Promise; 40 | address_getBalanceBatch(addrs: string[], callback?: Function): Promise; 41 | address_getHistoryBatch(addrs: string[], options?: { 42 | from?: number; 43 | to?: number; 44 | }, callback?: Function): Promise; 45 | private isStringOrNonEmptyArray; 46 | scripthash_getHistory(scripthash: any, options?: { 47 | from?: number; 48 | to?: number; 49 | }, callback?: Function): Promise; 50 | scripthash_getUtxos(args: { 51 | scripthash: any; 52 | }, callback?: Function): Promise; 53 | addresses_getUtxos(args: { 54 | addrs: any; 55 | offset?: number; 56 | limit?: number; 57 | afterHeight?: number; 58 | sort?: string; 59 | }, callback?: Function): Promise; 60 | sendRawTx(rawtx: string, callback?: Function): Promise; 61 | merchants_broadcastTx(rawtx: string, callback?: Function): Promise; 62 | merchants_statusTx(txid: string, callback?: Function): Promise; 63 | mapi_submitTx(rawtx: string, callback?: Function): Promise; 64 | mapi_statusTx(txid: string, callback?: Function): Promise; 65 | mapi_feeQuote(callback?: Function): Promise; 66 | } 67 | -------------------------------------------------------------------------------- /dist/api-client.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const axios_1 = require("axios"); 4 | const defaultOptions = { 5 | api_url: 'https://api.mattercloud.net', 6 | merchantapi_url: 'https://merchantapi.matterpool.io', 7 | network: 'main', 8 | version_path: 'api/v3', 9 | }; 10 | /** 11 | * API Client 12 | */ 13 | class APIClient { 14 | constructor(options) { 15 | this.options = defaultOptions; 16 | this.options = Object.assign({}, this.options, options); 17 | this.fullUrl = `${this.options.api_url}/${this.options.version_path}/${this.options.network}`; 18 | this.minerFullUrl = `${this.options.merchantapi_url}/mapi`; 19 | } 20 | // Populate api reqest header if it's set 21 | getHeaders() { 22 | if (this.options.api_key && this.options.api_key !== '') { 23 | return { 24 | api_key: this.options.api_key, 25 | 'Content-Type': 'application/json', 26 | }; 27 | } 28 | return { 29 | 'Content-Type': 'application/json', 30 | }; 31 | } 32 | /** 33 | * Resolve a promise and/or invoke a callback 34 | * @param resolve Resolve function to call when done 35 | * @param data Data to pass forward 36 | * @param callback Invoke an optional callback first 37 | */ 38 | resolveOrCallback(resolve, data, callback) { 39 | if (callback) { 40 | callback(data); 41 | return undefined; 42 | } 43 | if (resolve) { 44 | return resolve(data); 45 | } 46 | return new Promise((r, reject) => { 47 | return r(data); 48 | }); 49 | } 50 | /** 51 | * Resolve a promise and/or invoke a callback 52 | * @param reject Reject function to call when done 53 | * @param data Data to pass forward 54 | * @param callback Invoke an optional callback first 55 | */ 56 | rejectOrCallback(reject, err, callback) { 57 | if (callback) { 58 | callback(null, err); 59 | return; 60 | } 61 | if (reject) { 62 | return reject(err); 63 | } 64 | return new Promise((resolve, r) => { 65 | r(err); 66 | }); 67 | } 68 | formatErrorResponse(r) { 69 | // let getMessage = r && r.response && r.response.data ? r.response.data : r.toString(); 70 | let getMessage = r && r.response && r.response.data ? r.response.data : r; 71 | return Object.assign(Object.assign({}, getMessage), { success: getMessage.success ? getMessage.success : false, code: getMessage.code ? getMessage.code : -1, message: getMessage.message ? getMessage.message : '', error: getMessage.error ? getMessage.error : '' }); 72 | } 73 | tx_getTransaction(txid, callback) { 74 | return new Promise((resolve, reject) => { 75 | if (!txid || /^(\s*)$/.test(txid)) { 76 | return this.rejectOrCallback(reject, this.formatErrorResponse({ 77 | code: 422, 78 | message: 'txid required' 79 | }), callback); 80 | } 81 | axios_1.default.get(this.fullUrl + `/tx/${txid}`, { 82 | headers: this.getHeaders() 83 | }).then((response) => { 84 | return this.resolveOrCallback(resolve, response.data, callback); 85 | }).catch((ex) => { 86 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback); 87 | }); 88 | }); 89 | } 90 | tx_getRawTransaction(txid, callback) { 91 | return new Promise((resolve, reject) => { 92 | if (!txid || /^(\s*)$/.test(txid)) { 93 | return this.rejectOrCallback(reject, this.formatErrorResponse({ 94 | code: 422, 95 | message: 'txid required' 96 | }), callback); 97 | } 98 | axios_1.default.get(this.fullUrl + `/rawtx/${txid}`, { 99 | headers: this.getHeaders() 100 | }).then((response) => { 101 | if (response.data && response.data.rawtx) { 102 | return this.resolveOrCallback(resolve, response.data.rawtx, callback); 103 | } 104 | return this.resolveOrCallback(resolve, response.data, callback); 105 | }).catch((ex) => { 106 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback); 107 | }); 108 | }); 109 | } 110 | tx_getTransactionsBatch(txids, callback) { 111 | return new Promise((resolve, reject) => { 112 | if (!this.isStringOrNonEmptyArray(txids)) { 113 | return this.rejectOrCallback(reject, this.formatErrorResponse({ 114 | code: 422, 115 | message: 'txid required' 116 | }), callback); 117 | } 118 | let payload = { 119 | txids: Array.isArray(txids) ? txids.join(',') : txids 120 | }; 121 | axios_1.default.post(this.fullUrl + `/tx`, payload, { 122 | headers: this.getHeaders() 123 | }).then((response) => { 124 | return this.resolveOrCallback(resolve, response.data, callback); 125 | }).catch((ex) => { 126 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback); 127 | }); 128 | }); 129 | } 130 | address_getBalance(addr, callback) { 131 | return new Promise((resolve, reject) => { 132 | if (!this.isStringOrNonEmptyArray(addr)) { 133 | return this.rejectOrCallback(reject, this.formatErrorResponse({ 134 | code: 422, 135 | message: 'address required' 136 | }), callback); 137 | } 138 | axios_1.default.get(this.fullUrl + `/address/${addr}/balance`, { 139 | headers: this.getHeaders() 140 | }).then((response) => { 141 | return this.resolveOrCallback(resolve, response.data, callback); 142 | }).catch((ex) => { 143 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback); 144 | }); 145 | }); 146 | } 147 | address_getHistory(addr, options, callback) { 148 | return new Promise((resolve, reject) => { 149 | if (!this.isStringOrNonEmptyArray(addr)) { 150 | return this.rejectOrCallback(reject, this.formatErrorResponse({ 151 | code: 422, 152 | message: 'address required' 153 | }), callback); 154 | } 155 | let args = ''; 156 | if (options && options.from) { 157 | args += `from=${options.from}&`; 158 | } 159 | if (options && options.to) { 160 | args += `to=${options.to}&`; 161 | } 162 | const url = this.fullUrl + `/address/${addr}/history?${args}`; 163 | axios_1.default.get(url, { 164 | headers: this.getHeaders() 165 | }).then((response) => { 166 | return this.resolveOrCallback(resolve, response.data, callback); 167 | }).catch((ex) => { 168 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback); 169 | }); 170 | }); 171 | } 172 | address_getBalanceBatch(addrs, callback) { 173 | return new Promise((resolve, reject) => { 174 | if (!this.isStringOrNonEmptyArray(addrs)) { 175 | return this.rejectOrCallback(reject, this.formatErrorResponse({ 176 | code: 422, 177 | message: 'address required' 178 | }), callback); 179 | } 180 | let addrsNew = []; 181 | if (!Array.isArray(addrs)) { 182 | addrsNew.push(addrs); 183 | } 184 | else { 185 | addrsNew = addrs; 186 | } 187 | let payload = { 188 | addrs: Array.isArray(addrsNew) ? addrsNew.join(',') : addrsNew 189 | }; 190 | axios_1.default.post(this.fullUrl + `/address/balance`, payload, { 191 | headers: this.getHeaders() 192 | }).then((response) => { 193 | return this.resolveOrCallback(resolve, response.data, callback); 194 | }).catch((ex) => { 195 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback); 196 | }); 197 | }); 198 | } 199 | address_getHistoryBatch(addrs, options, callback) { 200 | return new Promise((resolve, reject) => { 201 | if (!this.isStringOrNonEmptyArray(addrs)) { 202 | return this.rejectOrCallback(reject, this.formatErrorResponse({ 203 | code: 422, 204 | message: 'address required' 205 | }), callback); 206 | } 207 | let addrsNew = []; 208 | if (!Array.isArray(addrs)) { 209 | addrsNew.push(addrs); 210 | } 211 | else { 212 | addrsNew = addrs; 213 | } 214 | let payload = { 215 | addrs: Array.isArray(addrsNew) ? addrsNew.join(',') : addrsNew 216 | }; 217 | if (options && options.from) { 218 | payload.from = options.from; 219 | } 220 | if (options && options.from) { 221 | payload.to = options.to; 222 | } 223 | axios_1.default.post(this.fullUrl + `/address/history`, payload, { 224 | headers: this.getHeaders() 225 | }).then((response) => { 226 | return this.resolveOrCallback(resolve, response.data, callback); 227 | }).catch((ex) => { 228 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback); 229 | }); 230 | }); 231 | } 232 | isStringOrNonEmptyArray(item) { 233 | if (!item) { 234 | return false; 235 | } 236 | if (Array.isArray(item) && !item.length) { 237 | return false; 238 | } 239 | return true; 240 | } 241 | scripthash_getHistory(scripthash, options, callback) { 242 | return new Promise((resolve, reject) => { 243 | if (!this.isStringOrNonEmptyArray(scripthash)) { 244 | return this.rejectOrCallback(reject, this.formatErrorResponse({ 245 | code: 422, 246 | message: 'scripthash required' 247 | }), callback); 248 | } 249 | let args = ''; 250 | if (options && options.from) { 251 | args += `from=${options.from}&`; 252 | } 253 | if (options && options.to) { 254 | args += `to=${options.to}&`; 255 | } 256 | const url = this.fullUrl + `/scripthash/${scripthash}/history?${args}`; 257 | axios_1.default.get(url, { 258 | headers: this.getHeaders() 259 | }).then((response) => { 260 | return this.resolveOrCallback(resolve, response.data, callback); 261 | }).catch((ex) => { 262 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback); 263 | }); 264 | }); 265 | } 266 | scripthash_getUtxos(args, callback) { 267 | return new Promise((resolve, reject) => { 268 | if (!this.isStringOrNonEmptyArray(args.scripthash)) { 269 | return this.rejectOrCallback(reject, this.formatErrorResponse({ 270 | code: 422, 271 | message: 'scripthash required', 272 | error: 'scripthash required' 273 | }), callback); 274 | } 275 | let scripthashes = []; 276 | if (!Array.isArray(args.scripthash)) { 277 | scripthashes.push(args.scripthash); 278 | } 279 | else { 280 | scripthashes = args.scripthash; 281 | } 282 | let payload = { 283 | scripthash: Array.isArray(scripthashes) ? scripthashes.join(',') : scripthashes 284 | }; 285 | axios_1.default.post(this.fullUrl + `/scripthash/utxo`, payload, { 286 | headers: this.getHeaders() 287 | }).then((response) => { 288 | return this.resolveOrCallback(resolve, response.data, callback); 289 | }).catch((ex) => { 290 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback); 291 | }); 292 | }); 293 | } 294 | addresses_getUtxos(args, callback) { 295 | return new Promise((resolve, reject) => { 296 | if (!this.isStringOrNonEmptyArray(args.addrs)) { 297 | return this.rejectOrCallback(reject, this.formatErrorResponse({ 298 | code: 422, 299 | message: 'address required' 300 | }), callback); 301 | } 302 | let addrs = []; 303 | if (!Array.isArray(args.addrs)) { 304 | addrs.push(args.addrs); 305 | } 306 | else { 307 | addrs = args.addrs; 308 | } 309 | let payload = { 310 | addrs: Array.isArray(addrs) ? addrs.join(',') : addrs 311 | }; 312 | if (args.offset) { 313 | payload.offset = args.offset; 314 | } 315 | if (args.limit) { 316 | payload.limit = args.limit; 317 | } 318 | if (args.afterHeight) { 319 | payload.afterHeight = args.afterHeight; 320 | } 321 | if (args.sort) { 322 | payload.sort = args.sort; 323 | } 324 | axios_1.default.post(this.fullUrl + `/address/utxo`, payload, { 325 | headers: this.getHeaders() 326 | }).then((response) => { 327 | return this.resolveOrCallback(resolve, response.data, callback); 328 | }).catch((ex) => { 329 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback); 330 | }); 331 | }); 332 | } 333 | // Deprecated, use broadcastTx 334 | sendRawTx(rawtx, callback) { 335 | return new Promise((resolve, reject) => { 336 | axios_1.default.post(this.fullUrl + `/tx/send`, { rawtx }, { 337 | headers: this.getHeaders() 338 | }).then((response) => { 339 | return this.resolveOrCallback(resolve, response.data, callback); 340 | }).catch((ex) => { 341 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback); 342 | }); 343 | }); 344 | } 345 | merchants_broadcastTx(rawtx, callback) { 346 | return new Promise((resolve, reject) => { 347 | axios_1.default.post(this.fullUrl + `/merchants/tx/broadcast`, { rawtx }, { 348 | headers: this.getHeaders() 349 | }).then((response) => { 350 | return this.resolveOrCallback(resolve, response.data, callback); 351 | }).catch((ex) => { 352 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback); 353 | }); 354 | }); 355 | } 356 | merchants_statusTx(txid, callback) { 357 | return new Promise((resolve, reject) => { 358 | axios_1.default.get(this.fullUrl + `/merchants/tx/status/${txid}`, { 359 | headers: this.getHeaders() 360 | }).then((response) => { 361 | return this.resolveOrCallback(resolve, response.data, callback); 362 | }).catch((ex) => { 363 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback); 364 | }); 365 | }); 366 | } 367 | mapi_submitTx(rawtx, callback) { 368 | return new Promise((resolve, reject) => { 369 | axios_1.default.post(this.minerFullUrl + `/tx`, { rawtx }, { 370 | headers: this.getHeaders() 371 | }).then((response) => { 372 | return this.resolveOrCallback(resolve, response.data, callback); 373 | }).catch((ex) => { 374 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback); 375 | }); 376 | }); 377 | } 378 | mapi_statusTx(txid, callback) { 379 | return new Promise((resolve, reject) => { 380 | axios_1.default.get(this.minerFullUrl + `/tx/${txid}`, { 381 | headers: this.getHeaders() 382 | }).then((response) => { 383 | return this.resolveOrCallback(resolve, response.data, callback); 384 | }).catch((ex) => { 385 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback); 386 | }); 387 | }); 388 | } 389 | mapi_feeQuote(callback) { 390 | return new Promise((resolve, reject) => { 391 | axios_1.default.get(this.minerFullUrl + `/feeQuote`, { 392 | headers: this.getHeaders() 393 | }).then((response) => { 394 | return this.resolveOrCallback(resolve, response.data, callback); 395 | }).catch((ex) => { 396 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback); 397 | }); 398 | }); 399 | } 400 | } 401 | exports.APIClient = APIClient; 402 | -------------------------------------------------------------------------------- /dist/basic.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | MatterCloud SDK Example 7 | 8 | 9 | 20 | 21 | 22 | MatterCloud 23 | Github 24 |

25 | UTXO query result: 26 |

27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /dist/browserdemo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | MatterCloud SDK Example 7 | 8 | 9 | 20 | 21 | 22 | MatterCloud 23 | Github 24 |

25 | UTXO query result: 26 |

27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | export declare class MerchantApi { 2 | options: any; 3 | constructor(providedOptions?: any); 4 | submitTx(rawtx: string, callback?: Function): Promise; 5 | getTxStatus(txid: string, callback?: Function): Promise; 6 | getFeeQuote(callback?: Function): Promise; 7 | static instance(newOptions?: any): MerchantApi; 8 | } 9 | export declare class MatterCloud { 10 | options: any; 11 | constructor(providedOptions?: any); 12 | setApiKey(key: string): void; 13 | setOptions(newOptions: any): void; 14 | getScriptHashUtxos(scripthash: string, args: {}, callback?: Function): Promise; 15 | getScriptHashHistory(scripthash: string, args: {}, callback?: Function): Promise; 16 | getUtxos(addrs: string, args: { 17 | offset?: number; 18 | limit?: number; 19 | afterHeight?: number; 20 | sort?: string; 21 | }, callback?: Function): Promise; 22 | getBalance(addr: string, callback?: Function): Promise; 23 | getBalanceBatch(addrs: string[], callback?: Function): Promise; 24 | getHistory(addr: string, args?: { 25 | from?: number; 26 | to?: number; 27 | }, callback?: Function): Promise; 28 | getHistoryBatch(addrs: string[], args?: { 29 | from?: number; 30 | to?: number; 31 | }, callback?: Function): Promise; 32 | getTx(txid: string, callback?: Function): Promise; 33 | getTxRaw(txid: string, callback?: Function): Promise; 34 | getTxBatch(txids: string[], callback?: Function): Promise; 35 | sendRawTx(rawtx: string, callback?: Function): Promise; 36 | merchantTxBroadcast(rawtx: string, callback?: Function): Promise; 37 | merchantTxStatus(txid: string, callback?: Function): Promise; 38 | get mapi(): MerchantApi; 39 | static instance(newOptions?: any): MatterCloud; 40 | } 41 | export declare function instance(newOptions?: any): MatterCloud; 42 | export declare function mapi(newOptions?: any): MerchantApi; 43 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const api_client_1 = require("./api-client"); 4 | const defaultOptions = { 5 | api_url: 'https://api.mattercloud.net', 6 | merchantapi_url: 'https://merchantapi.matterpool.io', 7 | network: 'main', 8 | version_path: 'api/v3', 9 | api_key: '' // Set to your API key 10 | }; 11 | class MerchantApi { 12 | constructor(providedOptions) { 13 | this.options = Object.assign({}, defaultOptions, providedOptions); 14 | } 15 | submitTx(rawtx, callback) { 16 | const apiClient = new api_client_1.APIClient(this.options); 17 | return apiClient.mapi_submitTx(rawtx, callback); 18 | } 19 | getTxStatus(txid, callback) { 20 | const apiClient = new api_client_1.APIClient(this.options); 21 | return apiClient.mapi_statusTx(txid, callback); 22 | } 23 | getFeeQuote(callback) { 24 | const apiClient = new api_client_1.APIClient(this.options); 25 | return apiClient.mapi_feeQuote(callback); 26 | } 27 | static instance(newOptions) { 28 | const mergedOptions = Object.assign({}, defaultOptions, newOptions); 29 | return new MerchantApi(mergedOptions); 30 | } 31 | } 32 | exports.MerchantApi = MerchantApi; 33 | class MatterCloud { 34 | constructor(providedOptions) { 35 | this.options = Object.assign({}, defaultOptions, providedOptions); 36 | } 37 | setApiKey(key) { 38 | this.options = Object.assign({}, this.options, { api_key: key }); 39 | } 40 | setOptions(newOptions) { 41 | this.options = Object.assign({}, this.options, newOptions); 42 | } 43 | getScriptHashUtxos(scripthash, args, callback) { 44 | const apiClient = new api_client_1.APIClient(this.options); 45 | return apiClient.scripthash_getUtxos(Object.assign({ scripthash }, args), callback); 46 | } 47 | getScriptHashHistory(scripthash, args, callback) { 48 | const apiClient = new api_client_1.APIClient(this.options); 49 | return apiClient.scripthash_getHistory(scripthash, Object.assign({}, args), callback); 50 | } 51 | getUtxos(addrs, args, callback) { 52 | const apiClient = new api_client_1.APIClient(this.options); 53 | return apiClient.addresses_getUtxos(Object.assign({ addrs }, args), callback); 54 | } 55 | getBalance(addr, callback) { 56 | const apiClient = new api_client_1.APIClient(this.options); 57 | return apiClient.address_getBalance(addr, callback); 58 | } 59 | getBalanceBatch(addrs, callback) { 60 | const apiClient = new api_client_1.APIClient(this.options); 61 | return apiClient.address_getBalanceBatch(addrs, callback); 62 | } 63 | getHistory(addr, args, callback) { 64 | const apiClient = new api_client_1.APIClient(this.options); 65 | return apiClient.address_getHistory(addr, args, callback); 66 | } 67 | getHistoryBatch(addrs, args, callback) { 68 | const apiClient = new api_client_1.APIClient(this.options); 69 | return apiClient.address_getHistoryBatch(addrs, args, callback); 70 | } 71 | getTx(txid, callback) { 72 | const apiClient = new api_client_1.APIClient(this.options); 73 | return apiClient.tx_getTransaction(txid, callback); 74 | } 75 | getTxRaw(txid, callback) { 76 | const apiClient = new api_client_1.APIClient(this.options); 77 | return apiClient.tx_getRawTransaction(txid, callback); 78 | } 79 | getTxBatch(txids, callback) { 80 | const apiClient = new api_client_1.APIClient(this.options); 81 | return apiClient.tx_getTransactionsBatch(txids, callback); 82 | } 83 | // @Deprecated 84 | // Use merchantapi mapi.submitTx 85 | sendRawTx(rawtx, callback) { 86 | const apiClient = new api_client_1.APIClient(this.options); 87 | return apiClient.sendRawTx(rawtx, callback); 88 | } 89 | // @Deprecated 90 | // Use merchantapi mapi.submitTx 91 | merchantTxBroadcast(rawtx, callback) { 92 | const apiClient = new api_client_1.APIClient(this.options); 93 | return apiClient.merchants_broadcastTx(rawtx, callback); 94 | } 95 | // @Deprecated 96 | // Use merchantapi mapi.getTxStatus 97 | merchantTxStatus(txid, callback) { 98 | const apiClient = new api_client_1.APIClient(this.options); 99 | return apiClient.merchants_statusTx(txid, callback); 100 | } 101 | get mapi() { 102 | return new MerchantApi(this.options); 103 | } 104 | static instance(newOptions) { 105 | const mergedOptions = Object.assign({}, defaultOptions, newOptions); 106 | return new MatterCloud(mergedOptions); 107 | } 108 | } 109 | exports.MatterCloud = MatterCloud; 110 | function instance(newOptions) { 111 | const mergedOptions = Object.assign({}, defaultOptions, newOptions); 112 | return new MatterCloud(mergedOptions); 113 | } 114 | exports.instance = instance; 115 | function mapi(newOptions) { 116 | const mergedOptions = Object.assign({}, defaultOptions, newOptions); 117 | return new MerchantApi(mergedOptions); 118 | } 119 | exports.mapi = mapi; 120 | try { 121 | if (window) { 122 | window['mattercloud'] = new MatterCloud(); 123 | window['merchantapi'] = new MerchantApi(); 124 | } 125 | } 126 | catch (ex) { 127 | // Window is not defined, must be running in windowless env.... 128 | } 129 | -------------------------------------------------------------------------------- /dist/mattercloud.js: -------------------------------------------------------------------------------- 1 | /** 2 | * mattercloudjs - MatterCloud Javascript SDK - https://www.mattercloud.net 3 | * @version v1.1.2 4 | * @link https://github.com/MatterCloud/mattercloudjs#readme 5 | * 6 | * Copyright (c) 2019 MatterCloud (Matter Web Services Inc.) 7 | * 8 | * Open BSV License 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * 1 - The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | * 2 - The Software, and any software that is derived from the Software or parts thereof, 19 | * can only be used on the Bitcoin SV blockchains. The Bitcoin SV blockchains are defined, 20 | * for purposes of this license, as the Bitcoin blockchain containing block height #556767 21 | * with the hash "000000000000000001d956714215d96ffc00e0afda4cd0a96c96f8d802b1662b" and 22 | * the test blockchains that are supported by the un-modified Software. 23 | * 24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 30 | * THE SOFTWARE. 31 | */ 32 | !function(){return function e(t,r,s){function n(i,a){if(!r[i]){if(!t[i]){var c="function"==typeof require&&require;if(!a&&c)return c(i,!0);if(o)return o(i,!0);var u=new Error("Cannot find module '"+i+"'");throw u.code="MODULE_NOT_FOUND",u}var l=r[i]={exports:{}};t[i][0].call(l.exports,function(e){return n(t[i][1][e]||e)},l,l.exports,e,t,r,s)}return r[i].exports}for(var o="function"==typeof require&&require,i=0;ie(t));r(t)}rejectOrCallback(e,t,r){if(!r)return e?e(t):new Promise((e,r)=>{r(t)});r(null,t)}formatErrorResponse(e){let t=e&&e.response&&e.response.data?e.response.data:e;return Object.assign(Object.assign({},t),{success:!!t.success&&t.success,code:t.code?t.code:-1,message:t.message?t.message:"",error:t.error?t.error:""})}tx_getTransaction(e,t){return new Promise((r,n)=>{if(!e||/^(\s*)$/.test(e))return this.rejectOrCallback(n,this.formatErrorResponse({code:422,message:"txid required"}),t);s.default.get(this.fullUrl+`/tx/${e}`,{headers:this.getHeaders()}).then(e=>this.resolveOrCallback(r,e.data,t)).catch(e=>this.rejectOrCallback(n,this.formatErrorResponse(e),t))})}tx_getRawTransaction(e,t){return new Promise((r,n)=>{if(!e||/^(\s*)$/.test(e))return this.rejectOrCallback(n,this.formatErrorResponse({code:422,message:"txid required"}),t);s.default.get(this.fullUrl+`/rawtx/${e}`,{headers:this.getHeaders()}).then(e=>e.data&&e.data.rawtx?this.resolveOrCallback(r,e.data.rawtx,t):this.resolveOrCallback(r,e.data,t)).catch(e=>this.rejectOrCallback(n,this.formatErrorResponse(e),t))})}tx_getTransactionsBatch(e,t){return new Promise((r,n)=>{if(!this.isStringOrNonEmptyArray(e))return this.rejectOrCallback(n,this.formatErrorResponse({code:422,message:"txid required"}),t);let o={txids:Array.isArray(e)?e.join(","):e};s.default.post(this.fullUrl+"/tx",o,{headers:this.getHeaders()}).then(e=>this.resolveOrCallback(r,e.data,t)).catch(e=>this.rejectOrCallback(n,this.formatErrorResponse(e),t))})}address_getBalance(e,t){return new Promise((r,n)=>{if(!this.isStringOrNonEmptyArray(e))return this.rejectOrCallback(n,this.formatErrorResponse({code:422,message:"address required"}),t);s.default.get(this.fullUrl+`/address/${e}/balance`,{headers:this.getHeaders()}).then(e=>this.resolveOrCallback(r,e.data,t)).catch(e=>this.rejectOrCallback(n,this.formatErrorResponse(e),t))})}address_getHistory(e,t,r){return new Promise((n,o)=>{if(!this.isStringOrNonEmptyArray(e))return this.rejectOrCallback(o,this.formatErrorResponse({code:422,message:"address required"}),r);let i="";t&&t.from&&(i+=`from=${t.from}&`),t&&t.to&&(i+=`to=${t.to}&`);const a=this.fullUrl+`/address/${e}/history?${i}`;s.default.get(a,{headers:this.getHeaders()}).then(e=>this.resolveOrCallback(n,e.data,r)).catch(e=>this.rejectOrCallback(o,this.formatErrorResponse(e),r))})}address_getBalanceBatch(e,t){return new Promise((r,n)=>{if(!this.isStringOrNonEmptyArray(e))return this.rejectOrCallback(n,this.formatErrorResponse({code:422,message:"address required"}),t);let o=[];Array.isArray(e)?o=e:o.push(e);let i={addrs:Array.isArray(o)?o.join(","):o};s.default.post(this.fullUrl+"/address/balance",i,{headers:this.getHeaders()}).then(e=>this.resolveOrCallback(r,e.data,t)).catch(e=>this.rejectOrCallback(n,this.formatErrorResponse(e),t))})}address_getHistoryBatch(e,t,r){return new Promise((n,o)=>{if(!this.isStringOrNonEmptyArray(e))return this.rejectOrCallback(o,this.formatErrorResponse({code:422,message:"address required"}),r);let i=[];Array.isArray(e)?i=e:i.push(e);let a={addrs:Array.isArray(i)?i.join(","):i};t&&t.from&&(a.from=t.from),t&&t.from&&(a.to=t.to),s.default.post(this.fullUrl+"/address/history",a,{headers:this.getHeaders()}).then(e=>this.resolveOrCallback(n,e.data,r)).catch(e=>this.rejectOrCallback(o,this.formatErrorResponse(e),r))})}isStringOrNonEmptyArray(e){return!(!e||Array.isArray(e)&&!e.length)}scripthash_getHistory(e,t,r){return new Promise((n,o)=>{if(!this.isStringOrNonEmptyArray(e))return this.rejectOrCallback(o,this.formatErrorResponse({code:422,message:"scripthash required"}),r);let i="";t&&t.from&&(i+=`from=${t.from}&`),t&&t.to&&(i+=`to=${t.to}&`);const a=this.fullUrl+`/scripthash/${e}/history?${i}`;s.default.get(a,{headers:this.getHeaders()}).then(e=>this.resolveOrCallback(n,e.data,r)).catch(e=>this.rejectOrCallback(o,this.formatErrorResponse(e),r))})}scripthash_getUtxos(e,t){return new Promise((r,n)=>{if(!this.isStringOrNonEmptyArray(e.scripthash))return this.rejectOrCallback(n,this.formatErrorResponse({code:422,message:"scripthash required",error:"scripthash required"}),t);let o=[];Array.isArray(e.scripthash)?o=e.scripthash:o.push(e.scripthash);let i={scripthash:Array.isArray(o)?o.join(","):o};s.default.post(this.fullUrl+"/scripthash/utxo",i,{headers:this.getHeaders()}).then(e=>this.resolveOrCallback(r,e.data,t)).catch(e=>this.rejectOrCallback(n,this.formatErrorResponse(e),t))})}addresses_getUtxos(e,t){return new Promise((r,n)=>{if(!this.isStringOrNonEmptyArray(e.addrs))return this.rejectOrCallback(n,this.formatErrorResponse({code:422,message:"address required"}),t);let o=[];Array.isArray(e.addrs)?o=e.addrs:o.push(e.addrs);let i={addrs:Array.isArray(o)?o.join(","):o};e.offset&&(i.offset=e.offset),e.limit&&(i.limit=e.limit),e.afterHeight&&(i.afterHeight=e.afterHeight),e.sort&&(i.sort=e.sort),s.default.post(this.fullUrl+"/address/utxo",i,{headers:this.getHeaders()}).then(e=>this.resolveOrCallback(r,e.data,t)).catch(e=>this.rejectOrCallback(n,this.formatErrorResponse(e),t))})}sendRawTx(e,t){return new Promise((r,n)=>{s.default.post(this.fullUrl+"/tx/send",{rawtx:e},{headers:this.getHeaders()}).then(e=>this.resolveOrCallback(r,e.data,t)).catch(e=>this.rejectOrCallback(n,this.formatErrorResponse(e),t))})}merchants_broadcastTx(e,t){return new Promise((r,n)=>{s.default.post(this.fullUrl+"/merchants/tx/broadcast",{rawtx:e},{headers:this.getHeaders()}).then(e=>this.resolveOrCallback(r,e.data,t)).catch(e=>this.rejectOrCallback(n,this.formatErrorResponse(e),t))})}merchants_statusTx(e,t){return new Promise((r,n)=>{s.default.get(this.fullUrl+`/merchants/tx/status/${e}`,{headers:this.getHeaders()}).then(e=>this.resolveOrCallback(r,e.data,t)).catch(e=>this.rejectOrCallback(n,this.formatErrorResponse(e),t))})}mapi_submitTx(e,t){return new Promise((r,n)=>{s.default.post(this.minerFullUrl+"/tx",{rawtx:e},{headers:this.getHeaders()}).then(e=>this.resolveOrCallback(r,e.data,t)).catch(e=>this.rejectOrCallback(n,this.formatErrorResponse(e),t))})}mapi_statusTx(e,t){return new Promise((r,n)=>{s.default.get(this.minerFullUrl+`/tx/${e}`,{headers:this.getHeaders()}).then(e=>this.resolveOrCallback(r,e.data,t)).catch(e=>this.rejectOrCallback(n,this.formatErrorResponse(e),t))})}mapi_feeQuote(e){return new Promise((t,r)=>{s.default.get(this.minerFullUrl+"/feeQuote",{headers:this.getHeaders()}).then(r=>this.resolveOrCallback(t,r.data,e)).catch(t=>this.rejectOrCallback(r,this.formatErrorResponse(t),e))})}}},{axios:3}],2:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0});const s=e("./api-client"),n={api_url:"https://api.mattercloud.net",merchantapi_url:"https://merchantapi.matterpool.io",network:"main",version_path:"api/v3",api_key:""};class o{constructor(e){this.options=Object.assign({},n,e)}submitTx(e,t){return new s.APIClient(this.options).mapi_submitTx(e,t)}getTxStatus(e,t){return new s.APIClient(this.options).mapi_statusTx(e,t)}getFeeQuote(e){return new s.APIClient(this.options).mapi_feeQuote(e)}static instance(e){const t=Object.assign({},n,e);return new o(t)}}r.MerchantApi=o;class i{constructor(e){this.options=Object.assign({},n,e)}setApiKey(e){this.options=Object.assign({},this.options,{api_key:e})}setOptions(e){this.options=Object.assign({},this.options,e)}getScriptHashUtxos(e,t,r){return new s.APIClient(this.options).scripthash_getUtxos(Object.assign({scripthash:e},t),r)}getScriptHashHistory(e,t,r){return new s.APIClient(this.options).scripthash_getHistory(e,Object.assign({},t),r)}getUtxos(e,t,r){return new s.APIClient(this.options).addresses_getUtxos(Object.assign({addrs:e},t),r)}getBalance(e,t){return new s.APIClient(this.options).address_getBalance(e,t)}getBalanceBatch(e,t){return new s.APIClient(this.options).address_getBalanceBatch(e,t)}getHistory(e,t,r){return new s.APIClient(this.options).address_getHistory(e,t,r)}getHistoryBatch(e,t,r){return new s.APIClient(this.options).address_getHistoryBatch(e,t,r)}getTx(e,t){return new s.APIClient(this.options).tx_getTransaction(e,t)}getTxRaw(e,t){return new s.APIClient(this.options).tx_getRawTransaction(e,t)}getTxBatch(e,t){return new s.APIClient(this.options).tx_getTransactionsBatch(e,t)}sendRawTx(e,t){return new s.APIClient(this.options).sendRawTx(e,t)}merchantTxBroadcast(e,t){return new s.APIClient(this.options).merchants_broadcastTx(e,t)}merchantTxStatus(e,t){return new s.APIClient(this.options).merchants_statusTx(e,t)}get mapi(){return new o(this.options)}static instance(e){const t=Object.assign({},n,e);return new i(t)}}r.MatterCloud=i,r.instance=function(e){const t=Object.assign({},n,e);return new i(t)},r.mapi=function(e){const t=Object.assign({},n,e);return new o(t)};try{window&&(window.mattercloud=new i,window.merchantapi=new o)}catch(e){}},{"./api-client":1}],3:[function(e,t,r){t.exports=e("./lib/axios")},{"./lib/axios":5}],4:[function(e,t,r){"use strict";var s=e("./../utils"),n=e("./../core/settle"),o=e("./../helpers/buildURL"),i=e("./../helpers/parseHeaders"),a=e("./../helpers/isURLSameOrigin"),c=e("../core/createError");t.exports=function(t){return new Promise(function(r,u){var l=t.data,h=t.headers;s.isFormData(l)&&delete h["Content-Type"];var f=new XMLHttpRequest;if(t.auth){var p=t.auth.username||"",d=t.auth.password||"";h.Authorization="Basic "+btoa(p+":"+d)}if(f.open(t.method.toUpperCase(),o(t.url,t.params,t.paramsSerializer),!0),f.timeout=t.timeout,f.onreadystatechange=function(){if(f&&4===f.readyState&&(0!==f.status||f.responseURL&&0===f.responseURL.indexOf("file:"))){var e="getAllResponseHeaders"in f?i(f.getAllResponseHeaders()):null,s={data:t.responseType&&"text"!==t.responseType?f.response:f.responseText,status:f.status,statusText:f.statusText,headers:e,config:t,request:f};n(r,u,s),f=null}},f.onerror=function(){u(c("Network Error",t,null,f)),f=null},f.ontimeout=function(){u(c("timeout of "+t.timeout+"ms exceeded",t,"ECONNABORTED",f)),f=null},s.isStandardBrowserEnv()){var m=e("./../helpers/cookies"),g=(t.withCredentials||a(t.url))&&t.xsrfCookieName?m.read(t.xsrfCookieName):void 0;g&&(h[t.xsrfHeaderName]=g)}if("setRequestHeader"in f&&s.forEach(h,function(e,t){void 0===l&&"content-type"===t.toLowerCase()?delete h[t]:f.setRequestHeader(t,e)}),t.withCredentials&&(f.withCredentials=!0),t.responseType)try{f.responseType=t.responseType}catch(e){if("json"!==t.responseType)throw e}"function"==typeof t.onDownloadProgress&&f.addEventListener("progress",t.onDownloadProgress),"function"==typeof t.onUploadProgress&&f.upload&&f.upload.addEventListener("progress",t.onUploadProgress),t.cancelToken&&t.cancelToken.promise.then(function(e){f&&(f.abort(),u(e),f=null)}),void 0===l&&(l=null),f.send(l)})}},{"../core/createError":11,"./../core/settle":14,"./../helpers/buildURL":18,"./../helpers/cookies":20,"./../helpers/isURLSameOrigin":22,"./../helpers/parseHeaders":24,"./../utils":26}],5:[function(e,t,r){"use strict";var s=e("./utils"),n=e("./helpers/bind"),o=e("./core/Axios"),i=e("./defaults");function a(e){var t=new o(e),r=n(o.prototype.request,t);return s.extend(r,o.prototype,t),s.extend(r,t),r}var c=a(i);c.Axios=o,c.create=function(e){return a(s.merge(i,e))},c.Cancel=e("./cancel/Cancel"),c.CancelToken=e("./cancel/CancelToken"),c.isCancel=e("./cancel/isCancel"),c.all=function(e){return Promise.all(e)},c.spread=e("./helpers/spread"),t.exports=c,t.exports.default=c},{"./cancel/Cancel":6,"./cancel/CancelToken":7,"./cancel/isCancel":8,"./core/Axios":9,"./defaults":16,"./helpers/bind":17,"./helpers/spread":25,"./utils":26}],6:[function(e,t,r){"use strict";function s(e){this.message=e}s.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},s.prototype.__CANCEL__=!0,t.exports=s},{}],7:[function(e,t,r){"use strict";var s=e("./Cancel");function n(e){if("function"!=typeof e)throw new TypeError("executor must be a function.");var t;this.promise=new Promise(function(e){t=e});var r=this;e(function(e){r.reason||(r.reason=new s(e),t(r.reason))})}n.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},n.source=function(){var e;return{token:new n(function(t){e=t}),cancel:e}},t.exports=n},{"./Cancel":6}],8:[function(e,t,r){"use strict";t.exports=function(e){return!(!e||!e.__CANCEL__)}},{}],9:[function(e,t,r){"use strict";var s=e("./../defaults"),n=e("./../utils"),o=e("./InterceptorManager"),i=e("./dispatchRequest");function a(e){this.defaults=e,this.interceptors={request:new o,response:new o}}a.prototype.request=function(e){"string"==typeof e&&(e=n.merge({url:arguments[0]},arguments[1])),(e=n.merge(s,{method:"get"},this.defaults,e)).method=e.method.toLowerCase();var t=[i,void 0],r=Promise.resolve(e);for(this.interceptors.request.forEach(function(e){t.unshift(e.fulfilled,e.rejected)}),this.interceptors.response.forEach(function(e){t.push(e.fulfilled,e.rejected)});t.length;)r=r.then(t.shift(),t.shift());return r},n.forEach(["delete","get","head","options"],function(e){a.prototype[e]=function(t,r){return this.request(n.merge(r||{},{method:e,url:t}))}}),n.forEach(["post","put","patch"],function(e){a.prototype[e]=function(t,r,s){return this.request(n.merge(s||{},{method:e,url:t,data:r}))}}),t.exports=a},{"./../defaults":16,"./../utils":26,"./InterceptorManager":10,"./dispatchRequest":12}],10:[function(e,t,r){"use strict";var s=e("./../utils");function n(){this.handlers=[]}n.prototype.use=function(e,t){return this.handlers.push({fulfilled:e,rejected:t}),this.handlers.length-1},n.prototype.eject=function(e){this.handlers[e]&&(this.handlers[e]=null)},n.prototype.forEach=function(e){s.forEach(this.handlers,function(t){null!==t&&e(t)})},t.exports=n},{"./../utils":26}],11:[function(e,t,r){"use strict";var s=e("./enhanceError");t.exports=function(e,t,r,n,o){var i=new Error(e);return s(i,t,r,n,o)}},{"./enhanceError":13}],12:[function(e,t,r){"use strict";var s=e("./../utils"),n=e("./transformData"),o=e("../cancel/isCancel"),i=e("../defaults"),a=e("./../helpers/isAbsoluteURL"),c=e("./../helpers/combineURLs");function u(e){e.cancelToken&&e.cancelToken.throwIfRequested()}t.exports=function(e){return u(e),e.baseURL&&!a(e.url)&&(e.url=c(e.baseURL,e.url)),e.headers=e.headers||{},e.data=n(e.data,e.headers,e.transformRequest),e.headers=s.merge(e.headers.common||{},e.headers[e.method]||{},e.headers||{}),s.forEach(["delete","get","head","post","put","patch","common"],function(t){delete e.headers[t]}),(e.adapter||i.adapter)(e).then(function(t){return u(e),t.data=n(t.data,t.headers,e.transformResponse),t},function(t){return o(t)||(u(e),t&&t.response&&(t.response.data=n(t.response.data,t.response.headers,e.transformResponse))),Promise.reject(t)})}},{"../cancel/isCancel":8,"../defaults":16,"./../helpers/combineURLs":19,"./../helpers/isAbsoluteURL":21,"./../utils":26,"./transformData":15}],13:[function(e,t,r){"use strict";t.exports=function(e,t,r,s,n){return e.config=t,r&&(e.code=r),e.request=s,e.response=n,e}},{}],14:[function(e,t,r){"use strict";var s=e("./createError");t.exports=function(e,t,r){var n=r.config.validateStatus;r.status&&n&&!n(r.status)?t(s("Request failed with status code "+r.status,r.config,null,r.request,r)):e(r)}},{"./createError":11}],15:[function(e,t,r){"use strict";var s=e("./../utils");t.exports=function(e,t,r){return s.forEach(r,function(r){e=r(e,t)}),e}},{"./../utils":26}],16:[function(e,t,r){(function(r){"use strict";var s=e("./utils"),n=e("./helpers/normalizeHeaderName"),o={"Content-Type":"application/x-www-form-urlencoded"};function i(e,t){!s.isUndefined(e)&&s.isUndefined(e["Content-Type"])&&(e["Content-Type"]=t)}var a,c={adapter:("undefined"!=typeof XMLHttpRequest?a=e("./adapters/xhr"):void 0!==r&&(a=e("./adapters/http")),a),transformRequest:[function(e,t){return n(t,"Content-Type"),s.isFormData(e)||s.isArrayBuffer(e)||s.isBuffer(e)||s.isStream(e)||s.isFile(e)||s.isBlob(e)?e:s.isArrayBufferView(e)?e.buffer:s.isURLSearchParams(e)?(i(t,"application/x-www-form-urlencoded;charset=utf-8"),e.toString()):s.isObject(e)?(i(t,"application/json;charset=utf-8"),JSON.stringify(e)):e}],transformResponse:[function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(e){}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,validateStatus:function(e){return e>=200&&e<300}};c.headers={common:{Accept:"application/json, text/plain, */*"}},s.forEach(["delete","get","head"],function(e){c.headers[e]={}}),s.forEach(["post","put","patch"],function(e){c.headers[e]=s.merge(o)}),t.exports=c}).call(this,e("_process"))},{"./adapters/http":4,"./adapters/xhr":4,"./helpers/normalizeHeaderName":23,"./utils":26,_process:28}],17:[function(e,t,r){"use strict";t.exports=function(e,t){return function(){for(var r=new Array(arguments.length),s=0;s=0)return;i[t]="set-cookie"===t?(i[t]?i[t]:[]).concat([r]):i[t]?i[t]+", "+r:r}}),i):i}},{"./../utils":26}],25:[function(e,t,r){"use strict";t.exports=function(e){return function(t){return e.apply(null,t)}}},{}],26:[function(e,t,r){"use strict";var s=e("./helpers/bind"),n=e("is-buffer"),o=Object.prototype.toString;function i(e){return"[object Array]"===o.call(e)}function a(e){return null!==e&&"object"==typeof e}function c(e){return"[object Function]"===o.call(e)}function u(e,t){if(null!=e)if("object"!=typeof e&&(e=[e]),i(e))for(var r=0,s=e.length;r1)for(var r=1;r - <%= pkg.description %>', 18 | ' * @version v<%= pkg.version %>', 19 | ' * @link <%= pkg.homepage %>', 20 | ' *', 21 | ' * Copyright (c) 2019 MatterCloud (Matter Web Services Inc.)', 22 | ' *', 23 | ' * Open BSV License', 24 | ' * Permission is hereby granted, free of charge, to any person obtaining a copy', 25 | ' * of this software and associated documentation files (the "Software"), to deal', 26 | ' * in the Software without restriction, including without limitation the rights', 27 | ' * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell', 28 | ' * copies of the Software, and to permit persons to whom the Software is', 29 | ' * furnished to do so, subject to the following conditions:', 30 | ' *', 31 | ' * 1 - The above copyright notice and this permission notice shall be included in', 32 | ' * all copies or substantial portions of the Software.', 33 | ' * 2 - The Software, and any software that is derived from the Software or parts thereof,', 34 | ' * can only be used on the Bitcoin SV blockchains. The Bitcoin SV blockchains are defined,', 35 | ' * for purposes of this license, as the Bitcoin blockchain containing block height #556767', 36 | ' * with the hash "000000000000000001d956714215d96ffc00e0afda4cd0a96c96f8d802b1662b" and', 37 | ' * the test blockchains that are supported by the un-modified Software.', 38 | ' *', 39 | ' * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR', 40 | ' * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,', 41 | ' * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE', 42 | ' * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER', 43 | ' * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,', 44 | ' * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN', 45 | ' * THE SOFTWARE.', 46 | ' */', 47 | ''].join('\n'); 48 | 49 | gulp.task("copy-html", function () { 50 | return gulp.src(paths.pages) 51 | .pipe(gulp.dest("dist")); 52 | }); 53 | 54 | gulp.task("build", ['copy-html'], function () { 55 | return browserify({ 56 | basedir: '.', 57 | debug: true, 58 | entries: ['lib/index.ts'], 59 | cache: {}, 60 | packageCache: {} 61 | }) 62 | .plugin(tsify) 63 | .bundle() 64 | .pipe(source('mattercloud.js')) 65 | .pipe(buffer()) 66 | .pipe(uglify()) 67 | .pipe(header(banner, { pkg : pkg } )) 68 | .pipe(gulp.dest("dist")); 69 | }); 70 | -------------------------------------------------------------------------------- /header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MatterCloud/mattercloudjs/af47f6c783ef4e2fc0610e2f1ca511fc836cdb3e/header.png -------------------------------------------------------------------------------- /lib/api-client.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | export interface MatterCloudApiClientOptions { 4 | api_url: string; 5 | merchantapi_url: string; 6 | api_key?: string; 7 | network: string; 8 | version_path: string; 9 | } 10 | 11 | const defaultOptions: MatterCloudApiClientOptions = { 12 | api_url: 'https://api.mattercloud.net', 13 | merchantapi_url: 'https://merchantapi.matterpool.io', 14 | network: 'main', // 'test', or 'stn' 15 | version_path: 'api/v3', // Leave as is 16 | // api_key: 'your api key ', // Get a key at www.mattercloud.net 17 | } 18 | /** 19 | * API Client 20 | */ 21 | export class APIClient { 22 | options = defaultOptions; 23 | fullUrl; 24 | minerFullUrl; 25 | constructor(options: any) { 26 | this.options = Object.assign({}, this.options, options); 27 | this.fullUrl = `${this.options.api_url}/${this.options.version_path}/${this.options.network}`; 28 | this.minerFullUrl = `${this.options.merchantapi_url}/mapi`; 29 | } 30 | 31 | // Populate api reqest header if it's set 32 | getHeaders(): any { 33 | if (this.options.api_key && this.options.api_key !== '') { 34 | return { 35 | api_key: this.options.api_key, 36 | 'Content-Type': 'application/json', 37 | }; 38 | } 39 | return { 40 | 'Content-Type': 'application/json', 41 | }; 42 | } 43 | 44 | /** 45 | * Resolve a promise and/or invoke a callback 46 | * @param resolve Resolve function to call when done 47 | * @param data Data to pass forward 48 | * @param callback Invoke an optional callback first 49 | */ 50 | private resolveOrCallback(resolve?: Function, data?: any, callback?: Function) { 51 | if (callback) { 52 | callback(data); 53 | return undefined; 54 | } 55 | if (resolve) { 56 | return resolve(data); 57 | } 58 | return new Promise((r, reject) => { 59 | return r(data); 60 | }); 61 | } 62 | 63 | /** 64 | * Resolve a promise and/or invoke a callback 65 | * @param reject Reject function to call when done 66 | * @param data Data to pass forward 67 | * @param callback Invoke an optional callback first 68 | */ 69 | private rejectOrCallback(reject?: Function, err?: any, callback?: Function) { 70 | if (callback) { 71 | callback(null, err); 72 | return; 73 | } 74 | if (reject) { 75 | return reject(err); 76 | } 77 | return new Promise((resolve, r) => { 78 | r(err); 79 | }); 80 | } 81 | private formatErrorResponse(r: any): any { 82 | // let getMessage = r && r.response && r.response.data ? r.response.data : r.toString(); 83 | let getMessage = r && r.response && r.response.data ? r.response.data : r; 84 | return { 85 | ...getMessage, 86 | success: getMessage.success ? getMessage.success : false, 87 | code: getMessage.code ? getMessage.code : -1, 88 | message: getMessage.message ? getMessage.message : '', 89 | error: getMessage.error ? getMessage.error : '', 90 | }; 91 | } 92 | 93 | tx_getTransaction(txid: string, callback?: Function): Promise { 94 | return new Promise((resolve, reject) => { 95 | if (!txid || /^(\s*)$/.test(txid)) { 96 | return this.rejectOrCallback(reject, this.formatErrorResponse({ 97 | code: 422, 98 | message: 'txid required' 99 | }), callback) 100 | } 101 | axios.get(this.fullUrl + `/tx/${txid}`, 102 | { 103 | headers: this.getHeaders() 104 | } 105 | ).then((response) => { 106 | return this.resolveOrCallback(resolve, response.data, callback); 107 | }).catch((ex) => { 108 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback) 109 | }) 110 | }); 111 | } 112 | 113 | tx_getRawTransaction(txid: string, callback?: Function): Promise { 114 | return new Promise((resolve, reject) => { 115 | if (!txid || /^(\s*)$/.test(txid)) { 116 | return this.rejectOrCallback(reject, this.formatErrorResponse({ 117 | code: 422, 118 | message: 'txid required' 119 | }), callback) 120 | } 121 | axios.get(this.fullUrl + `/rawtx/${txid}`, 122 | { 123 | headers: this.getHeaders() 124 | } 125 | ).then((response) => { 126 | if (response.data && response.data.rawtx) { 127 | return this.resolveOrCallback(resolve, response.data.rawtx, callback); 128 | } 129 | return this.resolveOrCallback(resolve, response.data, callback); 130 | }).catch((ex) => { 131 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback) 132 | }) 133 | }); 134 | } 135 | 136 | tx_getTransactionsBatch(txids: string[], callback?: Function): Promise { 137 | return new Promise((resolve, reject) => { 138 | if (!this.isStringOrNonEmptyArray(txids)) { 139 | return this.rejectOrCallback(reject, this.formatErrorResponse({ 140 | code: 422, 141 | message: 'txid required' 142 | }), callback) 143 | } 144 | let payload: any = { 145 | txids: Array.isArray(txids) ? txids.join(',') : txids 146 | }; 147 | axios.post(this.fullUrl + `/tx`, 148 | payload, 149 | { 150 | headers: this.getHeaders() 151 | } 152 | ).then((response) => { 153 | return this.resolveOrCallback(resolve, response.data, callback); 154 | }).catch((ex) => { 155 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback) 156 | }) 157 | }); 158 | } 159 | 160 | address_getBalance(addr: any, callback?: Function): Promise { 161 | return new Promise((resolve, reject) => { 162 | if (!this.isStringOrNonEmptyArray(addr)) { 163 | return this.rejectOrCallback(reject, this.formatErrorResponse({ 164 | code: 422, 165 | message: 'address required' 166 | }), callback) 167 | } 168 | axios.get(this.fullUrl + `/address/${addr}/balance`, 169 | { 170 | headers: this.getHeaders() 171 | } 172 | ).then((response) => { 173 | return this.resolveOrCallback(resolve, response.data, callback); 174 | }).catch((ex) => { 175 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback) 176 | }) 177 | }); 178 | } 179 | 180 | address_getHistory(addr: any, options?: {from?: number, to?: number }, callback?: Function): Promise { 181 | return new Promise((resolve, reject) => { 182 | if (!this.isStringOrNonEmptyArray(addr)) { 183 | return this.rejectOrCallback(reject, this.formatErrorResponse({ 184 | code: 422, 185 | message: 'address required' 186 | }), callback) 187 | } 188 | let args = ''; 189 | if (options && options.from) { 190 | args += `from=${options.from}&`; 191 | } 192 | if (options && options.to) { 193 | args += `to=${options.to}&`; 194 | } 195 | const url = this.fullUrl + `/address/${addr}/history?${args}`; 196 | axios.get(url, 197 | { 198 | headers: this.getHeaders() 199 | } 200 | ).then((response) => { 201 | return this.resolveOrCallback(resolve, response.data, callback); 202 | }).catch((ex) => { 203 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback) 204 | }) 205 | }); 206 | } 207 | 208 | address_getBalanceBatch(addrs: string[], callback?: Function): Promise { 209 | return new Promise((resolve, reject) => { 210 | if (!this.isStringOrNonEmptyArray(addrs)) { 211 | return this.rejectOrCallback(reject, this.formatErrorResponse({ 212 | code: 422, 213 | message: 'address required' 214 | }), callback) 215 | } 216 | let addrsNew: string[] = []; 217 | if (!Array.isArray(addrs)) { 218 | addrsNew.push(addrs); 219 | } else { 220 | addrsNew = addrs; 221 | } 222 | 223 | let payload: any = { 224 | addrs: Array.isArray(addrsNew) ? addrsNew.join(',') : addrsNew 225 | }; 226 | axios.post(this.fullUrl + `/address/balance`, 227 | payload, 228 | { 229 | headers: this.getHeaders() 230 | } 231 | ).then((response) => { 232 | return this.resolveOrCallback(resolve, response.data, callback); 233 | }).catch((ex) => { 234 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback) 235 | }) 236 | }); 237 | } 238 | 239 | address_getHistoryBatch(addrs: string[], options?: {from?: number, to?: number }, callback?: Function): Promise { 240 | return new Promise((resolve, reject) => { 241 | if (!this.isStringOrNonEmptyArray(addrs)) { 242 | return this.rejectOrCallback(reject, this.formatErrorResponse({ 243 | code: 422, 244 | message: 'address required' 245 | }), callback) 246 | } 247 | let addrsNew: string[] = []; 248 | if (!Array.isArray(addrs)) { 249 | addrsNew.push(addrs); 250 | } else { 251 | addrsNew = addrs; 252 | } 253 | 254 | let payload: any = { 255 | addrs: Array.isArray(addrsNew) ? addrsNew.join(',') : addrsNew 256 | }; 257 | 258 | if (options && options.from) { 259 | payload.from = options.from; 260 | } 261 | if (options && options.from) { 262 | payload.to = options.to; 263 | } 264 | 265 | axios.post(this.fullUrl + `/address/history`, 266 | payload, 267 | { 268 | headers: this.getHeaders() 269 | } 270 | ).then((response) => { 271 | return this.resolveOrCallback(resolve, response.data, callback); 272 | }).catch((ex) => { 273 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback) 274 | }) 275 | }); 276 | } 277 | 278 | private isStringOrNonEmptyArray(item: any): boolean { 279 | if (!item) { 280 | return false; 281 | } 282 | 283 | if (Array.isArray(item) && !item.length) { 284 | return false; 285 | } 286 | return true; 287 | } 288 | 289 | scripthash_getHistory(scripthash: any, options?: {from?: number, to?: number }, callback?: Function): Promise { 290 | return new Promise((resolve, reject) => { 291 | if (!this.isStringOrNonEmptyArray(scripthash)) { 292 | return this.rejectOrCallback(reject, this.formatErrorResponse({ 293 | code: 422, 294 | message: 'scripthash required' 295 | }), callback) 296 | } 297 | let args = ''; 298 | if (options && options.from) { 299 | args += `from=${options.from}&`; 300 | } 301 | if (options && options.to) { 302 | args += `to=${options.to}&`; 303 | } 304 | const url = this.fullUrl + `/scripthash/${scripthash}/history?${args}`; 305 | axios.get(url, 306 | { 307 | headers: this.getHeaders() 308 | } 309 | ).then((response) => { 310 | return this.resolveOrCallback(resolve, response.data, callback); 311 | }).catch((ex) => { 312 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback) 313 | }) 314 | }); 315 | } 316 | 317 | scripthash_getUtxos(args: { scripthash: any }, callback?: Function): Promise { 318 | return new Promise((resolve, reject) => { 319 | if (!this.isStringOrNonEmptyArray(args.scripthash)) { 320 | return this.rejectOrCallback(reject, this.formatErrorResponse({ 321 | code: 422, 322 | message: 'scripthash required', 323 | error: 'scripthash required' 324 | }), callback) 325 | } 326 | let scripthashes: string[] = []; 327 | if (!Array.isArray(args.scripthash)) { 328 | scripthashes.push(args.scripthash); 329 | } else { 330 | scripthashes = args.scripthash; 331 | } 332 | 333 | let payload: any = { 334 | scripthash: Array.isArray(scripthashes) ? scripthashes.join(',') : scripthashes 335 | }; 336 | axios.post(this.fullUrl + `/scripthash/utxo`, 337 | payload, 338 | { 339 | headers: this.getHeaders() 340 | } 341 | ).then((response) => { 342 | return this.resolveOrCallback(resolve, response.data, callback); 343 | }).catch((ex) => { 344 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback) 345 | }) 346 | }); 347 | } 348 | 349 | addresses_getUtxos(args: { addrs: any, offset?: number, limit?: number, afterHeight?: number, sort?: string}, callback?: Function): Promise { 350 | return new Promise((resolve, reject) => { 351 | if (!this.isStringOrNonEmptyArray(args.addrs)) { 352 | return this.rejectOrCallback(reject, this.formatErrorResponse({ 353 | code: 422, 354 | message: 'address required' 355 | }), callback) 356 | } 357 | let addrs: string[] = []; 358 | if (!Array.isArray(args.addrs)) { 359 | addrs.push(args.addrs); 360 | } else { 361 | addrs = args.addrs; 362 | } 363 | 364 | let payload: any = { 365 | addrs: Array.isArray(addrs) ? addrs.join(',') : addrs 366 | }; 367 | 368 | if (args.offset) { 369 | payload.offset = args.offset; 370 | } 371 | if (args.limit) { 372 | payload.limit = args.limit; 373 | } 374 | if (args.afterHeight) { 375 | payload.afterHeight = args.afterHeight; 376 | } 377 | if (args.sort) { 378 | payload.sort = args.sort; 379 | } 380 | axios.post(this.fullUrl + `/address/utxo`, 381 | payload, 382 | { 383 | headers: this.getHeaders() 384 | } 385 | ).then((response) => { 386 | return this.resolveOrCallback(resolve, response.data, callback); 387 | }).catch((ex) => { 388 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback) 389 | }) 390 | }); 391 | } 392 | // Deprecated, use broadcastTx 393 | sendRawTx(rawtx: string, callback?: Function): Promise { 394 | return new Promise((resolve, reject) => { 395 | axios.post(this.fullUrl + `/tx/send`, 396 | { rawtx }, 397 | { 398 | headers: this.getHeaders() 399 | } 400 | ).then((response) => { 401 | return this.resolveOrCallback(resolve, response.data, callback); 402 | }).catch((ex) => { 403 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback) 404 | }) 405 | }); 406 | } 407 | merchants_broadcastTx(rawtx: string, callback?: Function): Promise { 408 | return new Promise((resolve, reject) => { 409 | axios.post(this.fullUrl + `/merchants/tx/broadcast`, 410 | { rawtx }, 411 | { 412 | headers: this.getHeaders() 413 | } 414 | ).then((response) => { 415 | return this.resolveOrCallback(resolve, response.data, callback); 416 | }).catch((ex) => { 417 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback) 418 | }) 419 | }); 420 | } 421 | 422 | merchants_statusTx(txid: string, callback?: Function): Promise { 423 | return new Promise((resolve, reject) => { 424 | axios.get(this.fullUrl + `/merchants/tx/status/${txid}`, 425 | { 426 | headers: this.getHeaders() 427 | } 428 | ).then((response) => { 429 | return this.resolveOrCallback(resolve, response.data, callback); 430 | }).catch((ex) => { 431 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback) 432 | }) 433 | }); 434 | } 435 | mapi_submitTx(rawtx: string, callback?: Function): Promise { 436 | return new Promise((resolve, reject) => { 437 | axios.post(this.minerFullUrl + `/tx`, 438 | { rawtx }, 439 | { 440 | headers: this.getHeaders() 441 | } 442 | ).then((response) => { 443 | return this.resolveOrCallback(resolve, response.data, callback); 444 | }).catch((ex) => { 445 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback) 446 | }) 447 | }); 448 | } 449 | 450 | mapi_statusTx(txid: string, callback?: Function): Promise { 451 | return new Promise((resolve, reject) => { 452 | axios.get(this.minerFullUrl + `/tx/${txid}`, 453 | { 454 | headers: this.getHeaders() 455 | } 456 | ).then((response) => { 457 | return this.resolveOrCallback(resolve, response.data, callback); 458 | }).catch((ex) => { 459 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback) 460 | }) 461 | }); 462 | } 463 | 464 | mapi_feeQuote(callback?: Function): Promise { 465 | return new Promise((resolve, reject) => { 466 | axios.get(this.minerFullUrl + `/feeQuote`, 467 | { 468 | headers: this.getHeaders() 469 | } 470 | ).then((response) => { 471 | return this.resolveOrCallback(resolve, response.data, callback); 472 | }).catch((ex) => { 473 | return this.rejectOrCallback(reject, this.formatErrorResponse(ex), callback) 474 | }) 475 | }); 476 | } 477 | } -------------------------------------------------------------------------------- /lib/examples/browserdemo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | MatterCloud SDK Example 7 | 8 | 9 | 20 | 21 | 22 | MatterCloud 23 | Github 24 |

25 | UTXO query result: 26 |

27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /lib/index.ts: -------------------------------------------------------------------------------- 1 | import { APIClient } from './api-client'; 2 | 3 | const defaultOptions: any = { 4 | api_url: 'https://api.mattercloud.net', 5 | merchantapi_url: 'https://merchantapi.matterpool.io', 6 | network: 'main', // 'main', test', or 'stn'. 'main' and 'test' supported 7 | version_path: 'api/v3', // Do not change 8 | api_key: '' // Set to your API key 9 | } 10 | 11 | export class MerchantApi { 12 | options; 13 | constructor(providedOptions?: any) { 14 | this.options = Object.assign({}, defaultOptions, providedOptions); 15 | } 16 | 17 | submitTx(rawtx: string, callback?: Function): Promise { 18 | const apiClient = new APIClient(this.options); 19 | return apiClient.mapi_submitTx(rawtx, callback); 20 | } 21 | 22 | getTxStatus(txid: string, callback?: Function): Promise { 23 | const apiClient = new APIClient(this.options); 24 | return apiClient.mapi_statusTx(txid, callback); 25 | } 26 | 27 | getFeeQuote(callback?: Function): Promise { 28 | const apiClient = new APIClient(this.options); 29 | return apiClient.mapi_feeQuote(callback); 30 | } 31 | 32 | static instance(newOptions?: any): MerchantApi { 33 | const mergedOptions = Object.assign({}, defaultOptions, newOptions); 34 | return new MerchantApi(mergedOptions); 35 | } 36 | } 37 | 38 | export class MatterCloud { 39 | options; 40 | constructor(providedOptions?: any) { 41 | this.options = Object.assign({}, defaultOptions, providedOptions); 42 | } 43 | 44 | setApiKey(key: string) { 45 | this.options = Object.assign({}, this.options, { api_key: key }); 46 | } 47 | 48 | setOptions(newOptions) { 49 | this.options = Object.assign({}, this.options, newOptions); 50 | } 51 | 52 | getScriptHashUtxos(scripthash: string, args: { }, callback?: Function): Promise { 53 | const apiClient = new APIClient(this.options); 54 | return apiClient.scripthash_getUtxos({ 55 | scripthash, 56 | ...args 57 | }, callback); 58 | } 59 | 60 | getScriptHashHistory(scripthash: string, args: { }, callback?: Function): Promise { 61 | const apiClient = new APIClient(this.options); 62 | return apiClient.scripthash_getHistory(scripthash,{ 63 | ...args 64 | }, callback); 65 | } 66 | 67 | getUtxos(addrs: string, args: { offset?: number, limit?: number, afterHeight?: number, sort?: string}, callback?: Function): Promise { 68 | const apiClient = new APIClient(this.options); 69 | return apiClient.addresses_getUtxos({ 70 | addrs, 71 | ...args 72 | }, callback); 73 | } 74 | 75 | 76 | getBalance(addr: string, callback?: Function): Promise { 77 | const apiClient = new APIClient(this.options); 78 | return apiClient.address_getBalance(addr, callback); 79 | } 80 | 81 | getBalanceBatch(addrs: string[], callback?: Function): Promise { 82 | const apiClient = new APIClient(this.options); 83 | return apiClient.address_getBalanceBatch(addrs, callback); 84 | } 85 | 86 | getHistory(addr: string, args?: {from?: number, to?: number }, callback?: Function): Promise { 87 | const apiClient = new APIClient(this.options); 88 | return apiClient.address_getHistory(addr, args, callback); 89 | } 90 | 91 | getHistoryBatch(addrs: string[], args?: {from?: number, to?: number }, callback?: Function): Promise { 92 | const apiClient = new APIClient(this.options); 93 | return apiClient.address_getHistoryBatch(addrs, args, callback); 94 | } 95 | 96 | getTx(txid: string, callback?: Function): Promise { 97 | const apiClient = new APIClient(this.options); 98 | return apiClient.tx_getTransaction(txid, callback); 99 | } 100 | 101 | getTxRaw(txid: string, callback?: Function): Promise { 102 | const apiClient = new APIClient(this.options); 103 | return apiClient.tx_getRawTransaction(txid, callback); 104 | } 105 | 106 | getTxBatch(txids: string[], callback?: Function): Promise { 107 | const apiClient = new APIClient(this.options); 108 | return apiClient.tx_getTransactionsBatch(txids, callback); 109 | } 110 | 111 | // @Deprecated 112 | // Use merchantapi mapi.submitTx 113 | sendRawTx(rawtx: string, callback?: Function): Promise { 114 | const apiClient = new APIClient(this.options); 115 | return apiClient.sendRawTx(rawtx, callback); 116 | } 117 | // @Deprecated 118 | // Use merchantapi mapi.submitTx 119 | merchantTxBroadcast(rawtx: string, callback?: Function): Promise { 120 | const apiClient = new APIClient(this.options); 121 | return apiClient.merchants_broadcastTx(rawtx, callback); 122 | } 123 | // @Deprecated 124 | // Use merchantapi mapi.getTxStatus 125 | merchantTxStatus(txid: string, callback?: Function): Promise { 126 | const apiClient = new APIClient(this.options); 127 | return apiClient.merchants_statusTx(txid, callback); 128 | } 129 | 130 | get mapi() { 131 | return new MerchantApi(this.options); 132 | } 133 | 134 | static instance(newOptions?: any): MatterCloud { 135 | const mergedOptions = Object.assign({}, defaultOptions, newOptions); 136 | return new MatterCloud(mergedOptions); 137 | } 138 | } 139 | 140 | export function instance(newOptions?: any): MatterCloud { 141 | const mergedOptions = Object.assign({}, defaultOptions, newOptions); 142 | return new MatterCloud(mergedOptions); 143 | } 144 | 145 | export function mapi(newOptions?: any): MerchantApi { 146 | const mergedOptions = Object.assign({}, defaultOptions, newOptions); 147 | return new MerchantApi(mergedOptions); 148 | } 149 | 150 | try { 151 | if (window) { 152 | window['mattercloud'] = new MatterCloud(); 153 | window['merchantapi'] = new MerchantApi(); 154 | } 155 | } 156 | catch (ex) { 157 | // Window is not defined, must be running in windowless env.... 158 | } 159 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mattercloudjs", 3 | "version": "1.1.2", 4 | "description": "MatterCloud Javascript SDK - https://www.mattercloud.net", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "scripts": { 8 | "build": "tsc && gulp build", 9 | "test": "mocha --reporter spec", 10 | "test_address": "mocha --reporter spec --grep address", 11 | "test_tx": "mocha --reporter spec --grep transaction", 12 | "test_curr": "mocha --reporter spec --grep CURRENT_TEST", 13 | "test_merchants": "mocha --reporter spec --grep merchants", 14 | "test_sse": "mocha --reporter spec --grep sse", 15 | "test_mapi": "mocha --reporter spec --grep mapi", 16 | "test_block": "mocha --reporter spec --grep block", 17 | "test_current": "mocha --reporter spec --grep current", 18 | "test_minercraft": "mocha --reporter spec --grep minercraft", 19 | "prepare": "npm run build" 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "git+https://github.com/MatterCloud/mattercloudjs.git" 24 | }, 25 | "author": "MatterCloud - Matter Web Services Inc.", 26 | "license": "Open BSV", 27 | "bugs": { 28 | "url": "https://github.com/MatterCloud/mattercloudjs/issues" 29 | }, 30 | "keywords": [ 31 | "bitcoin", 32 | "bsv", 33 | "bitcoin-sv", 34 | "metanet", 35 | "blockchain", 36 | "mattercloud", 37 | "satoshi", 38 | "satoshi-vision" 39 | ], 40 | "homepage": "https://github.com/MatterCloud/mattercloudjs#readme", 41 | "devDependencies": { 42 | "@babel/cli": "^7.1.2", 43 | "@babel/core": "^7.1.2", 44 | "@babel/plugin-transform-arrow-functions": "^7.0.0", 45 | "@babel/preset-env": "^7.1.0", 46 | "babelify": "^10.0.0", 47 | "browserify": "^16.2.3", 48 | "browserify-shim": "^3.8.14", 49 | "chai": "^4.2.0", 50 | "gulp": "^3.9.1", 51 | "gulp-batch": "^1.0.5", 52 | "gulp-clean-css": "^3.10.0", 53 | "gulp-clone": "^2.0.1", 54 | "gulp-concat": "^2.6.1", 55 | "gulp-concat-css": "^3.1.0", 56 | "gulp-cssimport": "^6.0.1", 57 | "gulp-foreach": "^0.1.0", 58 | "gulp-header": "^2.0.7", 59 | "gulp-htmlmin": "^5.0.1", 60 | "gulp-less": "^4.0.1", 61 | "gulp-livereload": "^4.0.0", 62 | "gulp-sass": "^4.0.1", 63 | "gulp-sourcemaps": "^2.6.5", 64 | "gulp-typescript": "^5.0.1", 65 | "gulp-uglify": "^3.0.2", 66 | "gulp-uglify-es": "^1.0.4", 67 | "gulp-watch": "^5.0.1", 68 | "minercraft": "0.0.2", 69 | "mocha": "^5.2.0", 70 | "streamqueue": "^1.1.2", 71 | "tsify": "^4.0.1", 72 | "typescript": "^3.3.3", 73 | "vinyl-buffer": "^1.0.1", 74 | "vinyl-source-stream": "^2.0.0" 75 | }, 76 | "dependencies": { 77 | "axios": "^0.18.0", 78 | "eventsource": "^1.0.7" 79 | }, 80 | "files": [ 81 | "dist/*" 82 | ] 83 | } 84 | -------------------------------------------------------------------------------- /test/address.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var expect = require('chai').expect; 3 | var index = require('../dist/index.js'); 4 | 5 | const options = { 6 | api_key: '', 7 | // api_url: 'http://localhost:3000', 8 | // api_url: 'http://ec2-54-201-191-162.us-west-2.compute.amazonaws.com', 9 | }; 10 | 11 | describe('#getBalance', () => { 12 | it('should fail with invalid address', async () => { 13 | try { 14 | await index.instance(options).getBalance('address'); 15 | } catch (ex) { 16 | expect(ex).to.eql({ success: false, code: 422, message: 'address invalid', error: 'address invalid' }); 17 | } 18 | }); 19 | 20 | it('should fail with invalid address (callback)', (done) => { 21 | 22 | index.instance(options).getBalance('address', async (data, err) => { 23 | expect(err).to.eql({ success: false, code: 422, message: 'address invalid', error: 'address invalid' }); 24 | expect(data).to.eql(null); 25 | done(); 26 | }); 27 | 28 | }); 29 | 30 | it('should succeed with getting getBalance', async () => { 31 | var result = await index.instance(options).getBalance('12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX'); 32 | expect(result).to.eql( 33 | { 34 | "address": "12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX", 35 | "confirmed":30055, 36 | "unconfirmed": 0, 37 | } 38 | ); 39 | }); 40 | 41 | it('should succeed with getting getBalance (callback)', (done) => { 42 | index.instance(options).getBalance('12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX', async (data, err) => { 43 | expect(data).to.eql( 44 | { 45 | "address": "12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX", 46 | "confirmed":30055, 47 | "unconfirmed": 0, 48 | } 49 | ); 50 | expect(err).to.eql(undefined); 51 | done(); 52 | }); 53 | }); 54 | 55 | it('should succeed with getting getBalance batch', async () => { 56 | var result = await index.instance(options).getBalanceBatch(['12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX', '1XeMYaLJX6rhXcRe2XtGh6hgstgXwZ5SD']); 57 | expect(result).to.eql( 58 | [ 59 | { 60 | "address": "12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX", 61 | "confirmed":30055, 62 | "unconfirmed": 0, 63 | }, 64 | { 65 | "address": "1XeMYaLJX6rhXcRe2XtGh6hgstgXwZ5SD", 66 | "confirmed":15411, 67 | "unconfirmed": 0, 68 | } 69 | ] 70 | ); 71 | }); 72 | }); 73 | 74 | describe('#getBalanceBatch', () => { 75 | 76 | it('should succeed with getting getBalance batch', async () => { 77 | var result = await index.instance(options).getBalanceBatch(['12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX', '1XeMYaLJX6rhXcRe2XtGh6hgstgXwZ5SD']); 78 | expect(result).to.eql( 79 | [ 80 | { 81 | "address": "12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX", 82 | "confirmed":30055, 83 | "unconfirmed": 0, 84 | }, 85 | { 86 | "address": "1XeMYaLJX6rhXcRe2XtGh6hgstgXwZ5SD", 87 | "confirmed":15411, 88 | "unconfirmed": 0, 89 | } 90 | ] 91 | ); 92 | }); 93 | }); 94 | 95 | describe('#getUtxos', () => { 96 | it('should fail with invalid address', async () => { 97 | try { 98 | await index.instance(options).getUtxos('address'); 99 | } catch (ex) { 100 | expect(ex).to.eql({ success: false, code: 422, error: 'address invalid', message: 'address invalid' }); 101 | } 102 | }); 103 | 104 | it('should succeed with getting utxos with options', async () => { 105 | var result = await index.instance(options).getUtxos('12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX', { 106 | afterHeight: 576167, sort: 'value:desc' 107 | }); 108 | expect(result.length).to.eql(1); 109 | delete result[0].confirmations; 110 | 111 | expect(result).to.eql( 112 | [ 113 | { 114 | address: '12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX', 115 | txid: '5e3014372338f079f005eedc85359e4d96b8440e7dbeb8c35c4182e0c19a1a12', 116 | vout: 0, 117 | outputIndex: 0, 118 | amount: 0.00015399, 119 | satoshis: 15399, 120 | value: 15399, 121 | height: 576168, 122 | // confirmations: 1, 123 | "script": "76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac", 124 | scriptPubKey: '76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac' 125 | } 126 | ] 127 | ); 128 | var result = await index.instance(options).getUtxos(['12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX', '1XeMYaLJX6rhXcRe2XtGh6hgstgXwZ5SD'], { 129 | afterHeight: 576167, sort: 'value:desc' 130 | }); 131 | delete result[0].confirmations; 132 | delete result[1].confirmations; 133 | expect(result).to.eql( 134 | [ 135 | { 136 | "address": "1XeMYaLJX6rhXcRe2XtGh6hgstgXwZ5SD", 137 | "amount": 0.00015411, 138 | "height": 576171, 139 | "satoshis": 15411, 140 | "script": "76a91405cba91bd4ec7645df9a5c162877815f758c9b3888ac", 141 | "scriptPubKey": "76a91405cba91bd4ec7645df9a5c162877815f758c9b3888ac", 142 | "txid": "fcd2e37b0c9472fd81bc475e98193caa61581f3ded6c50e843d9c2e1ee5fdef6", 143 | "value": 15411, 144 | "vout": 0, 145 | outputIndex: 0, 146 | }, 147 | { 148 | address: '12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX', 149 | txid: '5e3014372338f079f005eedc85359e4d96b8440e7dbeb8c35c4182e0c19a1a12', 150 | vout: 0, 151 | outputIndex: 0, 152 | amount: 0.00015399, 153 | satoshis: 15399, 154 | value: 15399, 155 | height: 576168, 156 | // confirmations: 1, 157 | scriptPubKey: '76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac', 158 | script: '76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac' 159 | } 160 | ] 161 | ); 162 | }); 163 | 164 | it('should succeed with getting utxos', async () => { 165 | var result = await index.instance(options).getUtxos('12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX'); 166 | expect(result.length).to.eql(2); 167 | delete result[0].confirmations; 168 | delete result[1].confirmations; 169 | 170 | expect(result).to.eql( 171 | [ 172 | { 173 | address: '12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX', 174 | txid: '5e3014372338f079f005eedc85359e4d96b8440e7dbeb8c35c4182e0c19a1a12', 175 | vout: 0, 176 | outputIndex: 0, 177 | amount: 0.00015399, 178 | satoshis: 15399, 179 | value: 15399, 180 | height: 576168, 181 | // confirmations: 1, 182 | "script": "76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac", 183 | scriptPubKey: '76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac' 184 | }, 185 | { 186 | address: '12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX', 187 | txid: 188 | '96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6', 189 | vout: 1, 190 | outputIndex: 1, 191 | amount: 0.00014656, 192 | satoshis: 14656, 193 | value: 14656, 194 | height: 576025, 195 | // confirmations: 144, 196 | script: '76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac', 197 | scriptPubKey: '76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac' 198 | } 199 | ] 200 | ); 201 | var result = await index.instance(options).getUtxos(['12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX', '1XeMYaLJX6rhXcRe2XtGh6hgstgXwZ5SD']); 202 | delete result[0].confirmations; 203 | delete result[1].confirmations; 204 | delete result[2].confirmations; 205 | expect(result).to.eql( 206 | [ 207 | { 208 | "address": "1XeMYaLJX6rhXcRe2XtGh6hgstgXwZ5SD", 209 | "amount": 0.00015411, 210 | "height": 576171, 211 | "satoshis": 15411, 212 | "script": "76a91405cba91bd4ec7645df9a5c162877815f758c9b3888ac", 213 | "scriptPubKey": "76a91405cba91bd4ec7645df9a5c162877815f758c9b3888ac", 214 | "txid": "fcd2e37b0c9472fd81bc475e98193caa61581f3ded6c50e843d9c2e1ee5fdef6", 215 | "value": 15411, 216 | "vout": 0, 217 | outputIndex: 0, 218 | }, 219 | { 220 | address: '12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX', 221 | txid: '5e3014372338f079f005eedc85359e4d96b8440e7dbeb8c35c4182e0c19a1a12', 222 | vout: 0, 223 | outputIndex: 0, 224 | amount: 0.00015399, 225 | satoshis: 15399, 226 | value: 15399, 227 | height: 576168, 228 | // confirmations: 1, 229 | scriptPubKey: '76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac', 230 | script: '76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac' 231 | }, 232 | { 233 | address: '12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX', 234 | txid: 235 | '96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6', 236 | vout: 1, 237 | outputIndex: 1, 238 | amount: 0.00014656, 239 | satoshis: 14656, 240 | value: 14656, 241 | height: 576025, 242 | // confirmations: 144, 243 | scriptPubKey: '76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac', 244 | script: '76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac' 245 | } 246 | ] 247 | ); 248 | }); 249 | }); 250 | 251 | describe('#utxos batch', () => { 252 | it('should fail with invalid address', async () => { 253 | try { 254 | await index.instance(options).getUtxos(['asdfsf', '1XeMYaLJX6rhXcRe2XtGh6hgstgXwZ5SD']); 255 | } catch (ex) { 256 | expect(ex).to.eql({ success: false, code: 422, error: 'address invalid', message: 'address invalid' }); 257 | } 258 | 259 | }); 260 | 261 | it('should succeed with getting utxos', async () => { 262 | var result = await index.instance(options).getUtxos(['12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX', '1XeMYaLJX6rhXcRe2XtGh6hgstgXwZ5SD']); 263 | expect(result.length).to.eql(3); 264 | delete result[0].confirmations; 265 | delete result[1].confirmations; 266 | delete result[2].confirmations; 267 | 268 | expect(result).to.eql( 269 | [ 270 | { 271 | "address": "1XeMYaLJX6rhXcRe2XtGh6hgstgXwZ5SD", 272 | "amount": 0.00015411, 273 | "height": 576171, 274 | "satoshis": 15411, 275 | "script": "76a91405cba91bd4ec7645df9a5c162877815f758c9b3888ac", 276 | "scriptPubKey": "76a91405cba91bd4ec7645df9a5c162877815f758c9b3888ac", 277 | "txid": "fcd2e37b0c9472fd81bc475e98193caa61581f3ded6c50e843d9c2e1ee5fdef6", 278 | "value": 15411, 279 | "vout": 0, 280 | outputIndex: 0, 281 | }, 282 | { 283 | address: '12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX', 284 | txid: '5e3014372338f079f005eedc85359e4d96b8440e7dbeb8c35c4182e0c19a1a12', 285 | vout: 0, 286 | outputIndex: 0, 287 | amount: 0.00015399, 288 | satoshis: 15399, 289 | value: 15399, 290 | height: 576168, 291 | // confirmations: 1, 292 | scriptPubKey: '76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac', 293 | script: '76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac' 294 | }, 295 | { 296 | address: '12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX', 297 | txid: 298 | '96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6', 299 | vout: 1, 300 | outputIndex: 1, 301 | amount: 0.00014656, 302 | satoshis: 14656, 303 | value: 14656, 304 | height: 576025, 305 | // confirmations: 144, 306 | scriptPubKey: '76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac', 307 | script: '76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac' 308 | } 309 | ] 310 | ); 311 | }); 312 | }); 313 | 314 | 315 | describe('#getHistory', () => { 316 | 317 | it('should succeed with getting history', async () => { 318 | var result = await index.instance(options).getHistory('12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX'); 319 | expect(result).to.eql( 320 | { 321 | from: 0, 322 | to: 20, 323 | results: [ 324 | { 325 | "height": 576168, 326 | "txid": "5e3014372338f079f005eedc85359e4d96b8440e7dbeb8c35c4182e0c19a1a12" 327 | }, 328 | { 329 | "height": 576025, 330 | "txid": "bdf6f49776faaa4790af3e41b8b474a7d0d47df540f8d71c3579dc0addd64c45" 331 | }, 332 | { 333 | "height": 576025, 334 | "txid": "d834682a5d29646427e5627d38c10224036535fa7e3066ae2f7a163a96550e27" 335 | }, 336 | { 337 | "height": 576025, 338 | "txid": "96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6" 339 | } 340 | ] 341 | } 342 | ); 343 | }); 344 | 345 | it('should succeed with getting history with options', async () => { 346 | var args = { 347 | from: 1, 348 | to: 2 349 | }; 350 | var result = await index.instance(options).getHistory('12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX', args); 351 | expect(result).to.eql( 352 | { 353 | from: 1, 354 | to: 2, 355 | results: [ 356 | { 357 | "txid": "bdf6f49776faaa4790af3e41b8b474a7d0d47df540f8d71c3579dc0addd64c45", 358 | "height": 576025 359 | } 360 | ] 361 | } 362 | ); 363 | }); 364 | 365 | it('should fail with invalid range', async () => { 366 | var args = { 367 | from: 0, 368 | to: 21 369 | }; 370 | try { 371 | await index.instance(options).getHistory('12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX', args); 372 | } catch (ex) { 373 | expect(ex).to.eql({ success: false, code: 422, error: 'params invalid' , message: 'params invalid' }); 374 | } 375 | }); 376 | 377 | }); 378 | describe('#getHistoryBatch', () => { 379 | it('should succeed with getting history batch', async () => { 380 | var result = await index.instance(options).getHistoryBatch(['12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX', '1XeMYaLJX6rhXcRe2XtGh6hgstgXwZ5SD']); 381 | expect(result).to.eql( 382 | { 383 | "from": 0, 384 | "to": 20, 385 | "results": [ 386 | { 387 | "txid": "fcd2e37b0c9472fd81bc475e98193caa61581f3ded6c50e843d9c2e1ee5fdef6", 388 | "height": 576171 389 | }, 390 | { 391 | "txid": "5e3014372338f079f005eedc85359e4d96b8440e7dbeb8c35c4182e0c19a1a12", 392 | "height": 576168 393 | }, 394 | { 395 | "txid": "bdf6f49776faaa4790af3e41b8b474a7d0d47df540f8d71c3579dc0addd64c45", 396 | "height": 576025 397 | }, 398 | { 399 | "txid": "d834682a5d29646427e5627d38c10224036535fa7e3066ae2f7a163a96550e27", 400 | "height": 576025 401 | }, 402 | { 403 | "txid": "96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6", 404 | "height": 576025 405 | } 406 | ] 407 | } 408 | ); 409 | }); 410 | }); 411 | 412 | -------------------------------------------------------------------------------- /test/mapi.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var expect = require('chai').expect; 3 | var index = require('../dist/index.js'); 4 | 5 | const options = { 6 | api_key: '', 7 | // api_url: 'http://localhost:3000', 8 | }; 9 | 10 | describe('mapi #merchantTxBroadcast', () => { 11 | it('should get feeQuote', async () => { 12 | const result = await index.instance(options).mapi.getFeeQuote(); 13 | expect(result.encoding).to.eql('UTF-8'); 14 | const jsonParsed = JSON.parse(result.payload); 15 | expect(jsonParsed.fees).to.eql([ 16 | { 17 | "feeType": "standard", 18 | "miningFee": { 19 | "satoshis": 500, 20 | "bytes": 1000 21 | }, 22 | "relayFee": { 23 | "satoshis": 250, 24 | "bytes": 1000 25 | } 26 | }, 27 | { 28 | "feeType": "data", 29 | "miningFee": { 30 | "satoshis": 500, 31 | "bytes": 1000 32 | }, 33 | "relayFee": { 34 | "satoshis": 250, 35 | "bytes": 1000 36 | } 37 | } 38 | ]); 39 | }); 40 | 41 | it('should not get non existent transaction', async () => { 42 | try { 43 | await index.instance(options).mapi.getTxStatus('txid'); 44 | } catch (ex) { 45 | delete ex.timestamp; 46 | expect(ex).to.eql({ 47 | "code": 422, 48 | "error": "txid invalid", 49 | "message": "txid invalid", 50 | "success": false 51 | }); 52 | } 53 | }); 54 | 55 | it('should get existing transaction status', async () => { 56 | const result = await index.instance(options).mapi.getTxStatus('8c5d0bbe680b6ea8b9f91d38ba82859e89ef5e40c748a33ac30a5f33f06fda83'); 57 | expect(result.encoding).to.eql('UTF-8'); 58 | const jsonParsed = JSON.parse(result.payload); 59 | expect(jsonParsed.returnResult).to.eql('success'); 60 | expect(jsonParsed.blockHash).to.eql('000000000000000005b2f147af2cd46abc20e150cf2f6df0c1fdf4474d47a28b'); 61 | expect(jsonParsed.blockHeight).to.eql(630908); 62 | }); 63 | 64 | it('should return transaction not found', async () => { 65 | const result = await index.instance(options).mapi.getTxStatus('ac5d0bbe680b6ea8b9f91d38ba82859e89ef5e40c748a33ac30a5f33f06fda83'); 66 | expect(result.publicKey).to.eql('0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087'); 67 | const jsonParsed = JSON.parse(result.payload); 68 | expect(jsonParsed.returnResult).to.eql('failure'); 69 | expect(jsonParsed.resultDescription).to.eql('ERROR: No such mempool or blockchain transaction. Use gettransaction for wallet transactions.'); 70 | expect(jsonParsed.blockHash).to.eql(null); 71 | expect(jsonParsed.blockHeight).to.eql(null); 72 | }); 73 | 74 | it('should get transaction still in mempool (change me to new tx)', async () => { 75 | const result = await index.instance(options).mapi.getTxStatus('acd54d05f9edc03de2fd4b1f67fd12b59d744e7a4de1635be4e60a5dcdd7777f'); 76 | const jsonParsed = JSON.parse(result.payload); 77 | expect(jsonParsed.returnResult).to.eql('success'); 78 | expect(jsonParsed.resultDescription).to.eql(''); 79 | }); 80 | 81 | it('current should try to rebroadcast existing transaction', async () => { 82 | const result = await index.instance(options).mapi.submitTx('0100000001791daaaba5c9a1f1a1a95262b2e466bd129a6f92895925b2ca048f58c92ca350010000006a473044022033639b05b40f07a8dab1d104b716570a2f4fb5d28e17192400297f43860846640220294ab0d9124d45e3c656df4bc9ca5fcbffb6639d9563b98dfff6a5558f1d9c25412102e66efb4f5e6dded4047fe100f7f3436ae7e50954cf96978d38d13e91d95e92e0ffffffff020000000000000000bb006a22313964627a4d444467346a5a347076597a4c623239316e5438754371446136317a4801024c647b2262697466696e6578223a7b226c223a302e3032373630372c2276223a39327d2c2262697474726578223a7b226c223a302e3032373539372c2276223a3138357d2c22706f6c6f6e696578223a7b226c223a302e3032373630392c2276223a36307d7d22314c744870556b544d554c514b4e6e413452654159334558425879654d76355532720a31353837303734323230697e0000000000001976a914da1da4b5bbafd6c552c4187a41beec1462a6cce888ac00000000'); 83 | const jsonParsed = JSON.parse(result.payload); 84 | expect(jsonParsed.returnResult).to.eql('failure'); 85 | expect(jsonParsed.resultDescription).to.eql('ERROR: Missing inputs'); 86 | expect(!!jsonParsed.currentHighestBlockHash).to.eql(true); 87 | expect(!!jsonParsed.currentHighestBlockHeight).to.eql(true); 88 | }); 89 | 90 | it('current should try to broadcast bad transacttion', async () => { 91 | const result = await index.instance(options).mapi.submitTx('01000000012ce28ac533ac314932ab436e8cacc46e46e82e806f4d0d36cef4047e2479f04b010000006b483045022100faf6ec3560350df8aba10c4a7109cfed628cae7bd71ce19d97ebf408a647eca2022031cbbead9978624b9f2066d7598dcde22d6389a8fdef9669e2d047acb938cb49412102119ebe4639964590bcf358539740f8ea4b6546b8416cbbbf6de12fafd3a13d1affffffff020000000000000000176a026d0212706f737420746f206d656d6f2e6361736821ad500200000000001976a914161e9c31fbec37d9ecb297bf4b814c6e189dbe5288ac00000000'); 92 | const jsonParsed = JSON.parse(result.payload); 93 | expect(jsonParsed.returnResult).to.eql('failure'); 94 | expect(jsonParsed.resultDescription).to.eql('ERROR: 64: dust'); 95 | }); 96 | }); 97 | 98 | describe('merchants #merchantTxBroadcast', () => { 99 | it('should succed to send again', async () => { 100 | const result = await index.instance(options).merchantTxBroadcast('0100000001394bfd979d2850fe5805f394d38ddac608f20d55db04d3aba9cb27465b9bdf86000000006a47304402205004d188511471b3e7811ddeca9bcfcd1efe7080719d0e99c6807b8d16cefda6022043d13337f3dc9f59e08b00315a37d7b0dc522440b358b5d8a187d2e6e5d5f8d0412102288596fa8af85d0a8b988049d1563596fbdf546407fdd814a23ed4d0a9fe9a20ffffffff025f120000000000001976a914a968c5d8f0b26f24089e587f2b46101968e4196888ac40140000000000001976a914acc4348a20483fd1f44b0ba54827f016edf3d29588ac00000000'); 101 | expect(result).to.eql({ 102 | success: true, 103 | result: { 104 | "txid": "5205318c1ec8926ba31ab6358c5ae7a08347d13b5c5c87e9a6fe3349f112491c" 105 | } 106 | }); 107 | }); 108 | }); 109 | 110 | describe('merchants #merchantTxBroadcast', () => { 111 | it('should succed to send', async () => { 112 | const result = await index.instance(options).merchantTxBroadcast('0100000001c8a78a47a63cc8378ee1abb29b00fee57f54700008907b2cc212fd1077f46229010000006a47304402207ca8de8bbc656f7df9f99790b61799e7745d12d354a1f346a20fbc32cc76e045022005e5536c5c8997670566d693f725072cec9db8d24aa048caad1108e0400bfcd2412103b1fa158185120c1266ff328964446cdb5816a37b2668411e847b4d2395a6a265ffffffff02273c0000000000001976a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac43c40e00000000001976a914256b0efdfc907d12125c4fbb1754b38e7c8b1a1788ac00000000'); 113 | expect(result).to.eql({ 114 | success: true, 115 | result: { 116 | "txid": "5e3014372338f079f005eedc85359e4d96b8440e7dbeb8c35c4182e0c19a1a12" 117 | } 118 | }); 119 | }); 120 | }); 121 | 122 | describe('merchants #merchantTxBroadcast', () => { 123 | it('should succeed to send (existing tx)', async () => { 124 | const result = await index.instance(options).merchantTxBroadcast('0100000001c8a78a47a63cc8378ee1abb29b00fee57f54700008907b2cc212fd1077f46229010000006a47304402207ca8de8bbc656f7df9f99790b61799e7745d12d354a1f346a20fbc32cc76e045022005e5536c5c8997670566d693f725072cec9db8d24aa048caad1108e0400bfcd2412103b1fa158185120c1266ff328964446cdb5816a37b2668411e847b4d2395a6a265ffffffff02273c0000000000001976a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac43c40e00000000001976a914256b0efdfc907d12125c4fbb1754b38e7c8b1a1788ac00000000'); 125 | expect(result.success).to.eql(true); 126 | }); 127 | }); 128 | 129 | describe('merchants #merchantTxBroadcast', () => { 130 | it('should fail to send', async () => { 131 | try { 132 | await index.instance(options).merchantTxBroadcast('0100000001c02e9849efc62331af4e0a7be4a4be4b3d315f637b3fde735e2ab67ee464d1ac010000006a4730440220099bb922ab524368c370d5f882a576d052097bf1f94cebe36edd387b2e0ea2cf02206522a2e32f82ff7e975a70f39e73013b41642208e3f6ab9c9955a446e4b947bb412102119ebe4639964590bcf358539740f8ea4b6546b8416cbbbf6de12fafd3a13d1affffffff020000000000000000176a026d0212706f737420746f206d656d6f2e6361736821ba730200000000001976a914161e9c31fbec37d9ecb297bf4b814c6e189dbe5288ac00000000'); 133 | expect(false).to.eql(true); 134 | } catch (ex) { 135 | expect(ex).to.eql({ success: false, code: 422, error: 'DUST', message: 'DUST' }); 136 | } 137 | }); 138 | }); 139 | 140 | describe('merchants #merchantTxStatus', () => { 141 | it('should fail to send invalid address', async () => { 142 | try { 143 | await index.instance(options).merchantTxStatus('i34222invalid'); 144 | expect(false).to.eql(true); 145 | } catch (ex) { 146 | expect(ex).to.eql({ success: false, code: 422, error: 'txid invalid', message: 'txid invalid' }); 147 | } 148 | }); 149 | 150 | it('should not found transaction', async () => { 151 | try { 152 | await index.instance(options).merchantTxStatus('149a217f3a9eac4611688e44f3d5508cf8c711e6b583bb08bcff54dcda124ee5'); 153 | expect(false).to.eql(true); 154 | } catch (ex) { 155 | expect(ex).to.eql({ success: false, code: 404, error: 'TX_NOT_FOUND', message: 'TX_NOT_FOUND' }); 156 | } 157 | }); 158 | /* 159 | it('should build and send tx', async () => { 160 | filepay.build({ 161 | data: [ 162 | ['0x4311', 'hello world'], 163 | ], 164 | pay: { 165 | key: privateKey, 166 | } 167 | }, async (err, data) => { 168 | if (err){ 169 | expect(false).to.eql(true); 170 | return; 171 | } 172 | try { 173 | const tx = new bsv.Transaction(data); 174 | console.log('data.toString()', tx, data.toString()); 175 | 176 | const result = await index.instance(options).merchantTxBroadcast(data.toString()); 177 | expect(result).to.eql({ 178 | success: true, 179 | result: { 180 | txid: tx.toObject().hash 181 | } 182 | }); 183 | } catch (ex) { 184 | expect(false).to.eql(true); 185 | return; 186 | } 187 | }); 188 | }); 189 | */ 190 | it('merchants Retrieve status success', async () => { 191 | 192 | const result = await index.instance(options).merchantTxStatus('349a217f3a9eac4611688e44f3d5508cf8c711e6b583bb08bcff54dcda124ee5'); 193 | delete result.result.confirmations; 194 | expect(result).to.eql({ 195 | success: true, 196 | result: { 197 | "txid": "349a217f3a9eac4611688e44f3d5508cf8c711e6b583bb08bcff54dcda124ee5", 198 | "blockhash": "0000000000000000012c4624da90017fc6b636b926675be0c6f46e178ddc92b7", 199 | "blocktime": 1582991571, 200 | "time": 1582991571, 201 | "fees": 0.00000615, 202 | "size": 515, 203 | "valueIn": 0.003, 204 | "valueOut": 0.00299385, 205 | } 206 | }); 207 | }); 208 | 209 | }); -------------------------------------------------------------------------------- /test/minercraft.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var expect = require('chai').expect; 3 | var Minercraft = require('minercraft'); 4 | 5 | describe('minercraft', () => { 6 | it('should query with minercraft getFeeQuote', async () => { 7 | const miner = new Minercraft({ 8 | "url": "https://merchantapi.matterpool.io" 9 | }) 10 | 11 | let rate = await miner.fee.rate() 12 | expect(rate).to.eql({ standard: { mine: 0.5, relay: 0.25 }, 13 | data: { mine: 0.5, relay: 0.25 } }); 14 | }); 15 | 16 | it('should query fees and estimate tx fee cost', async () => { 17 | const miner = new Minercraft({ 18 | "url": "https://merchantapi.matterpool.io" 19 | }) 20 | let rate = await miner.fee.rate() 21 | expect(rate).to.eql({ standard: { mine: 0.5, relay: 0.25 }, 22 | data: { mine: 0.5, relay: 0.25 } }); 23 | 24 | let fee = miner.fee.get({ 25 | rate: rate, 26 | tx: "0100000001648ed7d1c1a27ec923445c8d404e227145218c4ce01cf958a898c5a048e8f264020000006a47304402207dc1953455be091c8df18e7f7e1424bc4efdced3e400642f8316e3ef298c3f30022062d833b3f1b94593ec7c088b930e2987475c7d99bf19f5714b12a9facff100df41210273f105be3e7ca116e96c7c40f17267ae05ede7160eb099aa2146a88b6328f4ecffffffff030000000000000000fdc901006a223144535869386876786e36506434546176686d544b7855374255715337636e7868770c57544458565633505a4b474414e5ae89e5bebd2fe585ade5ae892fe99c8de982b119323032302d30342d30365430363a30303a30302b30383a30304c697b22617169223a223538222c22706d3235223a223332222c22706d3130223a223636222c22736f32223a2235222c226e6f32223a223235222c22636f223a22302e373530222c226f33223a223635222c22706f6c223a22504d3130222c22717561223a22e889af227d4cfb78da75d1c16a02311006e077c959964cb29944dfa1d07bf1209e0a6b57b137114aaf2d2d5e446d7b29d59e3c492f22f834d9ea5b3859e826bba4b73fc34cf898b999b0dee89675184ad662c3815094a5293370ca1a298f73415151ba2b9370cdfd9c124f34c55c563fe419c5eb2b9aa5b1fb1e3d7edf66c5cf93fdfa2ed6072a66ae2621d15203775d99fb070013c50da7cab45599c09b04062688999437993f53d91933ade6a7f5d16e37e7e5676842307553aa1b2685c19e02137a93a94c92c74c69dc54bc7f9c173bfbf21882745b379784a60e0a0f071ea4fce1a45f521a399cfae770f6f0605f67f6795f0381688010dd1da7dd0b690c97db22020000000000001976a914666675d887a7ae09835af934096d9fcbbb70eed288ac61290000000000001976a9149e7520bc258934a3d58704ab98ed0200e2c1bb9688ac00000000" 27 | }) 28 | // todo why does the fee return NAN ? 29 | }); 30 | 31 | it('should query tx status', async () => { 32 | const miner = new Minercraft({ 33 | "url": "https://merchantapi.matterpool.io" 34 | }) 35 | let status = await miner.tx.status("e4763d71925c2ac11a4de0b971164b099dbdb67221f03756fc79708d53b8800e") 36 | delete status.timestamp; 37 | delete status.confirmations; 38 | expect(status).to.eql({ 39 | apiVersion: '0.1.0', 40 | returnResult: 'success', 41 | resultDescription: '', 42 | blockHash: '000000000000000000983dee680071d63939f4690a8a797c022eddadc88f925e', 43 | blockHeight: 630712, 44 | minerId: '0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087', 45 | txSecondMempoolExpiry: 0 46 | }); 47 | }); 48 | 49 | it('should post an existing transaction', async () => { 50 | const miner = new Minercraft({ 51 | "url": "https://merchantapi.matterpool.io", 52 | headers: { 53 | 'Content-Type': 'application/json' 54 | } 55 | }) 56 | let status = await miner.tx.push("0100000001648ed7d1c1a27ec923445c8d404e227145218c4ce01cf958a898c5a048e8f264020000006a47304402207dc1953455be091c8df18e7f7e1424bc4efdced3e400642f8316e3ef298c3f30022062d833b3f1b94593ec7c088b930e2987475c7d99bf19f5714b12a9facff100df41210273f105be3e7ca116e96c7c40f17267ae05ede7160eb099aa2146a88b6328f4ecffffffff030000000000000000fdc901006a223144535869386876786e36506434546176686d544b7855374255715337636e7868770c57544458565633505a4b474414e5ae89e5bebd2fe585ade5ae892fe99c8de982b119323032302d30342d30365430363a30303a30302b30383a30304c697b22617169223a223538222c22706d3235223a223332222c22706d3130223a223636222c22736f32223a2235222c226e6f32223a223235222c22636f223a22302e373530222c226f33223a223635222c22706f6c223a22504d3130222c22717561223a22e889af227d4cfb78da75d1c16a02311006e077c959964cb29944dfa1d07bf1209e0a6b57b137114aaf2d2d5e446d7b29d59e3c492f22f834d9ea5b3859e826bba4b73fc34cf898b999b0dee89675184ad662c3815094a5293370ca1a298f73415151ba2b9370cdfd9c124f34c55c563fe419c5eb2b9aa5b1fb1e3d7edf66c5cf93fdfa2ed6072a66ae2621d15203775d99fb070013c50da7cab45599c09b04062688999437993f53d91933ade6a7f5d16e37e7e5676842307553aa1b2685c19e02137a93a94c92c74c69dc54bc7f9c173bfbf21882745b379784a60e0a0f071ea4fce1a45f521a399cfae770f6f0605f67f6795f0381688010dd1da7dd0b690c97db22020000000000001976a914666675d887a7ae09835af934096d9fcbbb70eed288ac61290000000000001976a9149e7520bc258934a3d58704ab98ed0200e2c1bb9688ac00000000") 57 | delete status.currentHighestBlockHash; 58 | delete status.currentHighestBlockHeight; 59 | delete status.timestamp; 60 | expect(status).to.eql({ 61 | apiVersion: '0.1.0', 62 | "returnResult": "failure", 63 | "resultDescription": "ERROR: Missing inputs", 64 | txid: '', 65 | minerId: '0211ccfc29e3058b770f3cf3eb34b0b2fd2293057a994d4d275121be4151cdf087', 66 | txSecondMempoolExpiry: 0 67 | }); 68 | }); 69 | }); -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --timeout 60000 2 | 3 | -------------------------------------------------------------------------------- /test/script.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var expect = require('chai').expect; 3 | var index = require('../dist/index.js'); 4 | 5 | const options = { 6 | api_key: '', 7 | // api_url: 'http://localhost:3000', 8 | // api_url: 'https://api.mattercloud.net', 9 | }; 10 | 11 | describe('#getScriptHashUtxos', () => { 12 | it('should fail with invalid script', async () => { 13 | try { 14 | await index.instance(options).getScriptHashUtxos('address'); 15 | } catch (ex) { 16 | // todo use 422 instead 17 | expect(ex).to.eql({ success: false, code: 404, error: '', message: '' }); 18 | } 19 | }); 20 | 21 | it('should succeed with getting utxos', async () => { 22 | var result = await index.instance(options).getScriptHashUtxos('03b508a9da0879dd55619e06f5bd656696f77ba879aaa99e0eb22cedd7dd4846', { 23 | afterHeight: 576167, sort: 'value:desc' 24 | }); 25 | expect(result.length).to.eql(1); 26 | delete result[0].confirmations; 27 | 28 | expect(result).to.eql( 29 | [ 30 | { 31 | "scripthash": "03b508a9da0879dd55619e06f5bd656696f77ba879aaa99e0eb22cedd7dd4846", 32 | "txid": "dc36f3baa9b7e96827928760c07a160579b0a531814e3a3900c1c4112c4a92e7", 33 | "vout": 0, 34 | "amount": 0.00004363, 35 | "satoshis": 4363, 36 | "value": 4363, 37 | "height": 625311, 38 | // "confirmations": 65, 39 | "outputIndex": 0 40 | } 41 | ] 42 | ); 43 | }); 44 | }); 45 | 46 | describe('#getScriptHashHistory', () => { 47 | 48 | it('should succeed with getting history', async () => { 49 | var result = await index.instance(options).getScriptHashHistory('03b508a9da0879dd55619e06f5bd656696f77ba879aaa99e0eb22cedd7dd4846'); 50 | expect(result).to.eql( 51 | { 52 | success: true, 53 | from: 0, 54 | to: 99999, 55 | results: [ 56 | { 57 | "txid": "dc36f3baa9b7e96827928760c07a160579b0a531814e3a3900c1c4112c4a92e7", 58 | "height": 625311 59 | } 60 | ] 61 | } 62 | ); 63 | }); 64 | 65 | }); 66 | 67 | 68 | -------------------------------------------------------------------------------- /test/sse.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var expect = require('chai').expect; 3 | var index = require('../dist/index.js'); 4 | var EventSource = require('eventsource'); 5 | 6 | const options = { 7 | api_key: '', 8 | // api_url: 'http://localhost:3000', 9 | // api_url: 'https://api.mattercloud.net', 10 | }; 11 | 12 | describe('#sse', () => { 13 | // Todo 14 | /*it('listen to events', async () => { 15 | var es = new EventSource('http://localhost:8081/stream'); 16 | 17 | es.onmessage = function (event) { 18 | console.log('event', event); 19 | }; 20 | 21 | es.addEventListener('any', function (event) { 22 | console.log('eventName', eventName, event); 23 | }); 24 | });*/ 25 | }); 26 | 27 | -------------------------------------------------------------------------------- /test/transaction.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var expect = require('chai').expect; 3 | var index = require('../dist/index.js'); 4 | 5 | const options = { 6 | api_key: '', 7 | // api_url: 'http://localhost:3000', 8 | // api_url: 'https://api.mattercloud.net', 9 | }; 10 | describe('#tx', () => { 11 | it('should fail with invalid tx', async () => { 12 | try { 13 | await index.instance(options).getTx('tx'); 14 | } catch (ex) { 15 | expect(ex).to.eql({ success: false, code: 404, error: '', message: '' }); 16 | } 17 | }); 18 | 19 | it('should succeed single', async () => { 20 | var result = await index.instance(options).getTx('96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6'); 21 | delete result.confirmations; 22 | expect(result).to.eql( 23 | { 24 | "txid":"96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6", 25 | "hash":"96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6", 26 | "size":301, 27 | "version":1, 28 | "locktime":0, 29 | "vin":[ 30 | { 31 | "value":0.00015058, 32 | "valueSat":15058, 33 | "txid":"d834682a5d29646427e5627d38c10224036535fa7e3066ae2f7a163a96550e27", 34 | "vout":1, 35 | "scriptSig":{ 36 | "asm":"30440220132f6d484de9d34d314aec945865af5da95f35cf4c7cc271d40bc99f8d7f12e3022051fcb2ce4461d1c6e8a778f5e4dcb27c8461d18e0652f68a7a09a98e95df5cb7[ALL|FORKID] 044e2c1e2c055e7aefc291679882382c35894a6aa6dd95644f598e506c239f9d83b1d9671c1d9673e3c2b74f07e8032343f3adc21367bd4cffae92fe31efcd598a", 37 | "hex":"4730440220132f6d484de9d34d314aec945865af5da95f35cf4c7cc271d40bc99f8d7f12e3022051fcb2ce4461d1c6e8a778f5e4dcb27c8461d18e0652f68a7a09a98e95df5cb74141044e2c1e2c055e7aefc291679882382c35894a6aa6dd95644f598e506c239f9d83b1d9671c1d9673e3c2b74f07e8032343f3adc21367bd4cffae92fe31efcd598a" 38 | }, 39 | "addr":"12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX", 40 | "address":"12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX", 41 | "sequence":4294967295 42 | } 43 | ], 44 | "vout":[ 45 | { 46 | "value":0, 47 | "valueSat":0, 48 | "n": 0, 49 | "scriptPubKey":{ 50 | "asm":"OP_RETURN 31394878696756345179427633744870515663554551797131707a5a56646f417574 1717859169 746578742f6d61726b646f776e 5554462d38 616e6f74686572", 51 | "hex":"6a2231394878696756345179427633744870515663554551797131707a5a56646f41757404617364660d746578742f6d61726b646f776e055554462d3807616e6f74686572", 52 | "type":"nulldata" 53 | }, 54 | }, 55 | { 56 | "value":0.00014656, 57 | "valueSat":14656, 58 | "n": 1, 59 | "scriptPubKey":{ 60 | "asm":"OP_DUP OP_HASH160 10bdcba3041b5e5517a58f2e405293c14a7c70c1 OP_EQUALVERIFY OP_CHECKSIG", 61 | "hex":"76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac", 62 | "reqSigs":1, 63 | "type":"pubkeyhash", 64 | "addresses":[ 65 | "12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX" 66 | ] 67 | }, 68 | } 69 | ], 70 | "blockhash":"0000000000000000078f34d9cd3f48e4948aef4c79548ec777050e1c8953a85c", 71 | "blockheight": 576025, 72 | "time":1554007897, 73 | "blocktime":1554007897, 74 | "valueIn":0.00015058, 75 | "fees":0.00000402, 76 | "valueOut":0.00014656, 77 | "rawtx":"0100000001270e55963a167a2fae66307efa3565032402c1387d62e5276464295d2a6834d8010000008a4730440220132f6d484de9d34d314aec945865af5da95f35cf4c7cc271d40bc99f8d7f12e3022051fcb2ce4461d1c6e8a778f5e4dcb27c8461d18e0652f68a7a09a98e95df5cb74141044e2c1e2c055e7aefc291679882382c35894a6aa6dd95644f598e506c239f9d83b1d9671c1d9673e3c2b74f07e8032343f3adc21367bd4cffae92fe31efcd598affffffff020000000000000000456a2231394878696756345179427633744870515663554551797131707a5a56646f41757404617364660d746578742f6d61726b646f776e055554462d3807616e6f7468657240390000000000001976a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac00000000" 78 | } 79 | ); 80 | }); 81 | 82 | it('should succeed single rawtx', async () => { 83 | var result = await index.instance(options).getTxRaw('96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6'); 84 | expect(result).to.eql('0100000001270e55963a167a2fae66307efa3565032402c1387d62e5276464295d2a6834d8010000008a4730440220132f6d484de9d34d314aec945865af5da95f35cf4c7cc271d40bc99f8d7f12e3022051fcb2ce4461d1c6e8a778f5e4dcb27c8461d18e0652f68a7a09a98e95df5cb74141044e2c1e2c055e7aefc291679882382c35894a6aa6dd95644f598e506c239f9d83b1d9671c1d9673e3c2b74f07e8032343f3adc21367bd4cffae92fe31efcd598affffffff020000000000000000456a2231394878696756345179427633744870515663554551797131707a5a56646f41757404617364660d746578742f6d61726b646f776e055554462d3807616e6f7468657240390000000000001976a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac00000000'); 85 | }); 86 | 87 | it('should succeed batch', async () => { 88 | var result = await index.instance(options).getTxBatch(['96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6', '6abdf1368e1d05bcad224c1f7063d8a8deb393dc7172e5de660e3c0265c58ee7']); 89 | delete result[0].confirmations; 90 | delete result[1].confirmations; 91 | expect(result).to.eql( 92 | [ 93 | { 94 | "txid":"96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6", 95 | "hash":"96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6", 96 | "size":301, 97 | "version":1, 98 | "locktime":0, 99 | "vin":[ 100 | { 101 | "value":0.00015058, 102 | "valueSat":15058, 103 | "txid":"d834682a5d29646427e5627d38c10224036535fa7e3066ae2f7a163a96550e27", 104 | "vout":1, 105 | "scriptSig":{ 106 | "asm":"30440220132f6d484de9d34d314aec945865af5da95f35cf4c7cc271d40bc99f8d7f12e3022051fcb2ce4461d1c6e8a778f5e4dcb27c8461d18e0652f68a7a09a98e95df5cb7[ALL|FORKID] 044e2c1e2c055e7aefc291679882382c35894a6aa6dd95644f598e506c239f9d83b1d9671c1d9673e3c2b74f07e8032343f3adc21367bd4cffae92fe31efcd598a", 107 | "hex":"4730440220132f6d484de9d34d314aec945865af5da95f35cf4c7cc271d40bc99f8d7f12e3022051fcb2ce4461d1c6e8a778f5e4dcb27c8461d18e0652f68a7a09a98e95df5cb74141044e2c1e2c055e7aefc291679882382c35894a6aa6dd95644f598e506c239f9d83b1d9671c1d9673e3c2b74f07e8032343f3adc21367bd4cffae92fe31efcd598a" 108 | }, 109 | "addr":"12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX", 110 | "address":"12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX", 111 | "sequence":4294967295 112 | } 113 | ], 114 | "vout":[ 115 | { 116 | "value":0, 117 | "valueSat":0, 118 | "n": 0, 119 | "scriptPubKey":{ 120 | "asm":"OP_RETURN 31394878696756345179427633744870515663554551797131707a5a56646f417574 1717859169 746578742f6d61726b646f776e 5554462d38 616e6f74686572", 121 | "hex":"6a2231394878696756345179427633744870515663554551797131707a5a56646f41757404617364660d746578742f6d61726b646f776e055554462d3807616e6f74686572", 122 | "type":"nulldata" 123 | }, 124 | }, 125 | { 126 | "value":0.00014656, 127 | "valueSat":14656, 128 | "n": 1, 129 | "scriptPubKey":{ 130 | "asm":"OP_DUP OP_HASH160 10bdcba3041b5e5517a58f2e405293c14a7c70c1 OP_EQUALVERIFY OP_CHECKSIG", 131 | "hex":"76a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac", 132 | "reqSigs":1, 133 | "type":"pubkeyhash", 134 | "addresses":[ 135 | "12XXBHkRNrBEb7GCvAP4G8oUs5SoDREkVX" 136 | ] 137 | }, 138 | } 139 | ], 140 | "blockhash":"0000000000000000078f34d9cd3f48e4948aef4c79548ec777050e1c8953a85c", 141 | "blockheight": 576025, 142 | "time":1554007897, 143 | "blocktime":1554007897, 144 | "valueIn":0.00015058, 145 | "fees":0.00000402, 146 | "valueOut":0.00014656, 147 | "rawtx":"0100000001270e55963a167a2fae66307efa3565032402c1387d62e5276464295d2a6834d8010000008a4730440220132f6d484de9d34d314aec945865af5da95f35cf4c7cc271d40bc99f8d7f12e3022051fcb2ce4461d1c6e8a778f5e4dcb27c8461d18e0652f68a7a09a98e95df5cb74141044e2c1e2c055e7aefc291679882382c35894a6aa6dd95644f598e506c239f9d83b1d9671c1d9673e3c2b74f07e8032343f3adc21367bd4cffae92fe31efcd598affffffff020000000000000000456a2231394878696756345179427633744870515663554551797131707a5a56646f41757404617364660d746578742f6d61726b646f776e055554462d3807616e6f7468657240390000000000001976a91410bdcba3041b5e5517a58f2e405293c14a7c70c188ac00000000" 148 | }, 149 | { 150 | "txid": "6abdf1368e1d05bcad224c1f7063d8a8deb393dc7172e5de660e3c0265c58ee7", 151 | "hash": "6abdf1368e1d05bcad224c1f7063d8a8deb393dc7172e5de660e3c0265c58ee7", 152 | "size": 225, 153 | "version": 1, 154 | "locktime": 0, 155 | "vin": [ 156 | { 157 | "value": 23.64025478, 158 | "valueSat": 2364025478, 159 | "txid": "c28f0ad5dd16673b73501d4a118e4595c786f8603ba3d8dd35c56f9ac3a080cc", 160 | "vout": 1, 161 | "scriptSig": { 162 | "asm": "30440220441302ba6510db36a1765970eede1e79f3bec1bf86f5e1293fc0f28252287e9d02207597f187b9c5c15bd53577288d7779f7586d711a4eb709dafdb266976870b26b[ALL|FORKID] 038574d72d96d9d352ad2da7b115d9d4cfa7d7aa3cae8e0c29b399d03192baf7c3", 163 | "hex": "4730440220441302ba6510db36a1765970eede1e79f3bec1bf86f5e1293fc0f28252287e9d02207597f187b9c5c15bd53577288d7779f7586d711a4eb709dafdb266976870b26b4121038574d72d96d9d352ad2da7b115d9d4cfa7d7aa3cae8e0c29b399d03192baf7c3" 164 | }, 165 | "addr": "1BgUBaR2rjgp3db7dqBhverPoSKVipUmCN", 166 | "address": "1BgUBaR2rjgp3db7dqBhverPoSKVipUmCN", 167 | "sequence": 4294967295 168 | } 169 | ], 170 | "vout": [ 171 | { 172 | "value": 0.0196, 173 | "valueSat": 1960000, 174 | "n": 0, 175 | "scriptPubKey": { 176 | "asm": "OP_DUP OP_HASH160 3e257bcc6ff228fbdee52894f45bf32433a298b0 OP_EQUALVERIFY OP_CHECKSIG", 177 | "hex": "76a9143e257bcc6ff228fbdee52894f45bf32433a298b088ac", 178 | "reqSigs": 1, 179 | "type": "pubkeyhash", 180 | "addresses": [ 181 | "16fboJLLugG82GgQFNa2NMNKVaFjB6TKzG" 182 | ] 183 | }, 184 | }, 185 | { 186 | "value": 23.62065251, 187 | "valueSat": 2362065251, 188 | "n": 1, 189 | "scriptPubKey": { 190 | "asm": "OP_DUP OP_HASH160 36a2a8d1aeee3e4f14857f725d41b0930d15ec3e OP_EQUALVERIFY OP_CHECKSIG", 191 | "hex": "76a91436a2a8d1aeee3e4f14857f725d41b0930d15ec3e88ac", 192 | "reqSigs": 1, 193 | "type": "pubkeyhash", 194 | "addresses": [ 195 | "15ytM8rvCgiNRAJKZfERZGHdXy8JZqJjUB" 196 | ] 197 | }, 198 | } 199 | ], 200 | "blockhash": "0000000000000000062e0ca7d73338e68284eb58175db871b125acf046501b0a", 201 | "blockheight": 611037, 202 | "time": 1575106827, 203 | "blocktime": 1575106827, 204 | "valueIn": 23.64025478, 205 | "fees": 0.00000227, 206 | "valueOut": 23.64025251, 207 | "rawtx": "0100000001cc80a0c39a6fc535ddd8a33b60f886c795458e114a1d50733b6716ddd50a8fc2010000006a4730440220441302ba6510db36a1765970eede1e79f3bec1bf86f5e1293fc0f28252287e9d02207597f187b9c5c15bd53577288d7779f7586d711a4eb709dafdb266976870b26b4121038574d72d96d9d352ad2da7b115d9d4cfa7d7aa3cae8e0c29b399d03192baf7c3ffffffff0240e81d00000000001976a9143e257bcc6ff228fbdee52894f45bf32433a298b088ac6341ca8c000000001976a91436a2a8d1aeee3e4f14857f725d41b0930d15ec3e88ac00000000" 208 | } 209 | ] 210 | ); 211 | }); 212 | 213 | it('should fail too large batch', async () => { 214 | try { 215 | await index.instance(options).getTxBatch([ 216 | '96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6', 217 | '6abdf1368e1d05bcad224c1f7063d8a8deb393dc7172e5de660e3c0265c58ee7', 218 | '96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6', 219 | '6abdf1368e1d05bcad224c1f7063d8a8deb393dc7172e5de660e3c0265c58ee7', 220 | '96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6', 221 | '6abdf1368e1d05bcad224c1f7063d8a8deb393dc7172e5de660e3c0265c58ee7', 222 | '96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6', 223 | '6abdf1368e1d05bcad224c1f7063d8a8deb393dc7172e5de660e3c0265c58ee7', 224 | '96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6', 225 | '6abdf1368e1d05bcad224c1f7063d8a8deb393dc7172e5de660e3c0265c58ee7', 226 | '96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6', 227 | '6abdf1368e1d05bcad224c1f7063d8a8deb393dc7172e5de660e3c0265c58ee7', 228 | '96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6', 229 | '6abdf1368e1d05bcad224c1f7063d8a8deb393dc7172e5de660e3c0265c58ee7', 230 | '96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6', 231 | '6abdf1368e1d05bcad224c1f7063d8a8deb393dc7172e5de660e3c0265c58ee7', 232 | '96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6', 233 | '6abdf1368e1d05bcad224c1f7063d8a8deb393dc7172e5de660e3c0265c58ee7', 234 | '96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6', 235 | '6abdf1368e1d05bcad224c1f7063d8a8deb393dc7172e5de660e3c0265c58ee7', 236 | '96b3dc5941ce97046d4af6e7a69f4b38c48f05ef071c2a33f88807b89ab51da6', 237 | ]); 238 | } catch (ex) { 239 | expect(ex).to.eql({ success: false, code: 422, error: 'too many requested' , message: 'too many requested' }); 240 | } 241 | }); 242 | }); 243 | 244 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2015", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "outDir": "./dist", 7 | "strict": true, 8 | "noImplicitAny": false 9 | } 10 | } 11 | 12 | --------------------------------------------------------------------------------