@psf/bch-js 6.3.4 → 6.4.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": "6.3.4",
3
+ "version": "6.4.2",
4
4
  "description": "A JavaScript library for working with Bitcoin Cash, eCash, and SLP Tokens",
5
5
  "author": "Chris Troutner <chris.troutner@gmail.com>",
6
6
  "contributors": [
package/src/address.js CHANGED
@@ -133,7 +133,7 @@ class Address {
133
133
  * @api Address.toEcashAddress() toEcashAddress()
134
134
  * @apiName toEcashAddress
135
135
  * @apiGroup Address
136
- * @apiDescription Convert legacy to cashAddress format
136
+ * @apiDescription Convert legacy to eCash (XEC) format
137
137
  *
138
138
  * @apiExample Example usage:
139
139
  * // mainnet
@@ -158,6 +158,35 @@ class Address {
158
158
  return ecashAddress.split(':')[1]
159
159
  }
160
160
 
161
+ /**
162
+ * @api Address.toEtokenAddress() toEtokenAddress()
163
+ * @apiName toEtokenAddress
164
+ * @apiGroup Address
165
+ * @apiDescription Convert legacy to eToken (XEC) format
166
+ *
167
+ * @apiExample Example usage:
168
+ * // mainnet
169
+ * bchjs.Address.toEcashAddress('bitcoincash:qq50d800hgunr8u4trz3uuppspk3mds0dy9978plt2')
170
+ * // ecash:qq50d800hgunr8u4trz3uuppspk3mds0dyug2v69da
171
+ *
172
+ * // mainnet no prefix
173
+ * bchjs.Address.toEcashAddress('bitcoincash:qq50d800hgunr8u4trz3uuppspk3mds0dy9978plt2', false)
174
+ * // qq50d800hgunr8u4trz3uuppspk3mds0dyug2v69da
175
+ *
176
+ */
177
+ toEtokenAddress (address, prefix = true) {
178
+ const decoded = this._decode(address)
179
+
180
+ const etokenAddress = cashaddr.encode(
181
+ 'etoken',
182
+ decoded.type,
183
+ decoded.hash
184
+ )
185
+
186
+ if (prefix) return etokenAddress
187
+ return etokenAddress.split(':')[1]
188
+ }
189
+
161
190
  /**
162
191
  * @api Address.ecashtoCashAddress() ecashtoCashAddress()
163
192
  * @apiName ecashtoCashAddress
package/src/utxo.js CHANGED
@@ -10,6 +10,7 @@ const Electrumx = require('./electrumx')
10
10
  const Slp = require('./slp/slp')
11
11
  const PsfSlpIndexer = require('./psf-slp-indexer')
12
12
  const BigNumber = require('bignumber.js')
13
+ const Blockchain = require('./blockchain')
13
14
 
14
15
  class UTXO {
15
16
  constructor (config = {}) {
@@ -18,6 +19,7 @@ class UTXO {
18
19
  this.slp = new Slp(config)
19
20
  this.psfSlpIndexer = new PsfSlpIndexer(config)
20
21
  this.BigNumber = BigNumber
22
+ this.blockchain = new Blockchain(config)
21
23
  }
22
24
 
23
25
  /**
@@ -207,7 +209,7 @@ class UTXO {
207
209
 
208
210
  return outObj
209
211
  } catch (err) {
210
- console.error('Error in bchjs.Utxo.get(): ', err)
212
+ console.error('Error in bchjs.Utxo.get()')
211
213
 
212
214
  if (err.error) throw new Error(err.error)
213
215
  throw err
@@ -336,6 +338,57 @@ class UTXO {
336
338
 
337
339
  return utxos[largestIndex]
338
340
  }
341
+
342
+ /**
343
+ * @api Utxo.isValid() isValid()
344
+ * @apiName isValid
345
+ * @apiGroup UTXO
346
+ * @apiDescription Validate that UTXO exists and is still spendable.
347
+ *
348
+ * Given a UTXO, this method will return true if the UTXO is still in the
349
+ * mempool and still valid for spending. It will return false if the UTXO
350
+ * has been spent.
351
+ *
352
+ * @apiExample Example usage:
353
+ * (async () => {
354
+ * try {
355
+ * const utxos = await bchjs.Utxo.get('bitcoincash:qq54fgjn3hz0357n8a6guy4demw9xfkjk5jcj0xr0z');
356
+ * const isValid = bchjs.Utxo.isValid(utxos.bchUtxos[0])
357
+ * console.log(isValid);
358
+ * } catch(error) {
359
+ * console.error(error)
360
+ * }
361
+ * })()
362
+ *
363
+ * // returns
364
+ * true
365
+ */
366
+ async isValid (utxo) {
367
+ try {
368
+ // console.log('utxo: ', utxo)
369
+
370
+ // Convert different properties from different indexers
371
+ const txid = utxo.txid || utxo.tx_hash
372
+ const vout = utxo.vout | utxo.tx_pos
373
+
374
+ // Query the full node
375
+ const txOut = await this.blockchain.getTxOut(txid, vout, true)
376
+ // console.log('txOut: ', txOut)
377
+
378
+ // Simplify results to either true or false.
379
+ let isValid = null
380
+ if (txOut === null) {
381
+ isValid = false
382
+ } else {
383
+ isValid = true
384
+ }
385
+
386
+ return isValid
387
+ } catch (err) {
388
+ console.log('Error in Utxo.isValid()')
389
+ throw err
390
+ }
391
+ }
339
392
  }
340
393
 
341
394
  module.exports = UTXO
@@ -128,7 +128,7 @@ describe('#psf-slp-indexer', () => {
128
128
  describe('#getTokenData', () => {
129
129
  it('should get token data', async () => {
130
130
  const tokenId =
131
- 'f055256b938f1ecfa270459d6f12c7c8c82b66d3263c03d5074445a2b1a498a3'
131
+ 'd9aafa7acb514c597caf440ae268b5e4e955f2687e05f044cdf8fd9550d9a27b'
132
132
 
133
133
  // bchjs.PsfSlpIndexer.restURL = 'http://localhost:3000/v5/'
134
134
  const result = await bchjs.PsfSlpIndexer.getTokenData(tokenId)
@@ -122,6 +122,65 @@ describe('#UTXO', () => {
122
122
  assert.isAbove(result.slpUtxos.nft.tokens.length, 0)
123
123
  })
124
124
  })
125
+
126
+ describe('#isValid', () => {
127
+ it('should return true for valid UTXO with fullnode properties', async () => {
128
+ const utxo = {
129
+ txid: 'b94e1ff82eb5781f98296f0af2488ff06202f12ee92b0175963b8dba688d1b40',
130
+ vout: 0
131
+ }
132
+
133
+ const result = await bchjs.Utxo.isValid(utxo)
134
+ // console.log('result: ', result)
135
+
136
+ assert.equal(result, true)
137
+ })
138
+
139
+ it('should return true for valid UTXO with fulcrum properties', async () => {
140
+ const utxo = {
141
+ tx_hash: 'b94e1ff82eb5781f98296f0af2488ff06202f12ee92b0175963b8dba688d1b40',
142
+ tx_pos: 0
143
+ }
144
+
145
+ const result = await bchjs.Utxo.isValid(utxo)
146
+ // console.log('result: ', result)
147
+
148
+ assert.equal(result, true)
149
+ })
150
+
151
+ it('should return true for valid UTXO with fullnode properties', async () => {
152
+ const utxo = {
153
+ txid: '17754221b29f189532d4fc2ae89fb467ad2dede30fdec4854eb2129b3ba90d7a',
154
+ vout: 0
155
+ }
156
+
157
+ const result = await bchjs.Utxo.isValid(utxo)
158
+ // console.log('result: ', result)
159
+
160
+ assert.equal(result, false)
161
+ })
162
+
163
+ it('should return true for valid UTXO with fulcrum properties', async () => {
164
+ const utxo = {
165
+ tx_hash: '17754221b29f189532d4fc2ae89fb467ad2dede30fdec4854eb2129b3ba90d7a',
166
+ tx_pos: 0
167
+ }
168
+
169
+ const result = await bchjs.Utxo.isValid(utxo)
170
+ // console.log('result: ', result
171
+
172
+ assert.equal(result, false)
173
+ })
174
+
175
+ it('should process output of Utxo.get()', async () => {
176
+ const utxo = await bchjs.Utxo.get('bitcoincash:qr4yscpw9jgq8ltajfeknpj32kamkf9knujffcdhyq')
177
+ // console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`)
178
+
179
+ const result = await bchjs.Utxo.isValid(utxo.bchUtxos[0])
180
+
181
+ assert.equal(result, true)
182
+ })
183
+ })
125
184
  })
126
185
 
127
186
  function sleep (ms) {
@@ -935,4 +935,44 @@ describe('#address.js', () => {
935
935
  })
936
936
  })
937
937
  })
938
+
939
+ describe('#toEcashAddress', () => {
940
+ it('should convert a BCH address to an eCash address', () => {
941
+ const cashAddr = 'bitcoincash:qr24z7q6s26d9wr078lr2pxsmxg22cyn9s7yw984vk'
942
+
943
+ const result = bchjs.Address.toEcashAddress(cashAddr)
944
+ // console.log('result: ', result)
945
+
946
+ assert.equal(result, 'ecash:qr24z7q6s26d9wr078lr2pxsmxg22cyn9s8f6wu02p')
947
+ })
948
+
949
+ it('should convert a BCH address to an eCash address without a prefix', () => {
950
+ const cashAddr = 'bitcoincash:qr24z7q6s26d9wr078lr2pxsmxg22cyn9s7yw984vk'
951
+
952
+ const result = bchjs.Address.toEcashAddress(cashAddr, false)
953
+ // console.log('result: ', result)
954
+
955
+ assert.equal(result, 'qr24z7q6s26d9wr078lr2pxsmxg22cyn9s8f6wu02p')
956
+ })
957
+ })
958
+
959
+ describe('#toEtokenAddress', () => {
960
+ it('should convert a BCH address to an eToken address', () => {
961
+ const cashAddr = 'bitcoincash:qr24z7q6s26d9wr078lr2pxsmxg22cyn9s7yw984vk'
962
+
963
+ const result = bchjs.Address.toEtokenAddress(cashAddr)
964
+ // console.log('result: ', result)
965
+
966
+ assert.equal(result, 'etoken:qr24z7q6s26d9wr078lr2pxsmxg22cyn9sfhnv2gwk')
967
+ })
968
+
969
+ it('should convert a BCH address to an eToken address without a prefix', () => {
970
+ const cashAddr = 'bitcoincash:qr24z7q6s26d9wr078lr2pxsmxg22cyn9s7yw984vk'
971
+
972
+ const result = bchjs.Address.toEtokenAddress(cashAddr, false)
973
+ // console.log('result: ', result)
974
+
975
+ assert.equal(result, 'qr24z7q6s26d9wr078lr2pxsmxg22cyn9sfhnv2gwk')
976
+ })
977
+ })
938
978
  })
@@ -174,4 +174,36 @@ describe('#utxo', () => {
174
174
  assert.equal(result.nullUtxos.length, 0)
175
175
  })
176
176
  })
177
+
178
+ describe('#isValid', () => {
179
+ it('should return false if getTxOut() returns null', async () => {
180
+ // Mock dependencies
181
+ sandbox.stub(bchjs.Utxo.blockchain, 'getTxOut').resolves(null)
182
+
183
+ const utxo = {
184
+ tx_hash: '17754221b29f189532d4fc2ae89fb467ad2dede30fdec4854eb2129b3ba90d7a',
185
+ tx_pos: 0
186
+ }
187
+
188
+ const result = await bchjs.Utxo.isValid(utxo)
189
+ // console.log('result: ', result
190
+
191
+ assert.equal(result, false)
192
+ })
193
+
194
+ it('should return true if getTxOut() returns non-null output', async () => {
195
+ // Mock dependencies
196
+ sandbox.stub(bchjs.Utxo.blockchain, 'getTxOut').resolves({ a: 'b' })
197
+
198
+ const utxo = {
199
+ tx_hash: 'b94e1ff82eb5781f98296f0af2488ff06202f12ee92b0175963b8dba688d1b40',
200
+ tx_pos: 0
201
+ }
202
+
203
+ const result = await bchjs.Utxo.isValid(utxo)
204
+ // console.log('result: ', result
205
+
206
+ assert.equal(result, true)
207
+ })
208
+ })
177
209
  })