psf-bch-api 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/.env-local +9 -0
  2. package/README.md +22 -0
  3. package/bin/server.js +24 -1
  4. package/package.json +6 -2
  5. package/src/adapters/fulcrum-api.js +124 -0
  6. package/src/adapters/full-node-rpc.js +2 -6
  7. package/src/adapters/index.js +4 -0
  8. package/src/adapters/slp-indexer-api.js +124 -0
  9. package/src/config/env/common.js +45 -24
  10. package/src/config/x402.js +43 -0
  11. package/src/controllers/index.js +3 -1
  12. package/src/controllers/rest-api/fulcrum/controller.js +563 -0
  13. package/src/controllers/rest-api/fulcrum/router.js +64 -0
  14. package/src/controllers/rest-api/full-node/blockchain/controller.js +26 -26
  15. package/src/controllers/rest-api/full-node/blockchain/{index.js → router.js} +5 -1
  16. package/src/controllers/rest-api/full-node/control/controller.js +68 -0
  17. package/src/controllers/rest-api/full-node/control/router.js +51 -0
  18. package/src/controllers/rest-api/full-node/dsproof/controller.js +90 -0
  19. package/src/controllers/rest-api/full-node/dsproof/router.js +51 -0
  20. package/src/controllers/rest-api/full-node/mining/controller.js +99 -0
  21. package/src/controllers/rest-api/full-node/mining/router.js +52 -0
  22. package/src/controllers/rest-api/full-node/rawtransactions/controller.js +333 -0
  23. package/src/controllers/rest-api/full-node/rawtransactions/router.js +58 -0
  24. package/src/controllers/rest-api/index.js +33 -2
  25. package/src/controllers/rest-api/slp/controller.js +218 -0
  26. package/src/controllers/rest-api/slp/router.js +55 -0
  27. package/src/controllers/timer-controller.js +1 -1
  28. package/src/use-cases/fulcrum-use-cases.js +155 -0
  29. package/src/use-cases/full-node-control-use-cases.js +24 -0
  30. package/src/use-cases/full-node-dsproof-use-cases.js +24 -0
  31. package/src/use-cases/full-node-mining-use-cases.js +28 -0
  32. package/src/use-cases/full-node-rawtransactions-use-cases.js +121 -0
  33. package/src/use-cases/index.js +12 -0
  34. package/src/use-cases/slp-use-cases.js +321 -0
  35. package/test/unit/controllers/blockchain-controller-unit.js +2 -3
  36. package/test/unit/controllers/control-controller-unit.js +88 -0
  37. package/test/unit/controllers/dsproof-controller-unit.js +117 -0
  38. package/test/unit/controllers/fulcrum-controller-unit.js +481 -0
  39. package/test/unit/controllers/mining-controller-unit.js +139 -0
  40. package/test/unit/controllers/rawtransactions-controller-unit.js +388 -0
  41. package/test/unit/controllers/rest-api-index-unit.js +76 -6
  42. package/test/unit/controllers/slp-controller-unit.js +312 -0
  43. package/test/unit/use-cases/fulcrum-use-cases-unit.js +297 -0
  44. package/test/unit/use-cases/full-node-control-use-cases-unit.js +53 -0
  45. package/test/unit/use-cases/full-node-dsproof-use-cases-unit.js +54 -0
  46. package/test/unit/use-cases/full-node-mining-use-cases-unit.js +84 -0
  47. package/test/unit/use-cases/full-node-rawtransactions-use-cases-unit.js +267 -0
  48. package/test/unit/use-cases/slp-use-cases-unit.js +296 -0
  49. package/src/entities/event.js +0 -71
  50. package/test/integration/api/event-integration.js +0 -250
  51. package/test/integration/api/req-integration.js +0 -173
  52. package/test/integration/api/subscription-integration.js +0 -198
  53. package/test/integration/use-cases/manage-subscription-integration.js +0 -163
  54. package/test/integration/use-cases/publish-event-integration.js +0 -104
  55. package/test/integration/use-cases/query-events-integration.js +0 -95
  56. package/test/unit/entities/event-unit.js +0 -139
@@ -0,0 +1,563 @@
1
+ /*
2
+ REST API Controller for the /fulcrum routes.
3
+ */
4
+
5
+ import wlogger from '../../../adapters/wlogger.js'
6
+ import BCHJS from '@psf/bch-js'
7
+
8
+ const bchjs = new BCHJS()
9
+
10
+ class FulcrumRESTController {
11
+ constructor (localConfig = {}) {
12
+ this.adapters = localConfig.adapters
13
+ if (!this.adapters) {
14
+ throw new Error(
15
+ 'Instance of Adapters library required when instantiating Fulcrum REST Controller.'
16
+ )
17
+ }
18
+
19
+ this.useCases = localConfig.useCases
20
+ if (!this.useCases || !this.useCases.fulcrum) {
21
+ throw new Error(
22
+ 'Instance of Fulcrum use cases required when instantiating Fulcrum REST Controller.'
23
+ )
24
+ }
25
+
26
+ this.fulcrumUseCases = this.useCases.fulcrum
27
+
28
+ // Bind functions
29
+ this.root = this.root.bind(this)
30
+ this.getBalance = this.getBalance.bind(this)
31
+ this.balanceBulk = this.balanceBulk.bind(this)
32
+ this.getUtxos = this.getUtxos.bind(this)
33
+ this.utxosBulk = this.utxosBulk.bind(this)
34
+ this.getTransactionDetails = this.getTransactionDetails.bind(this)
35
+ this.transactionDetailsBulk = this.transactionDetailsBulk.bind(this)
36
+ this.broadcastTransaction = this.broadcastTransaction.bind(this)
37
+ this.getBlockHeaders = this.getBlockHeaders.bind(this)
38
+ this.blockHeadersBulk = this.blockHeadersBulk.bind(this)
39
+ this.getTransactions = this.getTransactions.bind(this)
40
+ this.transactionsBulk = this.transactionsBulk.bind(this)
41
+ this.getMempool = this.getMempool.bind(this)
42
+ this.mempoolBulk = this.mempoolBulk.bind(this)
43
+ this.handleError = this.handleError.bind(this)
44
+ }
45
+
46
+ /**
47
+ * @api {get} /v6/fulcrum/ Service status
48
+ * @apiName FulcrumRoot
49
+ * @apiGroup Fulcrum
50
+ *
51
+ * @apiDescription Returns the status of the fulcrum service.
52
+ *
53
+ * @apiSuccess {String} status Service identifier
54
+ */
55
+ async root (req, res) {
56
+ return res.status(200).json({ status: 'fulcrum' })
57
+ }
58
+
59
+ /**
60
+ * Validates and converts an address to cash address format
61
+ * @param {string} address - Address to validate and convert
62
+ * @returns {string} Cash address
63
+ * @throws {Error} If address is invalid or not mainnet
64
+ */
65
+ _validateAndConvertAddress (address) {
66
+ if (!address) {
67
+ throw new Error('address is empty')
68
+ }
69
+
70
+ // Convert legacy to cash address
71
+ const cashAddr = bchjs.Address.toCashAddress(address)
72
+
73
+ // Ensure it's a valid BCH address
74
+ try {
75
+ bchjs.Address.toLegacyAddress(cashAddr)
76
+ } catch (err) {
77
+ throw new Error(`Invalid BCH address. Double check your address is valid: ${address}`)
78
+ }
79
+
80
+ // Ensure it's mainnet (no testnet support)
81
+ const isMainnet = bchjs.Address.isMainnetAddress(cashAddr)
82
+ if (!isMainnet) {
83
+ throw new Error('Invalid network. Only mainnet addresses are supported.')
84
+ }
85
+
86
+ return cashAddr
87
+ }
88
+
89
+ /**
90
+ * @api {get} /v6/fulcrum/balance/:address Get balance for a single address
91
+ * @apiName GetBalance
92
+ * @apiGroup Fulcrum
93
+ * @apiDescription Returns an object with confirmed and unconfirmed balance associated with an address.
94
+ */
95
+ async getBalance (req, res) {
96
+ try {
97
+ const address = req.params.address
98
+
99
+ if (Array.isArray(address)) {
100
+ return res.status(400).json({
101
+ success: false,
102
+ error: 'address can not be an array. Use POST for bulk upload.'
103
+ })
104
+ }
105
+
106
+ const cashAddr = this._validateAndConvertAddress(address)
107
+
108
+ const result = await this.fulcrumUseCases.getBalance({ address: cashAddr })
109
+ return res.status(200).json(result)
110
+ } catch (err) {
111
+ return this.handleError(err, res)
112
+ }
113
+ }
114
+
115
+ /**
116
+ * @api {post} /v6/fulcrum/balance Get balances for an array of addresses
117
+ * @apiName GetBalances
118
+ * @apiGroup Fulcrum
119
+ * @apiDescription Returns an array of balances associated with an array of addresses. Limited to 20 items per request.
120
+ */
121
+ async balanceBulk (req, res) {
122
+ try {
123
+ const addresses = req.body.addresses
124
+
125
+ if (!Array.isArray(addresses)) {
126
+ return res.status(400).json({
127
+ success: false,
128
+ error: 'addresses needs to be an array. Use GET for single address.'
129
+ })
130
+ }
131
+
132
+ if (!this.adapters.fullNode.validateArraySize(addresses.length)) {
133
+ return res.status(400).json({
134
+ success: false,
135
+ error: 'Array too large.'
136
+ })
137
+ }
138
+
139
+ // Validate and convert all addresses
140
+ const validatedAddresses = []
141
+ for (let i = 0; i < addresses.length; i++) {
142
+ try {
143
+ const cashAddr = this._validateAndConvertAddress(addresses[i])
144
+ validatedAddresses.push(cashAddr)
145
+ } catch (err) {
146
+ return res.status(400).json({
147
+ success: false,
148
+ error: err.message
149
+ })
150
+ }
151
+ }
152
+
153
+ const result = await this.fulcrumUseCases.getBalances({ addresses: validatedAddresses })
154
+ return res.status(200).json(result)
155
+ } catch (err) {
156
+ return this.handleError(err, res)
157
+ }
158
+ }
159
+
160
+ /**
161
+ * @api {get} /v6/fulcrum/utxos/:address Get utxos for a single address
162
+ * @apiName GetUtxos
163
+ * @apiGroup Fulcrum
164
+ * @apiDescription Returns an object with UTXOs associated with an address.
165
+ */
166
+ async getUtxos (req, res) {
167
+ try {
168
+ const address = req.params.address
169
+
170
+ if (Array.isArray(address)) {
171
+ return res.status(400).json({
172
+ success: false,
173
+ error: 'address can not be an array. Use POST for bulk upload.'
174
+ })
175
+ }
176
+
177
+ const cashAddr = this._validateAndConvertAddress(address)
178
+
179
+ const result = await this.fulcrumUseCases.getUtxos({ address: cashAddr })
180
+ return res.status(200).json(result)
181
+ } catch (err) {
182
+ return this.handleError(err, res)
183
+ }
184
+ }
185
+
186
+ /**
187
+ * @api {post} /v6/fulcrum/utxos Get utxos for an array of addresses
188
+ * @apiName GetUtxosBulk
189
+ * @apiGroup Fulcrum
190
+ * @apiDescription Returns an array of objects with UTXOs associated with an address. Limited to 20 items per request.
191
+ */
192
+ async utxosBulk (req, res) {
193
+ try {
194
+ const addresses = req.body.addresses
195
+
196
+ if (!Array.isArray(addresses)) {
197
+ return res.status(400).json({
198
+ success: false,
199
+ error: 'addresses needs to be an array. Use GET for single address.'
200
+ })
201
+ }
202
+
203
+ if (!this.adapters.fullNode.validateArraySize(addresses.length)) {
204
+ return res.status(400).json({
205
+ success: false,
206
+ error: 'Array too large.'
207
+ })
208
+ }
209
+
210
+ // Validate and convert all addresses
211
+ const validatedAddresses = []
212
+ for (let i = 0; i < addresses.length; i++) {
213
+ try {
214
+ const cashAddr = this._validateAndConvertAddress(addresses[i])
215
+ validatedAddresses.push(cashAddr)
216
+ } catch (err) {
217
+ return res.status(400).json({
218
+ success: false,
219
+ error: err.message
220
+ })
221
+ }
222
+ }
223
+
224
+ const result = await this.fulcrumUseCases.getUtxosBulk({ addresses: validatedAddresses })
225
+ return res.status(200).json(result)
226
+ } catch (err) {
227
+ return this.handleError(err, res)
228
+ }
229
+ }
230
+
231
+ /**
232
+ * @api {get} /v6/fulcrum/tx/data/:txid Get transaction details for a TXID
233
+ * @apiName GetTransactionDetails
234
+ * @apiGroup Fulcrum
235
+ * @apiDescription Returns an object with transaction details of the TXID
236
+ */
237
+ async getTransactionDetails (req, res) {
238
+ try {
239
+ const txid = req.params.txid
240
+
241
+ if (typeof txid !== 'string') {
242
+ return res.status(400).json({
243
+ success: false,
244
+ error: 'txid must be a string'
245
+ })
246
+ }
247
+
248
+ const result = await this.fulcrumUseCases.getTransactionDetails({ txid })
249
+ return res.status(200).json(result)
250
+ } catch (err) {
251
+ return this.handleError(err, res)
252
+ }
253
+ }
254
+
255
+ /**
256
+ * @api {post} /v6/fulcrum/tx/data Get transaction details for an array of TXIDs
257
+ * @apiName GetTransactionDetailsBulk
258
+ * @apiGroup Fulcrum
259
+ * @apiDescription Returns an array of objects with transaction details of an array of TXIDs. Limited to 20 items per request.
260
+ */
261
+ async transactionDetailsBulk (req, res) {
262
+ try {
263
+ const txids = req.body.txids
264
+ const verbose = req.body.verbose !== undefined ? req.body.verbose : true
265
+
266
+ if (!Array.isArray(txids)) {
267
+ return res.status(400).json({
268
+ success: false,
269
+ error: 'txids needs to be an array. Use GET for single txid.'
270
+ })
271
+ }
272
+
273
+ if (!this.adapters.fullNode.validateArraySize(txids.length)) {
274
+ return res.status(400).json({
275
+ success: false,
276
+ error: 'Array too large.'
277
+ })
278
+ }
279
+
280
+ const result = await this.fulcrumUseCases.getTransactionDetailsBulk({ txids, verbose })
281
+ return res.status(200).json(result)
282
+ } catch (err) {
283
+ return this.handleError(err, res)
284
+ }
285
+ }
286
+
287
+ /**
288
+ * @api {post} /v6/fulcrum/tx/broadcast Broadcast a raw transaction
289
+ * @apiName BroadcastTransaction
290
+ * @apiGroup Fulcrum
291
+ * @apiDescription Broadcast a raw transaction and return the transaction ID on success or error on failure.
292
+ */
293
+ async broadcastTransaction (req, res) {
294
+ try {
295
+ const txHex = req.body.txHex
296
+
297
+ if (typeof txHex !== 'string') {
298
+ return res.status(400).json({
299
+ success: false,
300
+ error: 'txHex must be a string'
301
+ })
302
+ }
303
+
304
+ const result = await this.fulcrumUseCases.broadcastTransaction({ txHex })
305
+ return res.status(200).json(result)
306
+ } catch (err) {
307
+ return this.handleError(err, res)
308
+ }
309
+ }
310
+
311
+ /**
312
+ * @api {get} /v6/fulcrum/block/headers/:height Get block headers
313
+ * @apiName GetBlockHeaders
314
+ * @apiGroup Fulcrum
315
+ * @apiDescription Returns an array with block headers starting at the block height
316
+ *
317
+ * @apiParam {Number} height Block height
318
+ * @apiParam {Number} count Number of block headers to return (query parameter, default: 1)
319
+ */
320
+ async getBlockHeaders (req, res) {
321
+ try {
322
+ const heightRaw = req.params.height
323
+ const countRaw = req.query.count
324
+
325
+ const height = Number(heightRaw)
326
+ const count = countRaw === undefined ? 1 : Number(countRaw)
327
+
328
+ if (Number.isNaN(height) || height < 0) {
329
+ return res.status(400).json({
330
+ success: false,
331
+ error: 'height must be a positive number'
332
+ })
333
+ }
334
+
335
+ if (Number.isNaN(count) || count < 0) {
336
+ return res.status(400).json({
337
+ success: false,
338
+ error: 'count must be a positive number'
339
+ })
340
+ }
341
+
342
+ const result = await this.fulcrumUseCases.getBlockHeaders({ height, count })
343
+ return res.status(200).json(result)
344
+ } catch (err) {
345
+ return this.handleError(err, res)
346
+ }
347
+ }
348
+
349
+ /**
350
+ * @api {post} /v6/fulcrum/block/headers Get block headers for an array of height + count pairs
351
+ * @apiName GetBlockHeadersBulk
352
+ * @apiGroup Fulcrum
353
+ * @apiDescription Returns an array of objects with block headers. Limited to 20 items per request.
354
+ */
355
+ async blockHeadersBulk (req, res) {
356
+ try {
357
+ const heights = req.body.heights
358
+
359
+ if (!Array.isArray(heights)) {
360
+ return res.status(400).json({
361
+ success: false,
362
+ error: 'heights needs to be an array. Use GET for single height.'
363
+ })
364
+ }
365
+
366
+ if (!this.adapters.fullNode.validateArraySize(heights.length)) {
367
+ return res.status(400).json({
368
+ success: false,
369
+ error: 'Array too large.'
370
+ })
371
+ }
372
+
373
+ // Validate each height object
374
+ for (const item of heights) {
375
+ if (!item || typeof item.height !== 'number' || typeof item.count !== 'number') {
376
+ return res.status(400).json({
377
+ success: false,
378
+ error: 'Each height object must have numeric height and count properties'
379
+ })
380
+ }
381
+ if (item.height < 0 || item.count < 0) {
382
+ return res.status(400).json({
383
+ success: false,
384
+ error: 'height and count must be positive numbers'
385
+ })
386
+ }
387
+ }
388
+
389
+ const result = await this.fulcrumUseCases.getBlockHeadersBulk({ heights })
390
+ return res.status(200).json(result)
391
+ } catch (err) {
392
+ return this.handleError(err, res)
393
+ }
394
+ }
395
+
396
+ /**
397
+ * @api {get} /v6/fulcrum/transactions/:address Get transaction history for a single address
398
+ * @apiName GetTransactions
399
+ * @apiGroup Fulcrum
400
+ * @apiDescription Returns an array of historical transactions associated with an address. Results are returned in descending order (most recent TX first). Passing allTxs=true will return the entire transaction history, otherwise, only the last 100 TXIDs will be returned.
401
+ *
402
+ * @apiParam {String} address Address
403
+ * @apiParam {Boolean} allTxs Optional: return all transactions (default: false, limited to 100)
404
+ */
405
+ async getTransactions (req, res) {
406
+ try {
407
+ const address = req.params.address
408
+ let allTxs = false
409
+
410
+ // Check if allTxs is in params or query
411
+ if (req.params.allTxs) {
412
+ allTxs = req.params.allTxs === 'true'
413
+ } else if (req.query.allTxs) {
414
+ allTxs = req.query.allTxs === 'true'
415
+ }
416
+
417
+ if (Array.isArray(address)) {
418
+ return res.status(400).json({
419
+ success: false,
420
+ error: 'address can not be an array. Use POST for bulk upload.'
421
+ })
422
+ }
423
+
424
+ const cashAddr = this._validateAndConvertAddress(address)
425
+
426
+ const result = await this.fulcrumUseCases.getTransactions({ address: cashAddr, allTxs })
427
+ return res.status(200).json(result)
428
+ } catch (err) {
429
+ return this.handleError(err, res)
430
+ }
431
+ }
432
+
433
+ /**
434
+ * @api {post} /v6/fulcrum/transactions Get the transaction history for an array of addresses
435
+ * @apiName GetTransactionsBulk
436
+ * @apiGroup Fulcrum
437
+ * @apiDescription Returns an array of transactions associated with an array of addresses. Limited to 20 items per request. Passing allTxs=true will return the entire transaction history, otherwise, only the last 100 TXIDs will be returned.
438
+ */
439
+ async transactionsBulk (req, res) {
440
+ try {
441
+ const addresses = req.body.addresses
442
+ const allTxs = req.body.allTxs === true
443
+
444
+ if (!Array.isArray(addresses)) {
445
+ return res.status(400).json({
446
+ success: false,
447
+ error: 'addresses needs to be an array. Use GET for single address.'
448
+ })
449
+ }
450
+
451
+ if (!this.adapters.fullNode.validateArraySize(addresses.length)) {
452
+ return res.status(400).json({
453
+ success: false,
454
+ error: 'Array too large.'
455
+ })
456
+ }
457
+
458
+ // Validate and convert all addresses
459
+ const validatedAddresses = []
460
+ for (let i = 0; i < addresses.length; i++) {
461
+ try {
462
+ const cashAddr = this._validateAndConvertAddress(addresses[i])
463
+ validatedAddresses.push(cashAddr)
464
+ } catch (err) {
465
+ return res.status(400).json({
466
+ success: false,
467
+ error: err.message
468
+ })
469
+ }
470
+ }
471
+
472
+ const result = await this.fulcrumUseCases.getTransactionsBulk({
473
+ addresses: validatedAddresses,
474
+ allTxs
475
+ })
476
+ return res.status(200).json(result)
477
+ } catch (err) {
478
+ return this.handleError(err, res)
479
+ }
480
+ }
481
+
482
+ /**
483
+ * @api {get} /v6/fulcrum/unconfirmed/:address Get unconfirmed utxos for a single address
484
+ * @apiName GetMempool
485
+ * @apiGroup Fulcrum
486
+ * @apiDescription Returns an object with unconfirmed UTXOs associated with an address.
487
+ */
488
+ async getMempool (req, res) {
489
+ try {
490
+ const address = req.params.address
491
+
492
+ if (Array.isArray(address)) {
493
+ return res.status(400).json({
494
+ success: false,
495
+ error: 'address can not be an array. Use POST for bulk upload.'
496
+ })
497
+ }
498
+
499
+ const cashAddr = this._validateAndConvertAddress(address)
500
+
501
+ const result = await this.fulcrumUseCases.getMempool({ address: cashAddr })
502
+ return res.status(200).json(result)
503
+ } catch (err) {
504
+ return this.handleError(err, res)
505
+ }
506
+ }
507
+
508
+ /**
509
+ * @api {post} /v6/fulcrum/unconfirmed Get unconfirmed utxos for an array of addresses
510
+ * @apiName GetMempoolBulk
511
+ * @apiGroup Fulcrum
512
+ * @apiDescription Returns an array of objects with unconfirmed UTXOs associated with an address. Limited to 20 items per request.
513
+ */
514
+ async mempoolBulk (req, res) {
515
+ try {
516
+ const addresses = req.body.addresses
517
+
518
+ if (!Array.isArray(addresses)) {
519
+ return res.status(400).json({
520
+ success: false,
521
+ error: 'addresses needs to be an array. Use GET for single address.'
522
+ })
523
+ }
524
+
525
+ if (!this.adapters.fullNode.validateArraySize(addresses.length)) {
526
+ return res.status(400).json({
527
+ success: false,
528
+ error: 'Array too large.'
529
+ })
530
+ }
531
+
532
+ // Validate and convert all addresses
533
+ const validatedAddresses = []
534
+ for (let i = 0; i < addresses.length; i++) {
535
+ try {
536
+ const cashAddr = this._validateAndConvertAddress(addresses[i])
537
+ validatedAddresses.push(cashAddr)
538
+ } catch (err) {
539
+ return res.status(400).json({
540
+ success: false,
541
+ error: err.message
542
+ })
543
+ }
544
+ }
545
+
546
+ const result = await this.fulcrumUseCases.getMempoolBulk({ addresses: validatedAddresses })
547
+ return res.status(200).json(result)
548
+ } catch (err) {
549
+ return this.handleError(err, res)
550
+ }
551
+ }
552
+
553
+ handleError (err, res) {
554
+ wlogger.error('Error in FulcrumRESTController:', err)
555
+
556
+ const status = err.status || 500
557
+ const message = err.message || 'Internal server error'
558
+
559
+ return res.status(status).json({ error: message })
560
+ }
561
+ }
562
+
563
+ export default FulcrumRESTController
@@ -0,0 +1,64 @@
1
+ /*
2
+ REST API router for /full-node/fulcrum routes.
3
+ */
4
+
5
+ import express from 'express'
6
+ import FulcrumRESTController from './controller.js'
7
+
8
+ class FulcrumRouter {
9
+ constructor (localConfig = {}) {
10
+ this.adapters = localConfig.adapters
11
+ if (!this.adapters) {
12
+ throw new Error(
13
+ 'Instance of Adapters library required when instantiating Fulcrum REST Router.'
14
+ )
15
+ }
16
+
17
+ this.useCases = localConfig.useCases
18
+ if (!this.useCases) {
19
+ throw new Error(
20
+ 'Instance of Use Cases library required when instantiating Fulcrum REST Router.'
21
+ )
22
+ }
23
+
24
+ const dependencies = {
25
+ adapters: this.adapters,
26
+ useCases: this.useCases
27
+ }
28
+
29
+ this.fulcrumController = new FulcrumRESTController(dependencies)
30
+
31
+ this.apiPrefix = (localConfig.apiPrefix || '').replace(/\/$/, '')
32
+ this.baseUrl = `${this.apiPrefix}/fulcrum`
33
+ if (!this.baseUrl.startsWith('/')) {
34
+ this.baseUrl = `/${this.baseUrl}`
35
+ }
36
+ this.router = express.Router()
37
+ }
38
+
39
+ attach (app) {
40
+ if (!app) {
41
+ throw new Error('Must pass app object when attaching REST API controllers.')
42
+ }
43
+
44
+ this.router.get('/', this.fulcrumController.root)
45
+ this.router.get('/balance/:address', this.fulcrumController.getBalance)
46
+ this.router.post('/balance', this.fulcrumController.balanceBulk)
47
+ this.router.get('/utxos/:address', this.fulcrumController.getUtxos)
48
+ this.router.post('/utxos', this.fulcrumController.utxosBulk)
49
+ this.router.get('/tx/data/:txid', this.fulcrumController.getTransactionDetails)
50
+ this.router.post('/tx/data', this.fulcrumController.transactionDetailsBulk)
51
+ this.router.post('/tx/broadcast', this.fulcrumController.broadcastTransaction)
52
+ this.router.get('/block/headers/:height', this.fulcrumController.getBlockHeaders)
53
+ this.router.post('/block/headers', this.fulcrumController.blockHeadersBulk)
54
+ this.router.get('/transactions/:address', this.fulcrumController.getTransactions)
55
+ this.router.get('/transactions/:address/:allTxs', this.fulcrumController.getTransactions)
56
+ this.router.post('/transactions', this.fulcrumController.transactionsBulk)
57
+ this.router.get('/unconfirmed/:address', this.fulcrumController.getMempool)
58
+ this.router.post('/unconfirmed', this.fulcrumController.mempoolBulk)
59
+
60
+ app.use(this.baseUrl, this.router)
61
+ }
62
+ }
63
+
64
+ export default FulcrumRouter