@psf/bch-js 5.2.2 → 5.3.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@psf/bch-js",
3
- "version": "5.2.2",
3
+ "version": "5.3.2",
4
4
  "description": "The FullStack.cash JavaScript library for Bitcoin Cash and SLP Tokens",
5
5
  "author": "Chris Troutner <chris.troutner@gmail.com>",
6
6
  "contributors": [
@@ -18,7 +18,7 @@
18
18
  "test:integration:local:abc": "export RESTURL=http://localhost:3000/v5/ && mocha --timeout 30000 test/integration && mocha --timeout 30000 test/integration/chains/abc/",
19
19
  "test:integration:local:bchn": "export RESTURL=http://localhost:3000/v5/ && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/bchn/",
20
20
  "test:integration:local:testnet": "RESTURL=http://localhost:4000/v5/ mocha --timeout 30000 test/integration/chains/testnet",
21
- "test:integration:decatur:bchn": "export RESTURL=http://192.168.2.139:3000/v5/ && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/bchn/",
21
+ "test:integration:decatur:bchn": "export RESTURL=http://192.168.2.129:3000/v5/ && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/bchn/",
22
22
  "test:integration:decatur:abc": "export RESTURL=http://192.168.2.141:3000/v5/ && mocha --timeout 30000 test/integration && mocha --timeout 30000 test/integration/chains/abc/",
23
23
  "test:integration:temp:bchn": "export RESTURL=http://157.90.174.219:3000/v5/ && mocha --timeout 30000 test/integration/",
24
24
  "test:temp": "export RESTURL=http://localhost:3000/v5/ && mocha --timeout 30000 -g '#Encryption' test/integration/",
package/src/electrumx.js CHANGED
@@ -638,13 +638,24 @@ class ElectrumX {
638
638
  // Sort confirmed Transactions by the block height
639
639
  sortConfTxs (txs, sortingOrder = 'DESCENDING') {
640
640
  try {
641
+ // console.log(`sortConfTxs txs: ${JSON.stringify(txs, null, 2)}`)
642
+
641
643
  // Filter out unconfirmed transactions, with a height of 0 or less.
642
644
  txs = txs.filter(elem => elem.height > 0)
643
645
 
644
646
  if (sortingOrder === 'DESCENDING') {
645
- return txs.sort((a, b) => b.height - a.height)
647
+ // console.log('Sorting in descending order')
648
+ return txs.sort((a, b) => {
649
+ // console.log(`descending b.height: ${b.height}, a.height: ${a.height}`)
650
+ return b.height - a.height
651
+ })
646
652
  }
647
- return txs.sort((a, b) => a.height - b.height)
653
+
654
+ // console.log('Sorting in ascending order')
655
+ return txs.sort((a, b) => {
656
+ // console.log(`ascending b.height: ${b.height}, a.height: ${a.height}`)
657
+ return a.height - b.height
658
+ })
648
659
  } catch (err) {
649
660
  console.log('Error in util.js/sortConfTxs()')
650
661
  throw err
@@ -685,6 +696,8 @@ class ElectrumX {
685
696
  // Substitute zero-conf txs with the current block-height + 1
686
697
  async sortAllTxs (txs, sortingOrder = 'DESCENDING') {
687
698
  try {
699
+ // console.log(`sortingOrder: ${sortingOrder}`)
700
+
688
701
  // Calculate the height of the next block
689
702
  const nextBlock = (await this.blockchain.getBlockCount()) + 1
690
703
 
@@ -155,11 +155,13 @@ class PsfSlpIndexer {
155
155
  * @apiName Token Stats
156
156
  * @apiGroup PSF SLP
157
157
  * @apiDescription Return list stats for a single slp token.
158
+ * The second input is a Boolean, which determins the the transaction history
159
+ * of the token is included in the returned data. The default is false.
158
160
  *
159
161
  * @apiExample Example usage:
160
162
  * (async () => {
161
163
  * try {
162
- * let tokenStats = await bchjs.PsfSlpIndexer.tokenStats('a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2');
164
+ * let tokenStats = await bchjs.PsfSlpIndexer.tokenStats('a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', true);
163
165
  * console.log(tokenStats);
164
166
  * } catch(error) {
165
167
  * console.error(error)
@@ -194,13 +196,13 @@ class PsfSlpIndexer {
194
196
  *
195
197
  */
196
198
 
197
- async tokenStats (tokenId) {
199
+ async tokenStats (tokenId, withTxHistory = false) {
198
200
  try {
199
201
  // Handle single address.
200
202
  if (typeof tokenId === 'string') {
201
203
  const response = await axios.post(
202
204
  `${this.restURL}psf/slp/token`,
203
- { tokenId },
205
+ { tokenId, withTxHistory },
204
206
  this.axiosOptions
205
207
  )
206
208
  return response.data
package/src/util.js CHANGED
@@ -150,6 +150,56 @@ class Util {
150
150
  }
151
151
  }
152
152
 
153
+ /**
154
+ * @api Util.chunk100() chunk100()
155
+ * @apiName chunk100
156
+ * @apiGroup Util
157
+ * @apiDescription chunk up an array into multiple arrays of 100 elements each.
158
+ * Input: arrayToSlice - a one-dimensional array of elements.
159
+ * Returns a two-dimensional array. An array of 100-element arrays.
160
+ *
161
+ * @apiExample Example usage:
162
+ * (async () => {
163
+ * try {
164
+ * const bigArray = [0,1,2,3,4,5,6,7,8,9,10,...,148, 149, 150]
165
+ *
166
+ * const chunked = bchjs.Util.chunk20(bigArray)
167
+ * console.log(chunked)
168
+ * } catch(error) {
169
+ * console.error(error)
170
+ * }
171
+ * })()
172
+ *
173
+ * // returns
174
+ * [
175
+ * [0,1,2,3,4,5,6,7,8,9,10,11,...,98,99],
176
+ * [100,101,102,...,148,149,150]
177
+ * ]
178
+ */
179
+ chunk100 (arrayToSlice) {
180
+ try {
181
+ // Validate inputs
182
+ if (!Array.isArray(arrayToSlice)) {
183
+ throw new Error('input must be an array')
184
+ }
185
+
186
+ let offset = 0
187
+ const result = []
188
+
189
+ // Loop over the array and slice off chunks of 100 elements.
190
+ while (offset < arrayToSlice.length) {
191
+ const chunk = arrayToSlice.slice(offset, offset + 100)
192
+ result.push(chunk)
193
+ offset = offset + 100
194
+ }
195
+
196
+ return result
197
+ } catch (err) {
198
+ console.error('Error in chunk100()')
199
+ throw err
200
+ }
201
+ }
202
+
153
203
  /**
154
204
  * @api Util.sleep() sleep()
155
205
  * @apiName sleep
package/src/utxo.js CHANGED
@@ -404,8 +404,18 @@ class UTXO {
404
404
  if (!thisUtxo.isSlp) {
405
405
  thisUtxo.txid = thisUtxo.tx_hash
406
406
  thisUtxo.vout = thisUtxo.tx_pos
407
- thisUtxo.isSlp = false
408
407
  thisUtxo.address = addr
408
+
409
+ // Check the transaction to see if its a 'null' token, ignored by
410
+ // the indexer.
411
+ const txData = await this.psfSlpIndexer.tx(thisUtxo.tx_hash)
412
+ // console.log(`txData: ${JSON.stringify(txData, null, 2)}`)
413
+ if (txData.txData.isValidSlp === null) {
414
+ thisUtxo.isSlp = null
415
+ } else {
416
+ thisUtxo.isSlp = false
417
+ }
418
+ // console.log(`thisUtxo.isSlp: ${thisUtxo.isSlp}`)
409
419
  }
410
420
  }
411
421
 
@@ -438,7 +448,7 @@ class UTXO {
438
448
 
439
449
  return outObj
440
450
  } catch (err) {
441
- // console.error('Error in bchjs.utxo.get2(): ', err)
451
+ console.error('Error in bchjs.Utxo.get(): ', err)
442
452
 
443
453
  if (err.error) throw new Error(err.error)
444
454
  throw err
@@ -2,10 +2,10 @@
2
2
  Integration tests for the utxo.js library.
3
3
  */
4
4
 
5
- const assert = require('chai').assert
5
+ // const assert = require('chai').assert
6
6
 
7
- const BCHJS = require('../../../../src/bch-js')
8
- const bchjs = new BCHJS()
7
+ // const BCHJS = require('../../../../src/bch-js')
8
+ // const bchjs = new BCHJS()
9
9
 
10
10
  describe('#UTXO', () => {
11
11
  beforeEach(async () => {
@@ -14,6 +14,7 @@ describe('#UTXO', () => {
14
14
  if (process.env.IS_USING_FREE_TIER) await sleep(1500)
15
15
  })
16
16
 
17
+ /*
17
18
  describe('#get', () => {
18
19
  it('should get hydrated and filtered UTXOs for an address', async () => {
19
20
  // const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
@@ -31,6 +32,7 @@ describe('#UTXO', () => {
31
32
  assert.isArray(result[0].nullUtxos)
32
33
  })
33
34
  })
35
+ */
34
36
  })
35
37
 
36
38
  function sleep (ms) {
@@ -40,13 +40,24 @@ describe('#psf-slp-indexer', () => {
40
40
  })
41
41
 
42
42
  describe('#tokenStats', () => {
43
- it('should get stats on a token', async () => {
43
+ it('should get stats on a token, without tx history', async () => {
44
44
  const tokenId =
45
45
  '38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0'
46
46
 
47
47
  const result = await bchjs.PsfSlpIndexer.tokenStats(tokenId)
48
48
  // console.log('result: ', result)
49
49
 
50
+ assert.property(result.tokenData, 'documentUri')
51
+ assert.property(result.tokenData, 'totalBurned')
52
+ })
53
+
54
+ it('should get stats on a token, with tx history', async () => {
55
+ const tokenId =
56
+ '38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0'
57
+
58
+ const result = await bchjs.PsfSlpIndexer.tokenStats(tokenId, true)
59
+ // console.log('result: ', result)
60
+
50
61
  assert.property(result.tokenData, 'documentUri')
51
62
  assert.property(result.tokenData, 'txs')
52
63
  assert.property(result.tokenData, 'totalBurned')
@@ -0,0 +1,28 @@
1
+ /*
2
+ Integration tests for the transaction.js library.
3
+ */
4
+
5
+ const assert = require('chai').assert
6
+ const BCHJS = require('../../../../src/bch-js')
7
+ const bchjs = new BCHJS()
8
+
9
+ describe('#Transaction', () => {
10
+ beforeEach(async () => {
11
+ if (process.env.IS_USING_FREE_TIER) await bchjs.Util.sleep(1000)
12
+ })
13
+
14
+ describe('#get', () => {
15
+ it('should get a tx details for a non-SLP TX with an OP_RETURN', async () => {
16
+ const txid =
17
+ '01517ff1587fa5ffe6f5eb91c99cf3f2d22330cd7ee847e928ce90ca95bf781b'
18
+
19
+ const result = await bchjs.Transaction.get(txid)
20
+ // console.log('result: ', result)
21
+
22
+ assert.property(result.txData, 'txid')
23
+ assert.property(result.txData, 'vin')
24
+ assert.property(result.txData, 'vout')
25
+ assert.equal(result.txData.isValidSlp, false)
26
+ })
27
+ })
28
+ })
@@ -6,6 +6,7 @@ const assert = require('chai').assert
6
6
 
7
7
  const BCHJS = require('../../../../src/bch-js')
8
8
  const bchjs = new BCHJS()
9
+ // const bchjs = new BCHJS({ restURL: 'http://192.168.2.129:3000/v5/' })
9
10
 
10
11
  describe('#UTXO', () => {
11
12
  beforeEach(async () => {
@@ -199,7 +200,7 @@ describe('#UTXO', () => {
199
200
 
200
201
  // TODO: NFTs are currently not identified as different than normal BCH UTXOs.
201
202
  // The psf-slp-indexer needs to be updated to fix this issue.
202
- it('should handle NFTs and minting batons', async () => {
203
+ it('should handle minting batons', async () => {
203
204
  const addr = 'simpleledger:qrm0c67wwqh0w7wjxua2gdt2xggnm90xwsr5k22euj'
204
205
 
205
206
  const result = await bchjs.Utxo.get(addr)
@@ -218,6 +219,15 @@ describe('#UTXO', () => {
218
219
  assert.isAbove(result.bchUtxos.length, 0)
219
220
  assert.equal(result.slpUtxos.type1.tokens.length, 0)
220
221
  })
222
+
223
+ it('should handle Group NFTs', async () => {
224
+ const addr = 'bitcoincash:qrnghwrfgccf3s5e9wnglzxegcnhje9rkcwv2eka33'
225
+
226
+ const result = await bchjs.Utxo.get(addr)
227
+ // console.log(`result: ${JSON.stringify(result, null, 2)}`)
228
+
229
+ assert.isAbove(result.nullUtxos.length, 0)
230
+ })
221
231
  })
222
232
  })
223
233
 
@@ -249,6 +249,10 @@ describe('#utxo', () => {
249
249
  sandbox
250
250
  .stub(bchjs.Utxo.psfSlpIndexer, 'balance')
251
251
  .resolves(mockData.psfSlpIndexerUtxos01)
252
+ sandbox
253
+ .stub(bchjs.Utxo.psfSlpIndexer, 'tx')
254
+ .resolves({ txData: { isValidSlp: false } })
255
+
252
256
  // Mock function to return the same input. Good enough for this test.
253
257
  sandbox.stub(bchjs.Utxo, 'hydrateTokenData').resolves(x => x)
254
258
 
@@ -278,6 +282,9 @@ describe('#utxo', () => {
278
282
  sandbox
279
283
  .stub(bchjs.Utxo.electrumx, 'utxo')
280
284
  .resolves(mockData.fulcrumUtxos02)
285
+ sandbox
286
+ .stub(bchjs.Utxo.psfSlpIndexer, 'tx')
287
+ .resolves({ txData: { isValidSlp: false } })
281
288
 
282
289
  // Force psf-slp-indexer to return no UTXOs
283
290
  sandbox