psf-bch-api 1.3.0 → 7.2.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 +26 -5
- package/bin/server.js +60 -9
- package/package.json +5 -4
- package/production/docker/.env-local +34 -0
- package/production/docker/Dockerfile +8 -25
- package/production/docker/docker-compose.yml +4 -3
- package/production/docker/temp.js +7 -0
- package/src/config/env/common.js +10 -3
- package/src/config/x402.js +7 -0
- package/src/controllers/rest-api/encryption/controller.js +100 -0
- package/src/controllers/rest-api/encryption/router.js +51 -0
- package/src/controllers/rest-api/fulcrum/controller.js +2 -1
- package/src/controllers/rest-api/index.js +8 -0
- package/src/controllers/rest-api/price/controller.js +96 -0
- package/src/controllers/rest-api/price/router.js +52 -0
- package/src/controllers/rest-api/slp/controller.js +3 -1
- package/src/middleware/basic-auth.js +61 -0
- package/src/use-cases/encryption-use-cases.js +120 -0
- package/src/use-cases/fulcrum-use-cases.js +10 -2
- package/src/use-cases/index.js +9 -0
- package/src/use-cases/price-use-cases.js +83 -0
- package/src/use-cases/slp-use-cases.js +5 -1
- package/test/unit/controllers/encryption-controller-unit.js +203 -0
- package/test/unit/controllers/price-controller-unit.js +116 -0
- package/test/unit/controllers/rest-api-index-unit.js +15 -0
- package/test/unit/use-cases/encryption-use-cases-unit.js +247 -0
- package/test/unit/use-cases/fulcrum-use-cases-unit.js +1 -1
- package/test/unit/use-cases/price-use-cases-unit.js +103 -0
- package/test/unit/use-cases/slp-use-cases-unit.js +1 -1
- /package/{index.js → psf-bch-api.js} +0 -0
|
@@ -9,7 +9,9 @@ import RESTControllers from '../../../src/controllers/rest-api/index.js'
|
|
|
9
9
|
import BlockchainRouter from '../../../src/controllers/rest-api/full-node/blockchain/router.js'
|
|
10
10
|
import ControlRouter from '../../../src/controllers/rest-api/full-node/control/router.js'
|
|
11
11
|
import DSProofRouter from '../../../src/controllers/rest-api/full-node/dsproof/router.js'
|
|
12
|
+
import EncryptionRouter from '../../../src/controllers/rest-api/encryption/router.js'
|
|
12
13
|
import MiningRouter from '../../../src/controllers/rest-api/full-node/mining/router.js'
|
|
14
|
+
import PriceRouter from '../../../src/controllers/rest-api/price/router.js'
|
|
13
15
|
import RawTransactionsRouter from '../../../src/controllers/rest-api/full-node/rawtransactions/router.js'
|
|
14
16
|
import FulcrumRouter from '../../../src/controllers/rest-api/fulcrum/router.js'
|
|
15
17
|
import SlpRouter from '../../../src/controllers/rest-api/slp/router.js'
|
|
@@ -75,6 +77,10 @@ describe('#controllers/rest-api/index.js', () => {
|
|
|
75
77
|
getMiningInfo: () => {},
|
|
76
78
|
getNetworkHashPS: () => {}
|
|
77
79
|
},
|
|
80
|
+
price: {
|
|
81
|
+
getBCHUSD: () => {},
|
|
82
|
+
getPsffppWritePrice: () => {}
|
|
83
|
+
},
|
|
78
84
|
rawtransactions: {
|
|
79
85
|
decodeRawTransaction: () => {},
|
|
80
86
|
decodeRawTransactions: () => {},
|
|
@@ -95,6 +101,9 @@ describe('#controllers/rest-api/index.js', () => {
|
|
|
95
101
|
getMutableCid: () => {},
|
|
96
102
|
decodeOpReturn: () => {},
|
|
97
103
|
getCIDData: () => {}
|
|
104
|
+
},
|
|
105
|
+
encryption: {
|
|
106
|
+
getPublicKey: () => {}
|
|
98
107
|
}
|
|
99
108
|
}
|
|
100
109
|
})
|
|
@@ -124,8 +133,10 @@ describe('#controllers/rest-api/index.js', () => {
|
|
|
124
133
|
const blockchainAttachStub = sandbox.stub(BlockchainRouter.prototype, 'attach')
|
|
125
134
|
const controlAttachStub = sandbox.stub(ControlRouter.prototype, 'attach')
|
|
126
135
|
const dsproofAttachStub = sandbox.stub(DSProofRouter.prototype, 'attach')
|
|
136
|
+
const encryptionAttachStub = sandbox.stub(EncryptionRouter.prototype, 'attach')
|
|
127
137
|
const fulcrumAttachStub = sandbox.stub(FulcrumRouter.prototype, 'attach')
|
|
128
138
|
const miningAttachStub = sandbox.stub(MiningRouter.prototype, 'attach')
|
|
139
|
+
const priceAttachStub = sandbox.stub(PriceRouter.prototype, 'attach')
|
|
129
140
|
const rawtransactionsAttachStub = sandbox.stub(RawTransactionsRouter.prototype, 'attach')
|
|
130
141
|
const slpAttachStub = sandbox.stub(SlpRouter.prototype, 'attach')
|
|
131
142
|
const restControllers = new RESTControllers({
|
|
@@ -142,10 +153,14 @@ describe('#controllers/rest-api/index.js', () => {
|
|
|
142
153
|
assert.equal(controlAttachStub.getCall(0).args[0], app)
|
|
143
154
|
assert.isTrue(dsproofAttachStub.calledOnce)
|
|
144
155
|
assert.equal(dsproofAttachStub.getCall(0).args[0], app)
|
|
156
|
+
assert.isTrue(encryptionAttachStub.calledOnce)
|
|
157
|
+
assert.equal(encryptionAttachStub.getCall(0).args[0], app)
|
|
145
158
|
assert.isTrue(fulcrumAttachStub.calledOnce)
|
|
146
159
|
assert.equal(fulcrumAttachStub.getCall(0).args[0], app)
|
|
147
160
|
assert.isTrue(miningAttachStub.calledOnce)
|
|
148
161
|
assert.equal(miningAttachStub.getCall(0).args[0], app)
|
|
162
|
+
assert.isTrue(priceAttachStub.calledOnce)
|
|
163
|
+
assert.equal(priceAttachStub.getCall(0).args[0], app)
|
|
149
164
|
assert.isTrue(rawtransactionsAttachStub.calledOnce)
|
|
150
165
|
assert.equal(rawtransactionsAttachStub.getCall(0).args[0], app)
|
|
151
166
|
assert.isTrue(slpAttachStub.calledOnce)
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Unit tests for EncryptionUseCases.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { assert } from 'chai'
|
|
6
|
+
import sinon from 'sinon'
|
|
7
|
+
|
|
8
|
+
import EncryptionUseCases from '../../../src/use-cases/encryption-use-cases.js'
|
|
9
|
+
|
|
10
|
+
describe('#encryption-use-cases.js', () => {
|
|
11
|
+
let sandbox
|
|
12
|
+
let mockAdapters
|
|
13
|
+
let mockUseCases
|
|
14
|
+
let mockBchjs
|
|
15
|
+
let uut
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
sandbox = sinon.createSandbox()
|
|
19
|
+
mockAdapters = {}
|
|
20
|
+
|
|
21
|
+
// Mock bchjs
|
|
22
|
+
mockBchjs = {
|
|
23
|
+
Address: {
|
|
24
|
+
toCashAddress: sandbox.stub().returns('bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf')
|
|
25
|
+
},
|
|
26
|
+
ECPair: {
|
|
27
|
+
fromPublicKey: sandbox.stub().returns({}),
|
|
28
|
+
toCashAddress: sandbox.stub().returns('bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf')
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Mock use cases
|
|
33
|
+
mockUseCases = {
|
|
34
|
+
fulcrum: {
|
|
35
|
+
getTransactions: sandbox.stub().resolves({
|
|
36
|
+
transactions: [
|
|
37
|
+
{ tx_hash: 'abc123def456' }
|
|
38
|
+
]
|
|
39
|
+
})
|
|
40
|
+
},
|
|
41
|
+
rawtransactions: {
|
|
42
|
+
getRawTransaction: sandbox.stub().resolves({
|
|
43
|
+
vin: [
|
|
44
|
+
{
|
|
45
|
+
scriptSig: {
|
|
46
|
+
asm: 'signature 02abc123def456789'
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
uut = new EncryptionUseCases({
|
|
55
|
+
adapters: mockAdapters,
|
|
56
|
+
useCases: mockUseCases,
|
|
57
|
+
bchjs: mockBchjs
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
afterEach(() => {
|
|
62
|
+
sandbox.restore()
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
describe('#constructor()', () => {
|
|
66
|
+
it('should require adapters', () => {
|
|
67
|
+
assert.throws(() => {
|
|
68
|
+
// eslint-disable-next-line no-new
|
|
69
|
+
new EncryptionUseCases({ useCases: mockUseCases })
|
|
70
|
+
}, /Adapters instance required/)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('should require useCases', () => {
|
|
74
|
+
assert.throws(() => {
|
|
75
|
+
// eslint-disable-next-line no-new
|
|
76
|
+
new EncryptionUseCases({ adapters: mockAdapters })
|
|
77
|
+
}, /UseCases instance required/)
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
describe('#getPublicKey()', () => {
|
|
82
|
+
it('should return public key when found', async () => {
|
|
83
|
+
const result = await uut.getPublicKey({ address: 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf' })
|
|
84
|
+
|
|
85
|
+
assert.isTrue(result.success)
|
|
86
|
+
assert.equal(result.publicKey, '02abc123def456789')
|
|
87
|
+
assert.isTrue(mockBchjs.Address.toCashAddress.calledOnce)
|
|
88
|
+
assert.isTrue(mockUseCases.fulcrum.getTransactions.calledOnce)
|
|
89
|
+
assert.isTrue(mockUseCases.rawtransactions.getRawTransaction.calledOnce)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
it('should return not found when public key does not match', async () => {
|
|
93
|
+
// Make the ECPair.toCashAddress return a different address
|
|
94
|
+
mockBchjs.ECPair.toCashAddress.returns('bitcoincash:qqq000000000000000000000000000000000000000')
|
|
95
|
+
|
|
96
|
+
const result = await uut.getPublicKey({ address: 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf' })
|
|
97
|
+
|
|
98
|
+
assert.isFalse(result.success)
|
|
99
|
+
assert.equal(result.publicKey, 'not found')
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('should throw error when no transaction history', async () => {
|
|
103
|
+
mockUseCases.fulcrum.getTransactions.resolves({
|
|
104
|
+
transactions: []
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
await uut.getPublicKey({ address: 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf' })
|
|
109
|
+
assert.fail('Should have thrown an error')
|
|
110
|
+
} catch (err) {
|
|
111
|
+
assert.equal(err.message, 'No transaction history.')
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('should handle transactions without scriptSig', async () => {
|
|
116
|
+
mockUseCases.rawtransactions.getRawTransaction.resolves({
|
|
117
|
+
vin: [
|
|
118
|
+
{ txid: 'coinbase' } // No scriptSig
|
|
119
|
+
]
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
const result = await uut.getPublicKey({ address: 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf' })
|
|
123
|
+
|
|
124
|
+
assert.isFalse(result.success)
|
|
125
|
+
assert.equal(result.publicKey, 'not found')
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
it('should handle invalid public key hex gracefully', async () => {
|
|
129
|
+
mockUseCases.rawtransactions.getRawTransaction.resolves({
|
|
130
|
+
vin: [
|
|
131
|
+
{
|
|
132
|
+
scriptSig: {
|
|
133
|
+
asm: 'signature NOT_VALID_HEX'
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
const result = await uut.getPublicKey({ address: 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf' })
|
|
140
|
+
|
|
141
|
+
assert.isFalse(result.success)
|
|
142
|
+
assert.equal(result.publicKey, 'not found')
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
it('should handle ECPair.fromPublicKey throwing error', async () => {
|
|
146
|
+
mockBchjs.ECPair.fromPublicKey.throws(new Error('Invalid public key'))
|
|
147
|
+
|
|
148
|
+
const result = await uut.getPublicKey({ address: 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf' })
|
|
149
|
+
|
|
150
|
+
assert.isFalse(result.success)
|
|
151
|
+
assert.equal(result.publicKey, 'not found')
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
it('should search through multiple transactions', async () => {
|
|
155
|
+
// First transaction has no matching public key
|
|
156
|
+
mockUseCases.fulcrum.getTransactions.resolves({
|
|
157
|
+
transactions: [
|
|
158
|
+
{ tx_hash: 'tx1' },
|
|
159
|
+
{ tx_hash: 'tx2' }
|
|
160
|
+
]
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
// Return different data for each tx - first tx has input with non-matching key
|
|
164
|
+
mockUseCases.rawtransactions.getRawTransaction
|
|
165
|
+
.onFirstCall().resolves({
|
|
166
|
+
vin: [
|
|
167
|
+
{
|
|
168
|
+
scriptSig: {
|
|
169
|
+
asm: 'sig 02aaa111bbb222ccc'
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
]
|
|
173
|
+
})
|
|
174
|
+
.onSecondCall().resolves({
|
|
175
|
+
vin: [
|
|
176
|
+
{
|
|
177
|
+
scriptSig: {
|
|
178
|
+
asm: 'sig 02abc123def456789'
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
]
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
// First tx doesn't match, second tx matches
|
|
185
|
+
mockBchjs.ECPair.toCashAddress
|
|
186
|
+
.onFirstCall().returns('bitcoincash:qqq000000000000000000000000000000000000000')
|
|
187
|
+
.onSecondCall().returns('bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf')
|
|
188
|
+
|
|
189
|
+
const result = await uut.getPublicKey({ address: 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf' })
|
|
190
|
+
|
|
191
|
+
assert.isTrue(result.success)
|
|
192
|
+
assert.equal(result.publicKey, '02abc123def456789')
|
|
193
|
+
assert.equal(mockUseCases.rawtransactions.getRawTransaction.callCount, 2)
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
it('should search through multiple inputs in a transaction', async () => {
|
|
197
|
+
mockUseCases.rawtransactions.getRawTransaction.resolves({
|
|
198
|
+
vin: [
|
|
199
|
+
{
|
|
200
|
+
scriptSig: {
|
|
201
|
+
asm: 'sig 02aaa111bbb222ccc'
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
scriptSig: {
|
|
206
|
+
asm: 'sig 02abc123def456789'
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
]
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
// First input doesn't match, second input matches
|
|
213
|
+
mockBchjs.ECPair.toCashAddress
|
|
214
|
+
.onFirstCall().returns('bitcoincash:qqq000000000000000000000000000000000000000')
|
|
215
|
+
.onSecondCall().returns('bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf')
|
|
216
|
+
|
|
217
|
+
const result = await uut.getPublicKey({ address: 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf' })
|
|
218
|
+
|
|
219
|
+
assert.isTrue(result.success)
|
|
220
|
+
assert.equal(result.publicKey, '02abc123def456789')
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
it('should propagate fulcrum errors', async () => {
|
|
224
|
+
const error = new Error('Fulcrum API error')
|
|
225
|
+
mockUseCases.fulcrum.getTransactions.rejects(error)
|
|
226
|
+
|
|
227
|
+
try {
|
|
228
|
+
await uut.getPublicKey({ address: 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf' })
|
|
229
|
+
assert.fail('Should have thrown an error')
|
|
230
|
+
} catch (err) {
|
|
231
|
+
assert.equal(err.message, 'Fulcrum API error')
|
|
232
|
+
}
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
it('should propagate rawtransactions errors', async () => {
|
|
236
|
+
const error = new Error('RawTransactions API error')
|
|
237
|
+
mockUseCases.rawtransactions.getRawTransaction.rejects(error)
|
|
238
|
+
|
|
239
|
+
try {
|
|
240
|
+
await uut.getPublicKey({ address: 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf' })
|
|
241
|
+
assert.fail('Should have thrown an error')
|
|
242
|
+
} catch (err) {
|
|
243
|
+
assert.equal(err.message, 'RawTransactions API error')
|
|
244
|
+
}
|
|
245
|
+
})
|
|
246
|
+
})
|
|
247
|
+
})
|
|
@@ -24,7 +24,7 @@ describe('#fulcrum-use-cases.js', () => {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
// Create a mock BCHJS instance with stubbed sortAllTxs method
|
|
27
|
-
const mockBchjs = new BCHJS()
|
|
27
|
+
const mockBchjs = new BCHJS({ restURL: 'http://localhost:5942/v6/' })
|
|
28
28
|
if (!mockBchjs.Electrumx) {
|
|
29
29
|
mockBchjs.Electrumx = {}
|
|
30
30
|
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Unit tests for PriceUseCases.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { assert } from 'chai'
|
|
6
|
+
import sinon from 'sinon'
|
|
7
|
+
|
|
8
|
+
import PriceUseCases from '../../../src/use-cases/price-use-cases.js'
|
|
9
|
+
|
|
10
|
+
describe('#price-use-cases.js', () => {
|
|
11
|
+
let sandbox
|
|
12
|
+
let mockAdapters
|
|
13
|
+
let mockAxios
|
|
14
|
+
let mockConfig
|
|
15
|
+
let uut
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
sandbox = sinon.createSandbox()
|
|
19
|
+
mockAdapters = {}
|
|
20
|
+
|
|
21
|
+
mockConfig = {
|
|
22
|
+
restURL: 'http://localhost:3000/v5/'
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Mock axios
|
|
26
|
+
mockAxios = {
|
|
27
|
+
request: sandbox.stub()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
uut = new PriceUseCases({
|
|
31
|
+
adapters: mockAdapters,
|
|
32
|
+
axios: mockAxios,
|
|
33
|
+
config: mockConfig
|
|
34
|
+
})
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
afterEach(() => {
|
|
38
|
+
sandbox.restore()
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
describe('#constructor()', () => {
|
|
42
|
+
it('should require adapters', () => {
|
|
43
|
+
assert.throws(() => {
|
|
44
|
+
// eslint-disable-next-line no-new
|
|
45
|
+
new PriceUseCases()
|
|
46
|
+
}, /Adapters instance required/)
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
describe('#getBCHUSD()', () => {
|
|
51
|
+
it('should return BCH price from Coinex API', async () => {
|
|
52
|
+
const mockPrice = 250.5
|
|
53
|
+
mockAxios.request.resolves({
|
|
54
|
+
data: {
|
|
55
|
+
data: {
|
|
56
|
+
ticker: {
|
|
57
|
+
last: mockPrice.toString()
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
const result = await uut.getBCHUSD()
|
|
64
|
+
|
|
65
|
+
assert.equal(result, mockPrice)
|
|
66
|
+
assert.isTrue(mockAxios.request.calledOnce)
|
|
67
|
+
const callArgs = mockAxios.request.getCall(0).args[0]
|
|
68
|
+
assert.equal(callArgs.method, 'get')
|
|
69
|
+
assert.equal(callArgs.baseURL, 'https://api.coinex.com/v1/market/ticker?market=bchusdt')
|
|
70
|
+
assert.equal(callArgs.timeout, 15000)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('should handle errors', async () => {
|
|
74
|
+
const error = new Error('API error')
|
|
75
|
+
mockAxios.request.rejects(error)
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
await uut.getBCHUSD()
|
|
79
|
+
assert.fail('Should have thrown an error')
|
|
80
|
+
} catch (err) {
|
|
81
|
+
assert.equal(err.message, 'API error')
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
describe('#getPsffppWritePrice()', () => {
|
|
87
|
+
it('should handle errors properly', async () => {
|
|
88
|
+
// Note: Full unit testing of getPsffppWritePrice is difficult due to dynamic imports
|
|
89
|
+
// of SlpWallet and PSFFPP. Integration tests should verify the full flow.
|
|
90
|
+
// This test verifies that errors are properly handled and propagated.
|
|
91
|
+
try {
|
|
92
|
+
// This will likely fail in unit test environment without proper setup
|
|
93
|
+
// but we verify error handling works correctly
|
|
94
|
+
await uut.getPsffppWritePrice()
|
|
95
|
+
// If it succeeds, that's also acceptable
|
|
96
|
+
} catch (err) {
|
|
97
|
+
// Verify error is properly formatted
|
|
98
|
+
assert.isTrue(err instanceof Error)
|
|
99
|
+
// Verify error was logged (indirectly through wlogger)
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
})
|
|
103
|
+
})
|
|
File without changes
|