Compare commits

..
6 Commits
Author SHA1 Message Date
Chris Troutner 372d1b099d Merge pull request #244 from Permissionless-Software-Foundation/ct-unstable
fix(address): Adding toEtokenAddress() function
2022-07-10 09:50:44 -07:00
Chris Troutner dbfaf9c4ab fix(address): Adding toEtokenAddress() function 2022-07-10 09:47:49 -07:00
Chris Troutner eaa08f74e7 Merge pull request #243 from Permissionless-Software-Foundation/ct-unstable
fix(test): Updating integration test
2022-05-15 07:53:53 -07:00
Chris Troutner 9ac620ee64 fix(test): Updating integration test 2022-05-15 07:50:57 -07:00
Chris Troutner ac0a4b0407 Merge pull request #242 from Permissionless-Software-Foundation/ct-unstable
feat(Utxo.isValid()): can test if a UTXO has been spent
2022-05-10 09:34:37 -07:00
Chris Troutner 686012037f feat(Utxo.isValid()): can test if a UTXO has been spent 2022-05-10 09:30:57 -07:00
6 changed files with 216 additions and 3 deletions
+30 -1
View File
@@ -133,7 +133,7 @@ class Address {
* @api Address.toEcashAddress() toEcashAddress()
* @apiName toEcashAddress
* @apiGroup Address
* @apiDescription Convert legacy to cashAddress format
* @apiDescription Convert legacy to eCash (XEC) format
*
* @apiExample Example usage:
* // mainnet
@@ -158,6 +158,35 @@ class Address {
return ecashAddress.split(':')[1]
}
/**
* @api Address.toEtokenAddress() toEtokenAddress()
* @apiName toEtokenAddress
* @apiGroup Address
* @apiDescription Convert legacy to eToken (XEC) format
*
* @apiExample Example usage:
* // mainnet
* bchjs.Address.toEcashAddress('bitcoincash:qq50d800hgunr8u4trz3uuppspk3mds0dy9978plt2')
* // ecash:qq50d800hgunr8u4trz3uuppspk3mds0dyug2v69da
*
* // mainnet no prefix
* bchjs.Address.toEcashAddress('bitcoincash:qq50d800hgunr8u4trz3uuppspk3mds0dy9978plt2', false)
* // qq50d800hgunr8u4trz3uuppspk3mds0dyug2v69da
*
*/
toEtokenAddress (address, prefix = true) {
const decoded = this._decode(address)
const etokenAddress = cashaddr.encode(
'etoken',
decoded.type,
decoded.hash
)
if (prefix) return etokenAddress
return etokenAddress.split(':')[1]
}
/**
* @api Address.ecashtoCashAddress() ecashtoCashAddress()
* @apiName ecashtoCashAddress
+54 -1
View File
@@ -10,6 +10,7 @@ const Electrumx = require('./electrumx')
const Slp = require('./slp/slp')
const PsfSlpIndexer = require('./psf-slp-indexer')
const BigNumber = require('bignumber.js')
const Blockchain = require('./blockchain')
class UTXO {
constructor (config = {}) {
@@ -18,6 +19,7 @@ class UTXO {
this.slp = new Slp(config)
this.psfSlpIndexer = new PsfSlpIndexer(config)
this.BigNumber = BigNumber
this.blockchain = new Blockchain(config)
}
/**
@@ -207,7 +209,7 @@ class UTXO {
return outObj
} catch (err) {
console.error('Error in bchjs.Utxo.get(): ', err)
console.error('Error in bchjs.Utxo.get()')
if (err.error) throw new Error(err.error)
throw err
@@ -336,6 +338,57 @@ class UTXO {
return utxos[largestIndex]
}
/**
* @api Utxo.isValid() isValid()
* @apiName isValid
* @apiGroup UTXO
* @apiDescription Validate that UTXO exists and is still spendable.
*
* Given a UTXO, this method will return true if the UTXO is still in the
* mempool and still valid for spending. It will return false if the UTXO
* has been spent.
*
* @apiExample Example usage:
* (async () => {
* try {
* const utxos = await bchjs.Utxo.get('bitcoincash:qq54fgjn3hz0357n8a6guy4demw9xfkjk5jcj0xr0z');
* const isValid = bchjs.Utxo.isValid(utxos.bchUtxos[0])
* console.log(isValid);
* } catch(error) {
* console.error(error)
* }
* })()
*
* // returns
* true
*/
async isValid (utxo) {
try {
// console.log('utxo: ', utxo)
// Convert different properties from different indexers
const txid = utxo.txid || utxo.tx_hash
const vout = utxo.vout | utxo.tx_pos
// Query the full node
const txOut = await this.blockchain.getTxOut(txid, vout, true)
// console.log('txOut: ', txOut)
// Simplify results to either true or false.
let isValid = null
if (txOut === null) {
isValid = false
} else {
isValid = true
}
return isValid
} catch (err) {
console.log('Error in Utxo.isValid()')
throw err
}
}
}
module.exports = UTXO
@@ -128,7 +128,7 @@ describe('#psf-slp-indexer', () => {
describe('#getTokenData', () => {
it('should get token data', async () => {
const tokenId =
'f055256b938f1ecfa270459d6f12c7c8c82b66d3263c03d5074445a2b1a498a3'
'd9aafa7acb514c597caf440ae268b5e4e955f2687e05f044cdf8fd9550d9a27b'
// bchjs.PsfSlpIndexer.restURL = 'http://localhost:3000/v5/'
const result = await bchjs.PsfSlpIndexer.getTokenData(tokenId)
@@ -122,6 +122,65 @@ describe('#UTXO', () => {
assert.isAbove(result.slpUtxos.nft.tokens.length, 0)
})
})
describe('#isValid', () => {
it('should return true for valid UTXO with fullnode properties', async () => {
const utxo = {
txid: 'b94e1ff82eb5781f98296f0af2488ff06202f12ee92b0175963b8dba688d1b40',
vout: 0
}
const result = await bchjs.Utxo.isValid(utxo)
// console.log('result: ', result)
assert.equal(result, true)
})
it('should return true for valid UTXO with fulcrum properties', async () => {
const utxo = {
tx_hash: 'b94e1ff82eb5781f98296f0af2488ff06202f12ee92b0175963b8dba688d1b40',
tx_pos: 0
}
const result = await bchjs.Utxo.isValid(utxo)
// console.log('result: ', result)
assert.equal(result, true)
})
it('should return true for valid UTXO with fullnode properties', async () => {
const utxo = {
txid: '17754221b29f189532d4fc2ae89fb467ad2dede30fdec4854eb2129b3ba90d7a',
vout: 0
}
const result = await bchjs.Utxo.isValid(utxo)
// console.log('result: ', result)
assert.equal(result, false)
})
it('should return true for valid UTXO with fulcrum properties', async () => {
const utxo = {
tx_hash: '17754221b29f189532d4fc2ae89fb467ad2dede30fdec4854eb2129b3ba90d7a',
tx_pos: 0
}
const result = await bchjs.Utxo.isValid(utxo)
// console.log('result: ', result
assert.equal(result, false)
})
it('should process output of Utxo.get()', async () => {
const utxo = await bchjs.Utxo.get('bitcoincash:qr4yscpw9jgq8ltajfeknpj32kamkf9knujffcdhyq')
// console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`)
const result = await bchjs.Utxo.isValid(utxo.bchUtxos[0])
assert.equal(result, true)
})
})
})
function sleep (ms) {
+40
View File
@@ -935,4 +935,44 @@ describe('#address.js', () => {
})
})
})
describe('#toEcashAddress', () => {
it('should convert a BCH address to an eCash address', () => {
const cashAddr = 'bitcoincash:qr24z7q6s26d9wr078lr2pxsmxg22cyn9s7yw984vk'
const result = bchjs.Address.toEcashAddress(cashAddr)
// console.log('result: ', result)
assert.equal(result, 'ecash:qr24z7q6s26d9wr078lr2pxsmxg22cyn9s8f6wu02p')
})
it('should convert a BCH address to an eCash address without a prefix', () => {
const cashAddr = 'bitcoincash:qr24z7q6s26d9wr078lr2pxsmxg22cyn9s7yw984vk'
const result = bchjs.Address.toEcashAddress(cashAddr, false)
// console.log('result: ', result)
assert.equal(result, 'qr24z7q6s26d9wr078lr2pxsmxg22cyn9s8f6wu02p')
})
})
describe('#toEtokenAddress', () => {
it('should convert a BCH address to an eToken address', () => {
const cashAddr = 'bitcoincash:qr24z7q6s26d9wr078lr2pxsmxg22cyn9s7yw984vk'
const result = bchjs.Address.toEtokenAddress(cashAddr)
// console.log('result: ', result)
assert.equal(result, 'etoken:qr24z7q6s26d9wr078lr2pxsmxg22cyn9sfhnv2gwk')
})
it('should convert a BCH address to an eToken address without a prefix', () => {
const cashAddr = 'bitcoincash:qr24z7q6s26d9wr078lr2pxsmxg22cyn9s7yw984vk'
const result = bchjs.Address.toEtokenAddress(cashAddr, false)
// console.log('result: ', result)
assert.equal(result, 'qr24z7q6s26d9wr078lr2pxsmxg22cyn9sfhnv2gwk')
})
})
})
+32
View File
@@ -174,4 +174,36 @@ describe('#utxo', () => {
assert.equal(result.nullUtxos.length, 0)
})
})
describe('#isValid', () => {
it('should return false if getTxOut() returns null', async () => {
// Mock dependencies
sandbox.stub(bchjs.Utxo.blockchain, 'getTxOut').resolves(null)
const utxo = {
tx_hash: '17754221b29f189532d4fc2ae89fb467ad2dede30fdec4854eb2129b3ba90d7a',
tx_pos: 0
}
const result = await bchjs.Utxo.isValid(utxo)
// console.log('result: ', result
assert.equal(result, false)
})
it('should return true if getTxOut() returns non-null output', async () => {
// Mock dependencies
sandbox.stub(bchjs.Utxo.blockchain, 'getTxOut').resolves({ a: 'b' })
const utxo = {
tx_hash: 'b94e1ff82eb5781f98296f0af2488ff06202f12ee92b0175963b8dba688d1b40',
tx_pos: 0
}
const result = await bchjs.Utxo.isValid(utxo)
// console.log('result: ', result
assert.equal(result, true)
})
})
})