@psf/bch-js 5.3.1 → 5.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -7
- package/src/bch-js.js +0 -2
- package/src/psf-slp-indexer.js +13 -11
- package/test/integration/chains/bchn/psf-slp-indexer.integration.js +12 -1
- package/test/integration/chains/bchn/utxo-integration.js +11 -126
- package/src/ipfs.js +0 -454
- package/test/integration/chains/abc/slp.js +0 -226
- package/test/integration/chains/bchn-no-wl-slpdb/rawtransaction.js +0 -71
- package/test/integration/chains/bchn-no-wl-slpdb/slp.js +0 -273
- package/test/integration/chains/bchn-no-wl-slpdb/utxo-integration.js +0 -105
- package/test/unit/ipfs.js +0 -443
package/src/ipfs.js
DELETED
|
@@ -1,454 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
This library interacts with the IPFS REST API at FullStack.cash for uploading
|
|
3
|
-
and downloading data from the IPFS network.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const axios = require('axios')
|
|
7
|
-
const Uppy = require('@uppy/core')
|
|
8
|
-
const Tus = require('@uppy/tus')
|
|
9
|
-
const fs = require('fs')
|
|
10
|
-
|
|
11
|
-
let _this
|
|
12
|
-
|
|
13
|
-
class IPFS {
|
|
14
|
-
constructor (config) {
|
|
15
|
-
this.IPFS_API = process.env.IPFS_API
|
|
16
|
-
? process.env.IPFS_API
|
|
17
|
-
: 'https://ipfs-file-upload.fullstackcash.nl'
|
|
18
|
-
// : `http://localhost:5001`
|
|
19
|
-
|
|
20
|
-
// Default options when calling axios.
|
|
21
|
-
this.axiosOptions = {
|
|
22
|
-
headers: {
|
|
23
|
-
// authorization: `Token ${this.apiToken}`,
|
|
24
|
-
timeout: 15000 // Timeout if the server does not respond in time.
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
_this = this
|
|
29
|
-
|
|
30
|
-
_this.axios = axios
|
|
31
|
-
_this.fs = fs
|
|
32
|
-
|
|
33
|
-
// Initialize Uppy
|
|
34
|
-
_this.uppy = _this.initUppy()
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Initializes Uppy, which is used for file uploads.
|
|
38
|
-
initUppy () {
|
|
39
|
-
const uppy = Uppy({
|
|
40
|
-
allowMultipleUploads: false,
|
|
41
|
-
meta: { test: 'avatar' },
|
|
42
|
-
debug: false,
|
|
43
|
-
restrictions: {
|
|
44
|
-
maxFileSize: null,
|
|
45
|
-
maxNumberOfFiles: 1,
|
|
46
|
-
minNumberOfFiles: 1,
|
|
47
|
-
allowedFileTypes: null // type of files allowed to load
|
|
48
|
-
}
|
|
49
|
-
})
|
|
50
|
-
uppy.use(Tus, { endpoint: `${_this.IPFS_API}/uppy-files` })
|
|
51
|
-
|
|
52
|
-
return uppy
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* @api IPFS.createFileModelServer() createFileModelServer()
|
|
57
|
-
* @apiName createFileModelServer()
|
|
58
|
-
* @apiGroup IPFS
|
|
59
|
-
* @apiDescription Creates a new model on the server. If successful, will
|
|
60
|
-
* return an object with file data. That object contains a BCH address,
|
|
61
|
-
* payment amount, and _id required to be able to upload a file.
|
|
62
|
-
*
|
|
63
|
-
* @apiExample Example usage:
|
|
64
|
-
* (async () => {
|
|
65
|
-
* try {
|
|
66
|
-
* const path = `${__dirname}/ipfs.js`
|
|
67
|
-
* let fileData = await bchjs.IPFS.createFileModelServer(path);
|
|
68
|
-
* console.log(fileData);
|
|
69
|
-
* } catch(error) {
|
|
70
|
-
* console.error(error)
|
|
71
|
-
* }
|
|
72
|
-
* })()
|
|
73
|
-
*
|
|
74
|
-
* {
|
|
75
|
-
* "success": true,
|
|
76
|
-
* "hostingCostBCH": 0.00004197,
|
|
77
|
-
* "hostingCostUSD": 0.01,
|
|
78
|
-
* "file": {
|
|
79
|
-
* "payloadLink": "",
|
|
80
|
-
* "hasBeenPaid": false,
|
|
81
|
-
* "_id": "5ec562319bfacc745e8d8a52",
|
|
82
|
-
* "schemaVersion": 1,
|
|
83
|
-
* "size": 4458,
|
|
84
|
-
* "fileName": "ipfs.js",
|
|
85
|
-
* "fileExtension": "js",
|
|
86
|
-
* "createdTimestamp": "1589994033.655",
|
|
87
|
-
* "hostingCost": 4196,
|
|
88
|
-
* "walletIndex": 49,
|
|
89
|
-
* "bchAddr": "bchtest:qzrpkevu7h2ayfa4rjx08r5elvpfu72dg567x3mh3c",
|
|
90
|
-
* "__v": 0
|
|
91
|
-
* }
|
|
92
|
-
*/
|
|
93
|
-
async createFileModelServer (path) {
|
|
94
|
-
try {
|
|
95
|
-
// Ensure the file exists.
|
|
96
|
-
if (!_this.fs.existsSync(path)) {
|
|
97
|
-
throw new Error(`Could not find this file: ${path}`)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Read in the file.
|
|
101
|
-
const fileBuf = _this.fs.readFileSync(path)
|
|
102
|
-
// console.log(`fileBuf: `, fileBuf)
|
|
103
|
-
|
|
104
|
-
// console.log(`Buffer length: ${fileBuf.length}`)
|
|
105
|
-
|
|
106
|
-
// Get the file name from the path.
|
|
107
|
-
const splitPath = path.split('/')
|
|
108
|
-
const fileName = splitPath[splitPath.length - 1]
|
|
109
|
-
|
|
110
|
-
// Get the file extension.
|
|
111
|
-
const splitExt = fileName.split('.')
|
|
112
|
-
const fileExt = splitExt[splitExt.length - 1]
|
|
113
|
-
|
|
114
|
-
const fileObj = {
|
|
115
|
-
schemaVersion: 1,
|
|
116
|
-
size: fileBuf.length,
|
|
117
|
-
fileName: fileName,
|
|
118
|
-
fileExtension: fileExt
|
|
119
|
-
}
|
|
120
|
-
// console.log(`fileObj: ${JSON.stringify(fileObj, null, 2)}`)
|
|
121
|
-
|
|
122
|
-
const fileData = await _this.axios.post(`${this.IPFS_API}/files`, {
|
|
123
|
-
file: fileObj
|
|
124
|
-
})
|
|
125
|
-
// console.log(`fileData.data: ${JSON.stringify(fileData.data, null, 2)}`)
|
|
126
|
-
|
|
127
|
-
return fileData.data
|
|
128
|
-
} catch (err) {
|
|
129
|
-
console.error('Error in createFileModel()')
|
|
130
|
-
throw err
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* @api IPFS.uploadFileServer() uploadFileServer()
|
|
136
|
-
* @apiName uploadFile()
|
|
137
|
-
* @apiGroup IPFS
|
|
138
|
-
* @apiDescription Upload a file to the FullStack.cash IPFS server. If
|
|
139
|
-
* successful, it will return an object with an ID, a BCH address, and an
|
|
140
|
-
* amount of BCH to pay.
|
|
141
|
-
*
|
|
142
|
-
* @apiExample Example usage:
|
|
143
|
-
* (async () => {
|
|
144
|
-
* try {
|
|
145
|
-
* const path = `${__dirname}/ipfs.js`
|
|
146
|
-
* let fileData = await bchjs.IPFS.uploadFileServer(path, "5ec562319bfacc745e8d8a52");
|
|
147
|
-
* console.log(fileData);
|
|
148
|
-
* } catch(error) {
|
|
149
|
-
* console.error(error)
|
|
150
|
-
* }
|
|
151
|
-
* })()
|
|
152
|
-
*
|
|
153
|
-
* {
|
|
154
|
-
* "schemaVersion": 1,
|
|
155
|
-
* "size": 2374,
|
|
156
|
-
* "fileId": "5ec562319bfacc745e8d8a52",
|
|
157
|
-
* "fileName": "ipfs.js",
|
|
158
|
-
* "fileExtension": "js"
|
|
159
|
-
* }
|
|
160
|
-
*/
|
|
161
|
-
async uploadFileServer (path, modelId) {
|
|
162
|
-
try {
|
|
163
|
-
// Ensure the file exists.
|
|
164
|
-
if (!_this.fs.existsSync(path)) {
|
|
165
|
-
throw new Error(`Could not find this file: ${path}`)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (!modelId) {
|
|
169
|
-
throw new Error(
|
|
170
|
-
'Must include a file model ID in order to upload a file.'
|
|
171
|
-
)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Read in the file.
|
|
175
|
-
const fileBuf = _this.fs.readFileSync(path)
|
|
176
|
-
|
|
177
|
-
// Get the file name from the path.
|
|
178
|
-
const splitPath = path.split('/')
|
|
179
|
-
const fileName = splitPath[splitPath.length - 1]
|
|
180
|
-
|
|
181
|
-
// Prepare the upload object. Get a file ID from Uppy.
|
|
182
|
-
const id = _this.uppy.addFile({
|
|
183
|
-
name: fileName,
|
|
184
|
-
data: fileBuf,
|
|
185
|
-
source: 'Local',
|
|
186
|
-
isRemote: false
|
|
187
|
-
})
|
|
188
|
-
// console.log(`id: ${JSON.stringify(id, null, 2)}`)
|
|
189
|
-
|
|
190
|
-
// Add the model ID, required to be allowed to upload the file.
|
|
191
|
-
_this.uppy.setFileMeta(id, { fileModelId: modelId })
|
|
192
|
-
|
|
193
|
-
// Upload the file to the server.
|
|
194
|
-
const upData = await _this.uppy.upload()
|
|
195
|
-
|
|
196
|
-
if (upData.failed.length) {
|
|
197
|
-
throw new Error('The file could not be uploaded')
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (upData.successful.length) {
|
|
201
|
-
delete upData.successful[0].data
|
|
202
|
-
// console.log(`upData: ${JSON.stringify(upData, null, 2)}`)
|
|
203
|
-
|
|
204
|
-
const fileObj = {
|
|
205
|
-
schemaVersion: 1,
|
|
206
|
-
size: upData.successful[0].progress.bytesTotal,
|
|
207
|
-
fileId: upData.successful[0].meta.fileModelId,
|
|
208
|
-
fileName: upData.successful[0].name,
|
|
209
|
-
fileExtension: upData.successful[0].extension
|
|
210
|
-
}
|
|
211
|
-
// console.log(`fileObj: ${JSON.stringify(fileObj, null, 2)}`)
|
|
212
|
-
|
|
213
|
-
return fileObj
|
|
214
|
-
// return true
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return false
|
|
218
|
-
} catch (err) {
|
|
219
|
-
console.error('Error in bch-js/src/ipfs.js/upload(): ')
|
|
220
|
-
throw err
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* @api IPFS.getStatus() getStatus()
|
|
226
|
-
* @apiName getStatus()
|
|
227
|
-
* @apiGroup IPFS
|
|
228
|
-
* @apiDescription Gets the status of the uploaded file. Will return an object
|
|
229
|
-
* that indicates the payment status. If the file is paid, it should contain
|
|
230
|
-
* an IPFS hash.
|
|
231
|
-
*
|
|
232
|
-
* @apiExample Example usage:
|
|
233
|
-
* (async () => {
|
|
234
|
-
* try {
|
|
235
|
-
* const modelId = "5ec7392c2acfe57aa62e945a"
|
|
236
|
-
* let fileData = await bchjs.IPFS.getStatus(modelId)
|
|
237
|
-
* console.log(fileData)
|
|
238
|
-
* } catch(error) {
|
|
239
|
-
* console.error(error)
|
|
240
|
-
* }
|
|
241
|
-
* })()
|
|
242
|
-
*
|
|
243
|
-
* {
|
|
244
|
-
* "hasBeenPaid": true,
|
|
245
|
-
* "satCost": 4403,
|
|
246
|
-
* "bchAddr": "bchtest:qz5z82u0suqh80x5tfx4ht8kdrkkw664vcy44uz0wk",
|
|
247
|
-
* "ipfsHash": "QmRDHPhY5hCNVRMVQvS2H9uty8P1skdwgLaHpUAkEvsjcE",
|
|
248
|
-
* "fileId": "5ec7392c2acfe57aa62e945a",
|
|
249
|
-
* "fileName": "ipfs-e2e.js"
|
|
250
|
-
* }
|
|
251
|
-
*/
|
|
252
|
-
async getStatus (modelId) {
|
|
253
|
-
try {
|
|
254
|
-
if (!modelId) throw new Error('Must include a file model ID.')
|
|
255
|
-
|
|
256
|
-
const fileData = await _this.axios.get(
|
|
257
|
-
`${this.IPFS_API}/files/${modelId}`
|
|
258
|
-
)
|
|
259
|
-
// console.log(`fileData.data: ${JSON.stringify(fileData.data, null, 2)}`)
|
|
260
|
-
|
|
261
|
-
const fileObj = {
|
|
262
|
-
hasBeenPaid: fileData.data.file.hasBeenPaid,
|
|
263
|
-
satCost: fileData.data.file.hostingCost,
|
|
264
|
-
bchAddr: fileData.data.file.bchAddr,
|
|
265
|
-
ipfsHash: fileData.data.file.payloadLink,
|
|
266
|
-
fileId: fileData.data.file._id,
|
|
267
|
-
fileName: fileData.data.file.fileName
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
return fileObj
|
|
271
|
-
} catch (err) {
|
|
272
|
-
console.error('Error in getStatus()')
|
|
273
|
-
throw err
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* @api IPFS.createFileModelWeb() createFileModelWeb()
|
|
279
|
-
* @apiName createFileModelWeb()
|
|
280
|
-
* @apiGroup IPFS
|
|
281
|
-
* @apiDescription Creates a new model on the server. If successful, will
|
|
282
|
-
* return an object with file data. That object contains a BCH address,
|
|
283
|
-
* payment amount, and _id required to be able to upload a file.
|
|
284
|
-
*
|
|
285
|
-
* @apiExample Example usage:
|
|
286
|
-
* (async () => {
|
|
287
|
-
* try {
|
|
288
|
-
* const content = ['PSF']
|
|
289
|
-
* const name = 'psf.txt' // Content can be Array , ArrayBuffer , Blob
|
|
290
|
-
* const options = { type: "text/plain" }
|
|
291
|
-
* const file = new File(content,name,options)
|
|
292
|
-
* let fileData = await bchjs.IPFS.createFileModelWeb(file);
|
|
293
|
-
* console.log(fileData);
|
|
294
|
-
* } catch(error) {
|
|
295
|
-
* console.error(error)
|
|
296
|
-
* }
|
|
297
|
-
* })()
|
|
298
|
-
*
|
|
299
|
-
* {
|
|
300
|
-
* "success": true,
|
|
301
|
-
* "hostingCostBCH": 0.00004197,
|
|
302
|
-
* "hostingCostUSD": 0.01,
|
|
303
|
-
* "file": {
|
|
304
|
-
* "payloadLink": "",
|
|
305
|
-
* "hasBeenPaid": false,
|
|
306
|
-
* "_id": "5ec562319bfacc745e8d8a52",
|
|
307
|
-
* "schemaVersion": 1,
|
|
308
|
-
* "size": 4458,
|
|
309
|
-
* "fileName": "ipfs.js",
|
|
310
|
-
* "fileExtension": "js",
|
|
311
|
-
* "createdTimestamp": "1589994033.655",
|
|
312
|
-
* "hostingCost": 4196,
|
|
313
|
-
* "walletIndex": 49,
|
|
314
|
-
* "bchAddr": "bchtest:qzrpkevu7h2ayfa4rjx08r5elvpfu72dg567x3mh3c",
|
|
315
|
-
* "__v": 0
|
|
316
|
-
* }
|
|
317
|
-
*/
|
|
318
|
-
async createFileModelWeb (file) {
|
|
319
|
-
try {
|
|
320
|
-
if (!file) throw new Error('File is required')
|
|
321
|
-
|
|
322
|
-
const { name, size } = file
|
|
323
|
-
|
|
324
|
-
if (!name || typeof name !== 'string') {
|
|
325
|
-
throw new Error("File should have the property 'name' of string type")
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
if (!size || typeof size !== 'number') {
|
|
329
|
-
throw new Error("File should have the property 'size' of number type")
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// Get the file extension.
|
|
333
|
-
const splitExt = name.split('.')
|
|
334
|
-
const fileExt = splitExt[splitExt.length - 1]
|
|
335
|
-
|
|
336
|
-
const fileObj = {
|
|
337
|
-
schemaVersion: 1,
|
|
338
|
-
size: size,
|
|
339
|
-
fileName: name,
|
|
340
|
-
fileExtension: fileExt
|
|
341
|
-
}
|
|
342
|
-
// console.log(`fileObj: ${JSON.stringify(fileObj, null, 2)}`)
|
|
343
|
-
|
|
344
|
-
const fileData = await _this.axios.post(`${this.IPFS_API}/files`, {
|
|
345
|
-
file: fileObj
|
|
346
|
-
})
|
|
347
|
-
// console.log(`fileData.data: ${JSON.stringify(fileData.data, null, 2)}`)
|
|
348
|
-
|
|
349
|
-
return fileData.data
|
|
350
|
-
} catch (err) {
|
|
351
|
-
console.error('Error in createFileModelWeb()')
|
|
352
|
-
throw err
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* @api IPFS.uploadFileWeb() uploadFileWeb()
|
|
358
|
-
* @apiName uploadFileWeb()
|
|
359
|
-
* @apiGroup IPFS
|
|
360
|
-
* @apiDescription Upload a file to the FullStack.cash IPFS server. If
|
|
361
|
-
* successful, it will return an object with an ID, a BCH address, and an
|
|
362
|
-
* amount of BCH to pay.
|
|
363
|
-
*
|
|
364
|
-
* @apiExample Example usage:
|
|
365
|
-
* (async () => {
|
|
366
|
-
* try {
|
|
367
|
-
* * const content = ['PSF']
|
|
368
|
-
* const name = 'psf.txt' // Content can be Array , ArrayBuffer , Blob
|
|
369
|
-
* const options = { type: "text/plain" }
|
|
370
|
-
* const file = new File(content,name,options)
|
|
371
|
-
* let fileData = await bchjs.IPFS.uploadFile(file, "5ec562319bfacc745e8d8a52");
|
|
372
|
-
* console.log(fileData);
|
|
373
|
-
* } catch(error) {
|
|
374
|
-
* console.error(error)
|
|
375
|
-
* }
|
|
376
|
-
* })()
|
|
377
|
-
*
|
|
378
|
-
* {
|
|
379
|
-
* "schemaVersion": 1,
|
|
380
|
-
* "size": 2374,
|
|
381
|
-
* "fileId": "5ec562319bfacc745e8d8a52",
|
|
382
|
-
* "fileName": "ipfs.js",
|
|
383
|
-
* "fileExtension": "js"
|
|
384
|
-
* }
|
|
385
|
-
*/
|
|
386
|
-
async uploadFileWeb (file, modelId) {
|
|
387
|
-
try {
|
|
388
|
-
if (!file) throw new Error('File is required')
|
|
389
|
-
|
|
390
|
-
const { name, type, size } = file
|
|
391
|
-
|
|
392
|
-
if (!name || typeof name !== 'string') {
|
|
393
|
-
throw new Error("File should have the property 'name' of string type")
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
if (!type || typeof type !== 'string') {
|
|
397
|
-
throw new Error("File should have the property 'type' of string type")
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
if (!size || typeof size !== 'number') {
|
|
401
|
-
throw new Error("File should have the property 'size' of number type")
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
if (!modelId) {
|
|
405
|
-
throw new Error(
|
|
406
|
-
'Must include a file model ID in order to upload a file.'
|
|
407
|
-
)
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// Prepare the upload object. Get a file ID from Uppy.
|
|
411
|
-
const id = _this.uppy.addFile({
|
|
412
|
-
name: name,
|
|
413
|
-
data: file,
|
|
414
|
-
source: 'Local',
|
|
415
|
-
isRemote: false
|
|
416
|
-
})
|
|
417
|
-
// console.log(`id: ${JSON.stringify(id, null, 2)}`)
|
|
418
|
-
|
|
419
|
-
// Add the model ID, required to be allowed to upload the file.
|
|
420
|
-
_this.uppy.setFileMeta(id, { fileModelId: modelId })
|
|
421
|
-
|
|
422
|
-
// Upload the file to the server.
|
|
423
|
-
const upData = await _this.uppy.upload()
|
|
424
|
-
|
|
425
|
-
if (upData.failed.length) {
|
|
426
|
-
throw new Error('The file could not be uploaded')
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
if (upData.successful.length) {
|
|
430
|
-
delete upData.successful[0].data
|
|
431
|
-
// console.log(`upData: ${JSON.stringify(upData, null, 2)}`)
|
|
432
|
-
|
|
433
|
-
const fileObj = {
|
|
434
|
-
schemaVersion: 1,
|
|
435
|
-
size: upData.successful[0].progress.bytesTotal,
|
|
436
|
-
fileId: upData.successful[0].meta.fileModelId,
|
|
437
|
-
fileName: upData.successful[0].name,
|
|
438
|
-
fileExtension: upData.successful[0].extension
|
|
439
|
-
}
|
|
440
|
-
// console.log(`fileObj: ${JSON.stringify(fileObj, null, 2)}`)
|
|
441
|
-
|
|
442
|
-
return fileObj
|
|
443
|
-
// return true
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
return false
|
|
447
|
-
} catch (err) {
|
|
448
|
-
console.error('Error in bch-js/src/ipfs.js/uploadFileWeb(): ')
|
|
449
|
-
throw err
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
module.exports = IPFS
|
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Integration tests for the bchjs covering SLP tokens.
|
|
3
|
-
These tests are specific to the ABC chain.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const chai = require('chai')
|
|
7
|
-
const assert = chai.assert
|
|
8
|
-
|
|
9
|
-
const BCHJS = require('../../../../src/bch-js')
|
|
10
|
-
let bchjs
|
|
11
|
-
|
|
12
|
-
// Inspect utility used for debugging.
|
|
13
|
-
const util = require('util')
|
|
14
|
-
util.inspect.defaultOptions = {
|
|
15
|
-
showHidden: true,
|
|
16
|
-
colors: true,
|
|
17
|
-
depth: 1
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
describe('#SLP', () => {
|
|
21
|
-
// before(() => {
|
|
22
|
-
// console.log(`bchjs.SLP.restURL: ${bchjs.SLP.restURL}`)
|
|
23
|
-
// console.log(`bchjs.SLP.apiToken: ${bchjs.SLP.apiToken}`)
|
|
24
|
-
// })
|
|
25
|
-
|
|
26
|
-
beforeEach(async () => {
|
|
27
|
-
// Introduce a delay so that the BVT doesn't trip the rate limits.
|
|
28
|
-
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
|
29
|
-
|
|
30
|
-
bchjs = new BCHJS({ restURL: process.env.RESTURL })
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
describe('#util', () => {
|
|
34
|
-
describe('#tokenUtxoDetails', () => {
|
|
35
|
-
it('should handle a range of UTXO types', async () => {
|
|
36
|
-
const utxos = [
|
|
37
|
-
// Malformed SLP tx
|
|
38
|
-
{
|
|
39
|
-
note: 'Malformed SLP tx',
|
|
40
|
-
tx_hash:
|
|
41
|
-
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
|
|
42
|
-
tx_pos: 1,
|
|
43
|
-
value: 546
|
|
44
|
-
},
|
|
45
|
-
// Normal TX (non-SLP)
|
|
46
|
-
{
|
|
47
|
-
note: 'Normal TX (non-SLP)',
|
|
48
|
-
tx_hash:
|
|
49
|
-
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
|
|
50
|
-
tx_pos: 0,
|
|
51
|
-
value: 400000
|
|
52
|
-
},
|
|
53
|
-
// Valid PSF SLP tx
|
|
54
|
-
{
|
|
55
|
-
note: 'Valid PSF SLP tx',
|
|
56
|
-
tx_hash:
|
|
57
|
-
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
|
|
58
|
-
tx_pos: 1,
|
|
59
|
-
value: 546
|
|
60
|
-
},
|
|
61
|
-
// Valid SLP token not in whitelist
|
|
62
|
-
{
|
|
63
|
-
note: 'Valid SLP token not in whitelist',
|
|
64
|
-
tx_hash:
|
|
65
|
-
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
|
|
66
|
-
tx_pos: 1,
|
|
67
|
-
value: 546
|
|
68
|
-
},
|
|
69
|
-
// Token send on BCHN network.
|
|
70
|
-
{
|
|
71
|
-
note: 'Token send on BCHN network',
|
|
72
|
-
tx_hash:
|
|
73
|
-
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019',
|
|
74
|
-
tx_pos: 1,
|
|
75
|
-
value: 546
|
|
76
|
-
},
|
|
77
|
-
// Token send on ABC network.
|
|
78
|
-
{
|
|
79
|
-
note: 'Token send on ABC network',
|
|
80
|
-
tx_hash:
|
|
81
|
-
'336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d',
|
|
82
|
-
tx_pos: 1,
|
|
83
|
-
value: 546
|
|
84
|
-
},
|
|
85
|
-
// Known invalid SLP token send of PSF tokens.
|
|
86
|
-
{
|
|
87
|
-
note: 'Known invalid SLP token send of PSF tokens',
|
|
88
|
-
tx_hash:
|
|
89
|
-
'2bf691ad3679d928fef880b8a45b93b233f8fa0d0a92cf792313dbe77b1deb74',
|
|
90
|
-
tx_pos: 1,
|
|
91
|
-
value: 546
|
|
92
|
-
}
|
|
93
|
-
]
|
|
94
|
-
|
|
95
|
-
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
|
96
|
-
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
97
|
-
|
|
98
|
-
// Malformed SLP tx
|
|
99
|
-
assert.equal(data[0].tx_hash, utxos[0].tx_hash)
|
|
100
|
-
assert.equal(data[0].isValid, false)
|
|
101
|
-
|
|
102
|
-
// Normal TX (non-SLP)
|
|
103
|
-
assert.equal(data[1].tx_hash, utxos[1].tx_hash)
|
|
104
|
-
assert.equal(data[1].isValid, false)
|
|
105
|
-
|
|
106
|
-
// Valid PSF SLP tx
|
|
107
|
-
assert.equal(data[2].tx_hash, utxos[2].tx_hash)
|
|
108
|
-
assert.equal(data[2].isValid, true)
|
|
109
|
-
|
|
110
|
-
// Valid SLP token not in whitelist
|
|
111
|
-
assert.equal(data[3].tx_hash, utxos[3].tx_hash)
|
|
112
|
-
assert.equal(data[3].isValid, true)
|
|
113
|
-
|
|
114
|
-
// Token send on BCHN network
|
|
115
|
-
assert.equal(data[4].tx_hash, utxos[4].tx_hash)
|
|
116
|
-
// assert.equal(data[4].isValid, true)
|
|
117
|
-
assert.equal(data[4].isValid, null)
|
|
118
|
-
|
|
119
|
-
// Token send on ABC network
|
|
120
|
-
assert.equal(data[5].tx_hash, utxos[5].tx_hash)
|
|
121
|
-
assert.equal(data[5].isValid, true)
|
|
122
|
-
|
|
123
|
-
// Known invalid SLP token send of PSF tokens
|
|
124
|
-
assert.equal(data[6].tx_hash, utxos[6].tx_hash)
|
|
125
|
-
assert.equal(data[6].isValid, false)
|
|
126
|
-
})
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
describe('#validateTxid3', () => {
|
|
130
|
-
it('should invalidate a known invalid TXID', async () => {
|
|
131
|
-
const txid =
|
|
132
|
-
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a'
|
|
133
|
-
|
|
134
|
-
const result = await bchjs.SLP.Utils.validateTxid3(txid)
|
|
135
|
-
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
136
|
-
|
|
137
|
-
assert.isArray(result)
|
|
138
|
-
|
|
139
|
-
assert.property(result[0], 'txid')
|
|
140
|
-
assert.equal(result[0].txid, txid)
|
|
141
|
-
|
|
142
|
-
assert.property(result[0], 'valid')
|
|
143
|
-
assert.equal(result[0].valid, null)
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
it('should validate a known valid TXID', async () => {
|
|
147
|
-
const txid =
|
|
148
|
-
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd'
|
|
149
|
-
|
|
150
|
-
const result = await bchjs.SLP.Utils.validateTxid3(txid)
|
|
151
|
-
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
152
|
-
|
|
153
|
-
assert.isArray(result)
|
|
154
|
-
|
|
155
|
-
assert.property(result[0], 'txid')
|
|
156
|
-
assert.equal(result[0].txid, txid)
|
|
157
|
-
|
|
158
|
-
assert.property(result[0], 'valid')
|
|
159
|
-
assert.equal(result[0].valid, true)
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
|
|
163
|
-
const txids = [
|
|
164
|
-
// Malformed SLP tx
|
|
165
|
-
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
|
|
166
|
-
// Normal TX (non-SLP)
|
|
167
|
-
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
|
|
168
|
-
// Valid PSF SLP tx
|
|
169
|
-
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
|
|
170
|
-
// Valid SLP token not in whitelist
|
|
171
|
-
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
|
|
172
|
-
// Unprocessed SLP TX
|
|
173
|
-
// "a0d6406eecfd8634158efa9314ff15b4cbf451938e9dc7b5678c46b41eabc6ed" // Mint baton
|
|
174
|
-
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019'
|
|
175
|
-
]
|
|
176
|
-
|
|
177
|
-
const result = await bchjs.SLP.Utils.validateTxid3(txids)
|
|
178
|
-
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
179
|
-
|
|
180
|
-
assert.isArray(result)
|
|
181
|
-
assert.equal(result[0].valid, null)
|
|
182
|
-
assert.equal(result[1].valid, null)
|
|
183
|
-
assert.equal(result[2].valid, true)
|
|
184
|
-
// assert.equal(result[2].valid, null)
|
|
185
|
-
assert.equal(result[3].valid, true)
|
|
186
|
-
assert.equal(result[4].valid, null)
|
|
187
|
-
})
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
describe('#validateTxid', () => {
|
|
191
|
-
it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
|
|
192
|
-
const txids = [
|
|
193
|
-
// Malformed SLP tx
|
|
194
|
-
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
|
|
195
|
-
// Normal TX (non-SLP)
|
|
196
|
-
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
|
|
197
|
-
// Valid PSF SLP tx
|
|
198
|
-
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
|
|
199
|
-
// Valid SLP token not in whitelist
|
|
200
|
-
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
|
|
201
|
-
// Token send on BCHN network.
|
|
202
|
-
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019',
|
|
203
|
-
// Token send on ABC network.
|
|
204
|
-
'336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d'
|
|
205
|
-
]
|
|
206
|
-
|
|
207
|
-
const result = await bchjs.SLP.Utils.validateTxid(txids)
|
|
208
|
-
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
209
|
-
|
|
210
|
-
assert.isArray(result)
|
|
211
|
-
assert.equal(result[0].valid, null)
|
|
212
|
-
assert.equal(result[1].valid, null)
|
|
213
|
-
assert.equal(result[2].valid, true)
|
|
214
|
-
// assert.equal(result[2].valid, null)
|
|
215
|
-
assert.equal(result[3].valid, true)
|
|
216
|
-
assert.equal(result[4].valid, null)
|
|
217
|
-
assert.equal(result[5].valid, true)
|
|
218
|
-
})
|
|
219
|
-
})
|
|
220
|
-
})
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
// Promise-based sleep function
|
|
224
|
-
function sleep (ms) {
|
|
225
|
-
return new Promise(resolve => setTimeout(resolve, ms))
|
|
226
|
-
}
|