mirror of
https://github.com/Permissionless-Software-Foundation/bch-js.git
synced 2026-09-22 09:02:01 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78776bee93 | ||
|
|
a6e3155f37 | ||
|
|
47f60bccde | ||
|
|
d0a3b27682 | ||
|
|
372d1b099d | ||
|
|
dbfaf9c4ab | ||
|
|
eaa08f74e7 | ||
|
|
9ac620ee64 | ||
|
|
ac0a4b0407 | ||
|
|
686012037f | ||
|
|
cfb7b9f779 | ||
|
|
06e5af4b5d |
Generated
+863
-2081
File diff suppressed because it is too large
Load Diff
+30
-1
@@ -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.toEtokenAddress('bitcoincash:qq50d800hgunr8u4trz3uuppspk3mds0dy9978plt2')
|
||||
* // etoken:qq50d800hgunr8u4trz3uuppspk3mds0dyug2v69da
|
||||
*
|
||||
* // mainnet no prefix
|
||||
* bchjs.Address.toEtokenAddress('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
|
||||
|
||||
@@ -7,6 +7,7 @@ const axios = require('axios')
|
||||
|
||||
// Local libraries.
|
||||
const Blockchain = require('./blockchain')
|
||||
// const Address = require('./address')
|
||||
|
||||
// let _this
|
||||
|
||||
@@ -32,7 +33,9 @@ class ElectrumX {
|
||||
}
|
||||
}
|
||||
|
||||
// Encapsulate dependencies
|
||||
this.blockchain = new Blockchain(config)
|
||||
// this.address = new Address(config)
|
||||
|
||||
// _this = this
|
||||
}
|
||||
@@ -104,6 +107,8 @@ class ElectrumX {
|
||||
*/
|
||||
async utxo (address) {
|
||||
try {
|
||||
// console.log(`electrumx.js/utxo() restURL: ${this.restURL}`)
|
||||
|
||||
// Handle single address.
|
||||
if (typeof address === 'string') {
|
||||
const response = await axios.get(
|
||||
|
||||
+57
-1
@@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,7 +82,10 @@ class UTXO {
|
||||
}
|
||||
|
||||
// Ensure the address is a BCH address.
|
||||
const addr = this.slp.Address.toCashAddress(address)
|
||||
let addr = address
|
||||
if (!addr.includes('ecash')) {
|
||||
addr = this.slp.Address.toCashAddress(address)
|
||||
}
|
||||
|
||||
// Get the UTXOs associated with the address.
|
||||
const utxoData = await this.electrumx.utxo(addr)
|
||||
@@ -336,6 +341,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
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
Integration tests for the psf-slp-indexer.js library, specific to the eCash
|
||||
blockchain.
|
||||
*/
|
||||
|
||||
// Global npm libraries
|
||||
const assert = require('chai').assert
|
||||
|
||||
// Local libraries
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
let bchjs
|
||||
|
||||
describe('#psf-slp-indexer', () => {
|
||||
beforeEach(async () => {
|
||||
// Introduce a delay so that the BVT doesn't trip the rate limits.
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(3000)
|
||||
|
||||
bchjs = new BCHJS()
|
||||
})
|
||||
|
||||
describe('#balance', () => {
|
||||
it('should get token balance for an ecash address', async () => {
|
||||
const addr = 'ecash:qr5c4hfy52zn87484cucvzle5pljz0gtr5vhtw9z09'
|
||||
|
||||
const result = await bchjs.PsfSlpIndexer.balance(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result.balance, 'utxos')
|
||||
assert.property(result.balance, 'txs')
|
||||
assert.property(result.balance, 'balances')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// Promise-based sleep function
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -2,10 +2,10 @@
|
||||
Integration tests for the utxo.js library.
|
||||
*/
|
||||
|
||||
// const assert = require('chai').assert
|
||||
const assert = require('chai').assert
|
||||
|
||||
// const BCHJS = require('../../../../src/bch-js')
|
||||
// const bchjs = new BCHJS()
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
describe('#UTXO', () => {
|
||||
beforeEach(async () => {
|
||||
@@ -14,25 +14,23 @@ describe('#UTXO', () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
||||
})
|
||||
|
||||
/*
|
||||
describe('#get', () => {
|
||||
it('should get hydrated and filtered UTXOs for an address', async () => {
|
||||
// const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
||||
const addr = 'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9'
|
||||
const addr = 'ecash:qr5c4hfy52zn87484cucvzle5pljz0gtr5vhtw9z09'
|
||||
// const addr = 'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9'
|
||||
|
||||
const result = await bchjs.Utxo.get(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'address')
|
||||
assert.property(result[0], 'bchUtxos')
|
||||
assert.property(result[0], 'nullUtxos')
|
||||
assert.property(result[0], 'slpUtxos')
|
||||
assert.isArray(result[0].bchUtxos)
|
||||
assert.isArray(result[0].nullUtxos)
|
||||
// assert.isArray(result)
|
||||
assert.property(result, 'address')
|
||||
assert.property(result, 'bchUtxos')
|
||||
assert.property(result, 'nullUtxos')
|
||||
assert.property(result, 'slpUtxos')
|
||||
assert.isArray(result.bchUtxos)
|
||||
assert.isArray(result.nullUtxos)
|
||||
})
|
||||
})
|
||||
*/
|
||||
})
|
||||
|
||||
function sleep (ms) {
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
/*
|
||||
Integration tests for the psf-slp-indexer.js library
|
||||
Integration tests for the psf-slp-indexer.js library, specific to the BCH
|
||||
blockchain.
|
||||
*/
|
||||
|
||||
// Global npm libraries
|
||||
const assert = require('chai').assert
|
||||
|
||||
// Local libraries
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
let bchjs
|
||||
|
||||
@@ -128,7 +131,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)
|
||||
|
||||
@@ -84,7 +84,7 @@ describe('#UTXO', () => {
|
||||
})
|
||||
|
||||
it('should handle Type1 minting batons', async () => {
|
||||
const addr = 'simpleledger:qz5l5yzz9r09hw9aadcz53elp2knx6gyg5qk3s8md7'
|
||||
const addr = 'simpleledger:qrp4mlmsrtwlvjn4seuchvtmus06tuqmpv4awvv7m7'
|
||||
|
||||
const result = await bchjs.Utxo.get(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
@@ -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) {
|
||||
|
||||
@@ -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')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user