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.
- package/.env-local +9 -0
- package/README.md +22 -0
- package/bin/server.js +24 -1
- package/package.json +6 -2
- package/src/adapters/fulcrum-api.js +124 -0
- package/src/adapters/full-node-rpc.js +2 -6
- package/src/adapters/index.js +4 -0
- package/src/adapters/slp-indexer-api.js +124 -0
- package/src/config/env/common.js +45 -24
- package/src/config/x402.js +43 -0
- package/src/controllers/index.js +3 -1
- package/src/controllers/rest-api/fulcrum/controller.js +563 -0
- package/src/controllers/rest-api/fulcrum/router.js +64 -0
- package/src/controllers/rest-api/full-node/blockchain/controller.js +26 -26
- package/src/controllers/rest-api/full-node/blockchain/{index.js → router.js} +5 -1
- package/src/controllers/rest-api/full-node/control/controller.js +68 -0
- package/src/controllers/rest-api/full-node/control/router.js +51 -0
- package/src/controllers/rest-api/full-node/dsproof/controller.js +90 -0
- package/src/controllers/rest-api/full-node/dsproof/router.js +51 -0
- package/src/controllers/rest-api/full-node/mining/controller.js +99 -0
- package/src/controllers/rest-api/full-node/mining/router.js +52 -0
- package/src/controllers/rest-api/full-node/rawtransactions/controller.js +333 -0
- package/src/controllers/rest-api/full-node/rawtransactions/router.js +58 -0
- package/src/controllers/rest-api/index.js +33 -2
- package/src/controllers/rest-api/slp/controller.js +218 -0
- package/src/controllers/rest-api/slp/router.js +55 -0
- package/src/controllers/timer-controller.js +1 -1
- package/src/use-cases/fulcrum-use-cases.js +155 -0
- package/src/use-cases/full-node-control-use-cases.js +24 -0
- package/src/use-cases/full-node-dsproof-use-cases.js +24 -0
- package/src/use-cases/full-node-mining-use-cases.js +28 -0
- package/src/use-cases/full-node-rawtransactions-use-cases.js +121 -0
- package/src/use-cases/index.js +12 -0
- package/src/use-cases/slp-use-cases.js +321 -0
- package/test/unit/controllers/blockchain-controller-unit.js +2 -3
- package/test/unit/controllers/control-controller-unit.js +88 -0
- package/test/unit/controllers/dsproof-controller-unit.js +117 -0
- package/test/unit/controllers/fulcrum-controller-unit.js +481 -0
- package/test/unit/controllers/mining-controller-unit.js +139 -0
- package/test/unit/controllers/rawtransactions-controller-unit.js +388 -0
- package/test/unit/controllers/rest-api-index-unit.js +76 -6
- package/test/unit/controllers/slp-controller-unit.js +312 -0
- package/test/unit/use-cases/fulcrum-use-cases-unit.js +297 -0
- package/test/unit/use-cases/full-node-control-use-cases-unit.js +53 -0
- package/test/unit/use-cases/full-node-dsproof-use-cases-unit.js +54 -0
- package/test/unit/use-cases/full-node-mining-use-cases-unit.js +84 -0
- package/test/unit/use-cases/full-node-rawtransactions-use-cases-unit.js +267 -0
- package/test/unit/use-cases/slp-use-cases-unit.js +296 -0
- package/src/entities/event.js +0 -71
- package/test/integration/api/event-integration.js +0 -250
- package/test/integration/api/req-integration.js +0 -173
- package/test/integration/api/subscription-integration.js +0 -198
- package/test/integration/use-cases/manage-subscription-integration.js +0 -163
- package/test/integration/use-cases/publish-event-integration.js +0 -104
- package/test/integration/use-cases/query-events-integration.js +0 -95
- package/test/unit/entities/event-unit.js +0 -139
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/*
|
|
2
|
+
REST API router for /slp routes.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import express from 'express'
|
|
6
|
+
import SlpRESTController from './controller.js'
|
|
7
|
+
|
|
8
|
+
class SlpRouter {
|
|
9
|
+
constructor (localConfig = {}) {
|
|
10
|
+
this.adapters = localConfig.adapters
|
|
11
|
+
if (!this.adapters) {
|
|
12
|
+
throw new Error(
|
|
13
|
+
'Instance of Adapters library required when instantiating SLP 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 SLP REST Router.'
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const dependencies = {
|
|
25
|
+
adapters: this.adapters,
|
|
26
|
+
useCases: this.useCases
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
this.slpController = new SlpRESTController(dependencies)
|
|
30
|
+
|
|
31
|
+
this.apiPrefix = (localConfig.apiPrefix || '').replace(/\/$/, '')
|
|
32
|
+
this.baseUrl = `${this.apiPrefix}/slp`
|
|
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.slpController.root)
|
|
45
|
+
this.router.get('/status', this.slpController.getStatus)
|
|
46
|
+
this.router.post('/address', this.slpController.getAddress)
|
|
47
|
+
this.router.post('/txid', this.slpController.getTxid)
|
|
48
|
+
this.router.post('/token', this.slpController.getTokenStats)
|
|
49
|
+
this.router.post('/token/data', this.slpController.getTokenData)
|
|
50
|
+
|
|
51
|
+
app.use(this.baseUrl, this.router)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default SlpRouter
|
|
@@ -23,7 +23,7 @@ class TimerController {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
// Constants
|
|
26
|
-
this.SHUTDOWN_INTERVAL_MS = 10 * 60 * 1000 // 10
|
|
26
|
+
this.SHUTDOWN_INTERVAL_MS = 10 * 60 * 60 * 1000 // 10 hours in milliseconds
|
|
27
27
|
this.LIVENESS_CHECK_INTERVAL_MS = 1 * 60 * 1000 // 1 minute in milliseconds
|
|
28
28
|
|
|
29
29
|
// Handlers
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Use cases for interacting with the Fulcrum API service.
|
|
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 FulcrumUseCases {
|
|
11
|
+
constructor (localConfig = {}) {
|
|
12
|
+
this.adapters = localConfig.adapters
|
|
13
|
+
|
|
14
|
+
if (!this.adapters) {
|
|
15
|
+
throw new Error('Adapters instance required when instantiating Fulcrum use cases.')
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
this.fulcrum = this.adapters.fulcrum
|
|
19
|
+
if (!this.fulcrum) {
|
|
20
|
+
throw new Error('Fulcrum adapter required when instantiating Fulcrum use cases.')
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Allow bchjs to be injected for testing
|
|
24
|
+
this.bchjs = localConfig.bchjs || bchjs
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async getBalance ({ address }) {
|
|
28
|
+
return this.fulcrum.get(`electrumx/balance/${address}`)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async getBalances ({ addresses }) {
|
|
32
|
+
try {
|
|
33
|
+
const response = await this.fulcrum.post('electrumx/balance/', { addresses })
|
|
34
|
+
return response
|
|
35
|
+
} catch (err) {
|
|
36
|
+
wlogger.error('Error in FulcrumUseCases.getBalances()', err)
|
|
37
|
+
throw err
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async getUtxos ({ address }) {
|
|
42
|
+
return this.fulcrum.get(`electrumx/utxos/${address}`)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async getUtxosBulk ({ addresses }) {
|
|
46
|
+
try {
|
|
47
|
+
const response = await this.fulcrum.post('electrumx/utxos/', { addresses })
|
|
48
|
+
return response
|
|
49
|
+
} catch (err) {
|
|
50
|
+
wlogger.error('Error in FulcrumUseCases.getUtxosBulk()', err)
|
|
51
|
+
throw err
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async getTransactionDetails ({ txid }) {
|
|
56
|
+
return this.fulcrum.get(`electrumx/tx/data/${txid}`)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async getTransactionDetailsBulk ({ txids, verbose }) {
|
|
60
|
+
try {
|
|
61
|
+
const response = await this.fulcrum.post('electrumx/tx/data', { txids, verbose })
|
|
62
|
+
return response
|
|
63
|
+
} catch (err) {
|
|
64
|
+
wlogger.error('Error in FulcrumUseCases.getTransactionDetailsBulk()', err)
|
|
65
|
+
throw err
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async broadcastTransaction ({ txHex }) {
|
|
70
|
+
try {
|
|
71
|
+
const response = await this.fulcrum.post('electrumx/tx/broadcast', { txHex })
|
|
72
|
+
return response
|
|
73
|
+
} catch (err) {
|
|
74
|
+
wlogger.error('Error in FulcrumUseCases.broadcastTransaction()', err)
|
|
75
|
+
throw err
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async getBlockHeaders ({ height, count }) {
|
|
80
|
+
return this.fulcrum.get(`electrumx/block/headers/${height}?count=${count}`)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async getBlockHeadersBulk ({ heights }) {
|
|
84
|
+
try {
|
|
85
|
+
const response = await this.fulcrum.post('electrumx/block/headers', { heights })
|
|
86
|
+
return response
|
|
87
|
+
} catch (err) {
|
|
88
|
+
wlogger.error('Error in FulcrumUseCases.getBlockHeadersBulk()', err)
|
|
89
|
+
throw err
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async getTransactions ({ address, allTxs }) {
|
|
94
|
+
try {
|
|
95
|
+
const response = await this.fulcrum.get(`electrumx/transactions/${address}`)
|
|
96
|
+
|
|
97
|
+
// Sort transactions in descending order, so that newest transactions are first.
|
|
98
|
+
if (response.transactions && Array.isArray(response.transactions)) {
|
|
99
|
+
response.transactions = await this.bchjs.Electrumx.sortAllTxs(response.transactions, 'DESCENDING')
|
|
100
|
+
|
|
101
|
+
if (!allTxs) {
|
|
102
|
+
// Return only the first 100 transactions of the history.
|
|
103
|
+
response.transactions = response.transactions.slice(0, 100)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return response
|
|
108
|
+
} catch (err) {
|
|
109
|
+
wlogger.error('Error in FulcrumUseCases.getTransactions()', err)
|
|
110
|
+
throw err
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async getTransactionsBulk ({ addresses, allTxs }) {
|
|
115
|
+
try {
|
|
116
|
+
const response = await this.fulcrum.post('electrumx/transactions/', { addresses })
|
|
117
|
+
|
|
118
|
+
// Sort transactions in descending order for each address entry.
|
|
119
|
+
if (response.transactions && Array.isArray(response.transactions)) {
|
|
120
|
+
for (let i = 0; i < response.transactions.length; i++) {
|
|
121
|
+
const thisEntry = response.transactions[i]
|
|
122
|
+
if (thisEntry.transactions && Array.isArray(thisEntry.transactions)) {
|
|
123
|
+
thisEntry.transactions = await this.bchjs.Electrumx.sortAllTxs(thisEntry.transactions, 'DESCENDING')
|
|
124
|
+
|
|
125
|
+
if (!allTxs && thisEntry.transactions.length > 100) {
|
|
126
|
+
// Extract only the first 100 transactions.
|
|
127
|
+
thisEntry.transactions = thisEntry.transactions.slice(0, 100)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return response
|
|
134
|
+
} catch (err) {
|
|
135
|
+
wlogger.error('Error in FulcrumUseCases.getTransactionsBulk()', err)
|
|
136
|
+
throw err
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async getMempool ({ address }) {
|
|
141
|
+
return this.fulcrum.get(`electrumx/unconfirmed/${address}`)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async getMempoolBulk ({ addresses }) {
|
|
145
|
+
try {
|
|
146
|
+
const response = await this.fulcrum.post('electrumx/unconfirmed/', { addresses })
|
|
147
|
+
return response
|
|
148
|
+
} catch (err) {
|
|
149
|
+
wlogger.error('Error in FulcrumUseCases.getMempoolBulk()', err)
|
|
150
|
+
throw err
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export default FulcrumUseCases
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Use cases for interacting with the BCH full node control RPC interface.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
class ControlUseCases {
|
|
6
|
+
constructor (localConfig = {}) {
|
|
7
|
+
this.adapters = localConfig.adapters
|
|
8
|
+
|
|
9
|
+
if (!this.adapters) {
|
|
10
|
+
throw new Error('Adapters instance required when instantiating Control use cases.')
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
this.fullNode = this.adapters.fullNode
|
|
14
|
+
if (!this.fullNode) {
|
|
15
|
+
throw new Error('Full node adapter required when instantiating Control use cases.')
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async getNetworkInfo () {
|
|
20
|
+
return this.fullNode.call('getnetworkinfo')
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default ControlUseCases
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Use cases for interacting with the BCH full node double-spend proof RPC interface.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
class DSProofUseCases {
|
|
6
|
+
constructor (localConfig = {}) {
|
|
7
|
+
this.adapters = localConfig.adapters
|
|
8
|
+
|
|
9
|
+
if (!this.adapters) {
|
|
10
|
+
throw new Error('Adapters instance required when instantiating DSProof use cases.')
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
this.fullNode = this.adapters.fullNode
|
|
14
|
+
if (!this.fullNode) {
|
|
15
|
+
throw new Error('Full node adapter required when instantiating DSProof use cases.')
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async getDSProof ({ txid, verbose }) {
|
|
20
|
+
return this.fullNode.call('getdsproof', [txid, verbose])
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default DSProofUseCases
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Use cases for interacting with the BCH full node mining RPC interface.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
class MiningUseCases {
|
|
6
|
+
constructor (localConfig = {}) {
|
|
7
|
+
this.adapters = localConfig.adapters
|
|
8
|
+
|
|
9
|
+
if (!this.adapters) {
|
|
10
|
+
throw new Error('Adapters instance required when instantiating Mining use cases.')
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
this.fullNode = this.adapters.fullNode
|
|
14
|
+
if (!this.fullNode) {
|
|
15
|
+
throw new Error('Full node adapter required when instantiating Mining use cases.')
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async getMiningInfo () {
|
|
20
|
+
return this.fullNode.call('getmininginfo')
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async getNetworkHashPS ({ nblocks, height }) {
|
|
24
|
+
return this.fullNode.call('getnetworkhashps', [nblocks, height])
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default MiningUseCases
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Use cases for interacting with the BCH full node raw transactions RPC interface.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import wlogger from '../adapters/wlogger.js'
|
|
6
|
+
|
|
7
|
+
class RawTransactionsUseCases {
|
|
8
|
+
constructor (localConfig = {}) {
|
|
9
|
+
this.adapters = localConfig.adapters
|
|
10
|
+
|
|
11
|
+
if (!this.adapters) {
|
|
12
|
+
throw new Error('Adapters instance required when instantiating RawTransactions use cases.')
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
this.fullNode = this.adapters.fullNode
|
|
16
|
+
if (!this.fullNode) {
|
|
17
|
+
throw new Error('Full node adapter required when instantiating RawTransactions use cases.')
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async decodeRawTransaction ({ hex }) {
|
|
22
|
+
return this.fullNode.call('decoderawtransaction', [hex])
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async decodeRawTransactions ({ hexes }) {
|
|
26
|
+
try {
|
|
27
|
+
const promises = hexes.map(hex =>
|
|
28
|
+
this.fullNode.call('decoderawtransaction', [hex], `decoderawtransaction-${hex.slice(0, 16)}`)
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
return await Promise.all(promises)
|
|
32
|
+
} catch (err) {
|
|
33
|
+
wlogger.error('Error in RawTransactionsUseCases.decodeRawTransactions()', err)
|
|
34
|
+
throw err
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async decodeScript ({ hex }) {
|
|
39
|
+
return this.fullNode.call('decodescript', [hex])
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async decodeScripts ({ hexes }) {
|
|
43
|
+
try {
|
|
44
|
+
const promises = hexes.map(hex =>
|
|
45
|
+
this.fullNode.call('decodescript', [hex], `decodescript-${hex.slice(0, 16)}`)
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
return await Promise.all(promises)
|
|
49
|
+
} catch (err) {
|
|
50
|
+
wlogger.error('Error in RawTransactionsUseCases.decodeScripts()', err)
|
|
51
|
+
throw err
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async getRawTransaction ({ txid, verbose = false }) {
|
|
56
|
+
const verboseInt = verbose ? 1 : 0
|
|
57
|
+
return this.fullNode.call('getrawtransaction', [txid, verboseInt])
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async getRawTransactions ({ txids, verbose = false }) {
|
|
61
|
+
try {
|
|
62
|
+
const verboseInt = verbose ? 1 : 0
|
|
63
|
+
const promises = txids.map(txid =>
|
|
64
|
+
this.fullNode.call('getrawtransaction', [txid, verboseInt], `getrawtransaction-${txid}`)
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
return await Promise.all(promises)
|
|
68
|
+
} catch (err) {
|
|
69
|
+
wlogger.error('Error in RawTransactionsUseCases.getRawTransactions()', err)
|
|
70
|
+
throw err
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async getRawTransactionWithHeight ({ txid, verbose = false }) {
|
|
75
|
+
const verboseInt = verbose ? 1 : 0
|
|
76
|
+
const data = await this.fullNode.call('getrawtransaction', [txid, verboseInt])
|
|
77
|
+
|
|
78
|
+
if (verbose && data && data.blockhash) {
|
|
79
|
+
data.height = null
|
|
80
|
+
try {
|
|
81
|
+
// Look up the block height and append it to the TX response.
|
|
82
|
+
const blockHeader = await this.fullNode.call('getblockheader', [data.blockhash, true])
|
|
83
|
+
data.height = blockHeader.height
|
|
84
|
+
} catch (err) {
|
|
85
|
+
// Exit quietly if block header lookup fails
|
|
86
|
+
wlogger.debug('Could not fetch block header for height lookup', err)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return data
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async getBlockHeader ({ blockHash, verbose = false }) {
|
|
94
|
+
return this.fullNode.call('getblockheader', [blockHash, verbose])
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async sendRawTransaction ({ hex }) {
|
|
98
|
+
return this.fullNode.call('sendrawtransaction', [hex])
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async sendRawTransactions ({ hexes }) {
|
|
102
|
+
// Dev Note: Sending the 'sendrawtransaction' RPC call to a full node in parallel will
|
|
103
|
+
// not work. Testing showed that the full node will return the same TXID for
|
|
104
|
+
// different TX hexes. I believe this is by design, to prevent double spends.
|
|
105
|
+
// In parallel, we are essentially asking the node to broadcast a new TX before
|
|
106
|
+
// it's finished broadcasting the previous one. Serial execution is required.
|
|
107
|
+
try {
|
|
108
|
+
const result = []
|
|
109
|
+
for (const hex of hexes) {
|
|
110
|
+
const txid = await this.fullNode.call('sendrawtransaction', [hex], `sendrawtransaction-${hex.slice(0, 16)}`)
|
|
111
|
+
result.push(txid)
|
|
112
|
+
}
|
|
113
|
+
return result
|
|
114
|
+
} catch (err) {
|
|
115
|
+
wlogger.error('Error in RawTransactionsUseCases.sendRawTransactions()', err)
|
|
116
|
+
throw err
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export default RawTransactionsUseCases
|
package/src/use-cases/index.js
CHANGED
|
@@ -6,6 +6,12 @@
|
|
|
6
6
|
|
|
7
7
|
// Local libraries
|
|
8
8
|
import BlockchainUseCases from './full-node-blockchain-use-cases.js'
|
|
9
|
+
import ControlUseCases from './full-node-control-use-cases.js'
|
|
10
|
+
import DSProofUseCases from './full-node-dsproof-use-cases.js'
|
|
11
|
+
import FulcrumUseCases from './fulcrum-use-cases.js'
|
|
12
|
+
import MiningUseCases from './full-node-mining-use-cases.js'
|
|
13
|
+
import RawTransactionsUseCases from './full-node-rawtransactions-use-cases.js'
|
|
14
|
+
import SlpUseCases from './slp-use-cases.js'
|
|
9
15
|
|
|
10
16
|
class UseCases {
|
|
11
17
|
constructor (localConfig = {}) {
|
|
@@ -17,6 +23,12 @@ class UseCases {
|
|
|
17
23
|
}
|
|
18
24
|
|
|
19
25
|
this.blockchain = new BlockchainUseCases({ adapters: this.adapters })
|
|
26
|
+
this.control = new ControlUseCases({ adapters: this.adapters })
|
|
27
|
+
this.dsproof = new DSProofUseCases({ adapters: this.adapters })
|
|
28
|
+
this.fulcrum = new FulcrumUseCases({ adapters: this.adapters })
|
|
29
|
+
this.mining = new MiningUseCases({ adapters: this.adapters })
|
|
30
|
+
this.rawtransactions = new RawTransactionsUseCases({ adapters: this.adapters })
|
|
31
|
+
this.slp = new SlpUseCases({ adapters: this.adapters })
|
|
20
32
|
}
|
|
21
33
|
|
|
22
34
|
// Run any startup Use Cases at the start of the app.
|