mirror of
https://github.com/Permissionless-Software-Foundation/bch-js.git
synced 2026-09-22 00:52:01 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
951fea8f9b | ||
|
|
6d75dceffb | ||
|
|
3a491c7aba | ||
|
|
f03c020e4f | ||
|
|
4aeb1148e5 | ||
|
|
f03ee13a1e | ||
|
|
cb98773d6a | ||
|
|
c593d68ee5 | ||
|
|
dc7d3a9339 | ||
|
|
6f4cc0f439 | ||
|
|
7aa0fa865e | ||
|
|
e8b6d7fb36 | ||
|
|
b13ef94ea3 | ||
|
|
912f899f4e | ||
|
|
9063d8da0b | ||
|
|
f4e2bd96f0 | ||
|
|
1c898a4ad3 | ||
|
|
c4db813f76 | ||
|
|
38b96b441f |
@@ -33,9 +33,6 @@ Here are two YouTube walk-through videos to help you get started:
|
||||
```
|
||||
const BCHJS = require("@psf/bch-js")
|
||||
let bchjs = new BCHJS() // Defaults to BCHN network.
|
||||
|
||||
// testnet
|
||||
bchjs = new BCHJS({ restURL: 'https://testnet3.fullstack.cash/v5/' })
|
||||
```
|
||||
|
||||
This library is intended to be paired with
|
||||
@@ -43,7 +40,6 @@ the [bch-api](https://github.com/Permissionless-Software-Foundation/bch-api) RES
|
||||
|
||||
- BCHN Mainnet REST API server: https://bchn.fullstack.cash/v5/
|
||||
- ABC Mainnet REST API server: https://abc.fullstack.cash/v5/
|
||||
- Testnet3 REST API server: https://testnet3.fullstack.cash/v5/
|
||||
- Check server status: https://metrics.fullstack.cash
|
||||
|
||||
### API Key
|
||||
|
||||
Generated
+4693
-8303
File diff suppressed because it is too large
Load Diff
+3
-3
@@ -54,7 +54,7 @@
|
||||
"bip66": "^1.1.5",
|
||||
"bitcoinjs-message": "^2.0.0",
|
||||
"bs58": "^4.0.1",
|
||||
"cashaddrjs": "^0.3.3",
|
||||
"ecashaddrjs": "^1.0.7",
|
||||
"ini": "^1.3.8",
|
||||
"randombytes": "^2.0.6",
|
||||
"safe-buffer": "^5.1.2",
|
||||
@@ -76,9 +76,9 @@
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"husky": "^4.3.6",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"mocha": "^6.1.4",
|
||||
"mocha": "^9.1.3",
|
||||
"node-mocks-http": "^1.7.0",
|
||||
"nyc": "^14.1.0",
|
||||
"nyc": "^15.1.0",
|
||||
"prettier": "^1.18.2",
|
||||
"semantic-release": "^17.3.9",
|
||||
"sinon": "^7.3.2",
|
||||
|
||||
+74
-1
@@ -1,6 +1,6 @@
|
||||
// const axios = require("axios")
|
||||
const Bitcoin = require('@psf/bitcoincashjs-lib')
|
||||
const cashaddr = require('cashaddrjs')
|
||||
const cashaddr = require('ecashaddrjs')
|
||||
const coininfo = require('@psf/coininfo')
|
||||
|
||||
class Address {
|
||||
@@ -129,6 +129,63 @@ class Address {
|
||||
return cashAddress.split(':')[1]
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Address.toEcashAddress() toEcashAddress()
|
||||
* @apiName toEcashAddress
|
||||
* @apiGroup Address
|
||||
* @apiDescription Convert legacy to cashAddress format
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* // mainnet
|
||||
* bchjs.Address.toEcashAddress('bitcoincash:qq50d800hgunr8u4trz3uuppspk3mds0dy9978plt2')
|
||||
* // ecash:qq50d800hgunr8u4trz3uuppspk3mds0dyug2v69da
|
||||
*
|
||||
* // mainnet no prefix
|
||||
* bchjs.Address.toEcashAddress('bitcoincash:qq50d800hgunr8u4trz3uuppspk3mds0dy9978plt2', false)
|
||||
* // qq50d800hgunr8u4trz3uuppspk3mds0dyug2v69da
|
||||
*
|
||||
*/
|
||||
toEcashAddress (address, prefix = true) {
|
||||
const decoded = this._decode(address)
|
||||
|
||||
const ecashAddress = cashaddr.encode(
|
||||
'ecash',
|
||||
decoded.type,
|
||||
decoded.hash
|
||||
)
|
||||
|
||||
if (prefix) return ecashAddress
|
||||
return ecashAddress.split(':')[1]
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Address.ecashtoCashAddress() ecashtoCashAddress()
|
||||
* @apiName ecashtoCashAddress
|
||||
* @apiGroup Address
|
||||
* @apiDescription Convert legacy to cashAddress format
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* // mainnet
|
||||
* bchjs.Address.ecashtoCashAddress('ecash:qq50d800hgunr8u4trz3uuppspk3mds0dyug2v69da')
|
||||
* // bitcoincash:qq50d800hgunr8u4trz3uuppspk3mds0dy9978plt2
|
||||
*
|
||||
* // mainnet no prefix
|
||||
* bchjs.Address.ecashtoCashAddress('ecash:qq50d800hgunr8u4trz3uuppspk3mds0dyug2v69da', false)
|
||||
* // qq50d800hgunr8u4trz3uuppspk3mds0dy9978plt2
|
||||
*/
|
||||
ecashtoCashAddress (address, prefix = true) {
|
||||
const decoded = this._decodeEcashAddress(address)
|
||||
|
||||
const cashAddress = cashaddr.encode(
|
||||
'bitcoincash',
|
||||
decoded.type,
|
||||
decoded.hash
|
||||
)
|
||||
|
||||
if (prefix) return cashAddress
|
||||
return cashAddress.split(':')[1]
|
||||
}
|
||||
|
||||
// Converts any address format to hash160
|
||||
toHash160 (address) {
|
||||
const legacyAddress = this.toLegacyAddress(address)
|
||||
@@ -271,6 +328,22 @@ class Address {
|
||||
throw new Error(`Invalid format : ${address}`)
|
||||
}
|
||||
|
||||
_decodeEcashAddress (address) {
|
||||
if (address.indexOf(':') !== -1) {
|
||||
const decoded = cashaddr.decode(address)
|
||||
decoded.format = 'cashaddr'
|
||||
return decoded
|
||||
}
|
||||
|
||||
try {
|
||||
const decoded = cashaddr.decode(`ecash:${address}`)
|
||||
decoded.format = 'cashaddr'
|
||||
return decoded
|
||||
} catch (error) {}
|
||||
|
||||
throw new Error(`Invalid format : ${address}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Address.isLegacyAddress() isLegacyAddress()
|
||||
* @apiName isLegacyAddress
|
||||
|
||||
+42
-3
@@ -127,8 +127,9 @@ class Price {
|
||||
* @apiName Price getBchaUsd()
|
||||
* @apiGroup Price
|
||||
* @apiDescription Return current price of BCHA in USD.
|
||||
* This endpoint gets the USD price of BCHA from the Coinex API. The price
|
||||
* comes from bch-api, so it has a better chance of working in Tor.
|
||||
* This endpoint gets the USD price of XEC from the Coinex API. The price
|
||||
* denominated in BCHA comes from bch-api, so it has a better chance of
|
||||
* working in Tor.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
*(async () => {
|
||||
@@ -140,9 +141,47 @@ class Price {
|
||||
* }
|
||||
*})()
|
||||
*
|
||||
* // 18.81
|
||||
* // 212.34
|
||||
*/
|
||||
async getBchaUsd () {
|
||||
try {
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}price/bchausd`,
|
||||
this.axiosOptions
|
||||
)
|
||||
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
|
||||
|
||||
const bchaPrice = response.data.usd * 1000000
|
||||
// Convert XEC denomination to BCHA denomination
|
||||
|
||||
return bchaPrice
|
||||
} catch (err) {
|
||||
if (err.response && err.response.data) throw err.response.data
|
||||
else throw err
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api price.getXecUsd() getXecUsd()
|
||||
* @apiName Price getXecUsd()
|
||||
* @apiGroup Price
|
||||
* @apiDescription Return current price of XEC in USD.
|
||||
* This endpoint gets the USD price of XEC from the Coinex API. The price
|
||||
* comes from bch-api, so it has a better chance of working in Tor.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
*(async () => {
|
||||
* try {
|
||||
* let current = await bchjs.Price.getXecUsd();
|
||||
* console.log(current);
|
||||
* } catch(err) {
|
||||
* console.err(err)
|
||||
* }
|
||||
*})()
|
||||
*
|
||||
* // 0.00021234
|
||||
*/
|
||||
async getXecUsd () {
|
||||
try {
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}price/bchausd`,
|
||||
|
||||
@@ -319,6 +319,9 @@ class RawTransactions {
|
||||
const inputTxid = vin.txid
|
||||
const inputVout = vin.vout
|
||||
|
||||
// TODO: Coinbase TXs have no input transaction. Figure out how to
|
||||
// handle this corner case.
|
||||
|
||||
// Get the TX details for the input, in order to retrieve the address of
|
||||
// the sender.
|
||||
const txDetailsParent = await this.getRawTransaction(inputTxid, true)
|
||||
|
||||
@@ -287,9 +287,15 @@ class TokenType1 {
|
||||
try {
|
||||
// TODO: Add input validation.
|
||||
|
||||
let baseQty = new BigNumber(configObj.initialQty).times(
|
||||
10 ** configObj.decimals
|
||||
)
|
||||
let baseQty
|
||||
if (configObj.decimals !== 0) {
|
||||
baseQty = new BigNumber(configObj.initialQty).times(
|
||||
10 ** configObj.decimals
|
||||
)
|
||||
} else {
|
||||
baseQty = new BigNumber(configObj.initialQty)
|
||||
}
|
||||
|
||||
baseQty = baseQty.absoluteValue()
|
||||
baseQty = Math.floor(baseQty)
|
||||
baseQty = baseQty.toString()
|
||||
|
||||
+1
-1
@@ -921,7 +921,7 @@ class Utils {
|
||||
* const txid =
|
||||
* "266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1"
|
||||
*
|
||||
* const data = await slp.Utils.decodeOpReturn2(txid)
|
||||
* const data = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
||||
*
|
||||
* console.log(`Decoded OP_RETURN data: ${JSON.stringify(data,null,2)}`)
|
||||
* } catch (error) {
|
||||
|
||||
+49
-10
@@ -4,6 +4,7 @@
|
||||
|
||||
const RawTransaction = require('./raw-transactions')
|
||||
const SlpUtils = require('./slp/utils')
|
||||
const BigNumber = require('bignumber.js')
|
||||
|
||||
class Transaction {
|
||||
constructor (config) {
|
||||
@@ -75,9 +76,18 @@ class Transaction {
|
||||
// Add the token quantity to each output.
|
||||
for (let i = 0; i < outTokenData.amounts.length; i++) {
|
||||
const rawQty = outTokenData.amounts[i]
|
||||
const realQty = Number(rawQty) / Math.pow(10, txDetails.tokenDecimals)
|
||||
// const realQty = Number(rawQty) / Math.pow(10, txDetails.tokenDecimals)
|
||||
|
||||
txDetails.vout[i + 1].tokenQty = realQty
|
||||
// Calculate the real quantity using a BigNumber, then convert it to a
|
||||
// floating point number.
|
||||
let realQty = new BigNumber(rawQty).dividedBy(
|
||||
10 ** parseInt(txDetails.tokenDecimals)
|
||||
)
|
||||
realQty = realQty.toString()
|
||||
// realQty = parseFloat(realQty)
|
||||
|
||||
txDetails.vout[i + 1].tokenQtyStr = realQty
|
||||
txDetails.vout[i + 1].tokenQty = parseFloat(realQty)
|
||||
}
|
||||
|
||||
// Add tokenQty = null to any outputs that don't have a value.
|
||||
@@ -101,17 +111,46 @@ class Transaction {
|
||||
// `vin[${i}] tokenData: ${JSON.stringify(inTokenData, null, 2)}`
|
||||
// )
|
||||
|
||||
// Get the appropriate vout token amount. This may throw an error,
|
||||
// which means this Vin is not actually a token UTXO, it was just
|
||||
// associated with a previous token TX.
|
||||
const tokenQty = inTokenData.amounts[thisVin.vout - 1]
|
||||
// console.log(`tokenQty: ${JSON.stringify(tokenQty, null, 2)}`)
|
||||
let tokenQty = 0
|
||||
if (inTokenData.txType === 'SEND') {
|
||||
// Get the appropriate vout token amount. This may throw an error,
|
||||
// which means this Vin is not actually a token UTXO, it was just
|
||||
// associated with a previous token TX.
|
||||
tokenQty = inTokenData.amounts[thisVin.vout - 1]
|
||||
// console.log(`tokenQty: ${JSON.stringify(tokenQty, null, 2)}`)
|
||||
|
||||
//
|
||||
} else if (inTokenData.txType === 'GENESIS') {
|
||||
// Only vout[1] of a Genesis transaction represents the tokens.
|
||||
// Any other outputs in that transaction are normal BCH UTXOs.
|
||||
if (thisVin.vout === 1) {
|
||||
tokenQty = inTokenData.qty
|
||||
// console.log(`tokenQty: ${JSON.stringify(tokenQty, null, 2)}`)
|
||||
}
|
||||
|
||||
//
|
||||
} else {
|
||||
console.log(
|
||||
'Unexpected code path in Transaction.get(). Is this a MINT transaction?'
|
||||
)
|
||||
console.log(inTokenData)
|
||||
throw new Error('Unexpected code path')
|
||||
}
|
||||
|
||||
if (tokenQty) {
|
||||
const realQty =
|
||||
Number(tokenQty) / Math.pow(10, txDetails.tokenDecimals)
|
||||
// const realQty =
|
||||
// Number(tokenQty) / Math.pow(10, txDetails.tokenDecimals)
|
||||
|
||||
thisVin.tokenQty = realQty
|
||||
// Calculate the real quantity using a BigNumber, then convert it to a
|
||||
// floating point number.
|
||||
let realQty = new BigNumber(tokenQty).dividedBy(
|
||||
10 ** parseInt(txDetails.tokenDecimals)
|
||||
)
|
||||
realQty = realQty.toString()
|
||||
// realQty = parseFloat(realQty)
|
||||
|
||||
thisVin.tokenQtyStr = realQty
|
||||
thisVin.tokenQty = parseFloat(realQty)
|
||||
// txDetails.vin[i].tokenQty = tokenQty
|
||||
} else {
|
||||
thisVin.tokenQty = null
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
// const chai = require('chai')
|
||||
// const assert = chai.assert
|
||||
const sinon = require('sinon')
|
||||
|
||||
// const BCHJS = require('../../../../src/bch-js')
|
||||
// const bchjs = new BCHJS({ ninsightURL: 'https://trest.bitcoin.com/v2' })
|
||||
|
||||
describe('#Ninsight', () => {
|
||||
let sandbox
|
||||
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
||||
|
||||
sandbox = sinon.createSandbox()
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
// describe('#utxo', () => {
|
||||
// it('should GET utxos for a single address', async () => {
|
||||
// const addr = 'bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr'
|
||||
//
|
||||
// const result = await bchjs.Ninsight.utxo(addr)
|
||||
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
//
|
||||
// assert.property(result[0], 'utxos')
|
||||
// assert.property(result[0], 'legacyAddress')
|
||||
// assert.property(result[0], 'cashAddress')
|
||||
// assert.property(result[0], 'slpAddress')
|
||||
// assert.property(result[0], 'scriptPubKey')
|
||||
// assert.property(result[0], 'asm')
|
||||
//
|
||||
// assert.isArray(result[0].utxos)
|
||||
//
|
||||
// assert.property(result[0].utxos[0], 'txid')
|
||||
// assert.property(result[0].utxos[0], 'vout')
|
||||
// assert.property(result[0].utxos[0], 'amount')
|
||||
// assert.property(result[0].utxos[0], 'satoshis')
|
||||
// assert.property(result[0].utxos[0], 'height')
|
||||
// assert.property(result[0].utxos[0], 'confirmations')
|
||||
// })
|
||||
//
|
||||
// it('should POST utxo details for an array of addresses', async () => {
|
||||
// const addr = [
|
||||
// 'bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr',
|
||||
// 'bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul'
|
||||
// ]
|
||||
//
|
||||
// const result = await bchjs.Ninsight.utxo(addr)
|
||||
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
//
|
||||
// assert.isArray(result)
|
||||
// assert.isArray(result[0].utxos)
|
||||
//
|
||||
// assert.property(result[0], 'utxos')
|
||||
// assert.property(result[0], 'legacyAddress')
|
||||
// assert.property(result[0], 'cashAddress')
|
||||
// assert.property(result[0], 'slpAddress')
|
||||
// assert.property(result[0], 'scriptPubKey')
|
||||
// assert.property(result[0], 'asm')
|
||||
//
|
||||
// // assert.hasAnyKeys(result[0][0], [
|
||||
// // "txid",
|
||||
// // "vout",
|
||||
// // "value",
|
||||
// // "height",
|
||||
// // "confirmations"
|
||||
// // ])
|
||||
// })
|
||||
// })
|
||||
//
|
||||
// describe('#transactions', () => {
|
||||
// it('should POST transactions history for a single address', async () => {
|
||||
// const addr = 'bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr'
|
||||
//
|
||||
// const result = await bchjs.Ninsight.transactions(addr)
|
||||
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
//
|
||||
// assert.isArray(result)
|
||||
// assert.property(result[0], 'cashAddress')
|
||||
// assert.property(result[0], 'legacyAddress')
|
||||
// assert.property(result[0], 'txs')
|
||||
// assert.isArray(result[0].txs)
|
||||
// assert.property(result[0].txs[0], 'txid')
|
||||
// assert.property(result[0].txs[0], 'vin')
|
||||
// assert.property(result[0].txs[0], 'vout')
|
||||
// })
|
||||
// it('should POST transactions history for an array of addresses', async () => {
|
||||
// const addr = [
|
||||
// 'bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr',
|
||||
// 'bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul'
|
||||
// ]
|
||||
//
|
||||
// const result = await bchjs.Ninsight.transactions(addr)
|
||||
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
//
|
||||
// assert.isArray(result)
|
||||
// assert.property(result[0], 'cashAddress')
|
||||
// assert.property(result[0], 'legacyAddress')
|
||||
// assert.property(result[0], 'txs')
|
||||
// assert.isArray(result[0].txs)
|
||||
// assert.property(result[0].txs[0], 'txid')
|
||||
// assert.property(result[0].txs[0], 'vin')
|
||||
// assert.property(result[0].txs[0], 'vout')
|
||||
// })
|
||||
// })
|
||||
//
|
||||
// describe('#txDetails', () => {
|
||||
// it('should POST transactions details for a single address', async () => {
|
||||
// const txid =
|
||||
// '76856d82e00b2696acd8d989e1fa6c46b431005046a285ce905814cac0ff8fea'
|
||||
//
|
||||
// const result = await bchjs.Ninsight.txDetails(txid)
|
||||
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
//
|
||||
// assert.isArray(result)
|
||||
// assert.property(result[0], 'txid')
|
||||
// assert.property(result[0], 'version')
|
||||
// assert.property(result[0], 'locktime')
|
||||
// assert.property(result[0], 'vin')
|
||||
// assert.property(result[0], 'vout')
|
||||
// assert.property(result[0], 'blockhash')
|
||||
// assert.property(result[0], 'blockheight')
|
||||
// assert.property(result[0], 'confirmations')
|
||||
// assert.property(result[0], 'time')
|
||||
// assert.property(result[0], 'blocktime')
|
||||
// assert.property(result[0], 'valueOut')
|
||||
// assert.property(result[0], 'size')
|
||||
// })
|
||||
// it('should POST transactions details for an array of addresses', async () => {
|
||||
// const txid = [
|
||||
// 'f191d1062789d7071da6f2168ba306869a829294f6b1c09d03492db4ca3a8e77',
|
||||
// '76856d82e00b2696acd8d989e1fa6c46b431005046a285ce905814cac0ff8fea'
|
||||
// ]
|
||||
//
|
||||
// const result = await bchjs.Ninsight.txDetails(txid)
|
||||
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
//
|
||||
// assert.isArray(result)
|
||||
// assert.property(result[0], 'txid')
|
||||
// assert.property(result[0], 'vin')
|
||||
// assert.property(result[0], 'vout')
|
||||
// })
|
||||
// })
|
||||
})
|
||||
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
const sinon = require('sinon')
|
||||
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
const bchjs = new BCHJS({ ninsightURL: 'https://rest.bitcoin.com/v2' })
|
||||
|
||||
describe('#Ninsight', () => {
|
||||
let sandbox
|
||||
|
||||
beforeEach(async () => {
|
||||
sandbox = sinon.createSandbox()
|
||||
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe('#utxo', () => {
|
||||
it('should GET utxos for a single address', async () => {
|
||||
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
||||
|
||||
const result = await bchjs.Ninsight.utxo(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result[0], 'utxos')
|
||||
assert.property(result[0], 'legacyAddress')
|
||||
assert.property(result[0], 'cashAddress')
|
||||
assert.property(result[0], 'slpAddress')
|
||||
assert.property(result[0], 'scriptPubKey')
|
||||
assert.property(result[0], 'asm')
|
||||
|
||||
assert.isArray(result[0].utxos)
|
||||
|
||||
assert.property(result[0].utxos[0], 'txid')
|
||||
assert.property(result[0].utxos[0], 'vout')
|
||||
assert.property(result[0].utxos[0], 'amount')
|
||||
assert.property(result[0].utxos[0], 'satoshis')
|
||||
assert.property(result[0].utxos[0], 'height')
|
||||
assert.property(result[0].utxos[0], 'confirmations')
|
||||
})
|
||||
|
||||
it('should POST utxo details for an array of addresses', async () => {
|
||||
const addr = [
|
||||
'bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7',
|
||||
'bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr'
|
||||
]
|
||||
|
||||
const result = await bchjs.Ninsight.utxo(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.isArray(result[0].utxos)
|
||||
|
||||
assert.property(result[0], 'utxos')
|
||||
assert.property(result[0], 'legacyAddress')
|
||||
assert.property(result[0], 'cashAddress')
|
||||
assert.property(result[0], 'slpAddress')
|
||||
assert.property(result[0], 'scriptPubKey')
|
||||
assert.property(result[0], 'asm')
|
||||
})
|
||||
})
|
||||
describe('#transactions', () => {
|
||||
it('should POST transactions history for a single address', async () => {
|
||||
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
||||
|
||||
const result = await bchjs.Ninsight.transactions(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'cashAddress')
|
||||
assert.property(result[0], 'legacyAddress')
|
||||
assert.property(result[0], 'txs')
|
||||
assert.isArray(result[0].txs)
|
||||
assert.property(result[0].txs[0], 'txid')
|
||||
assert.property(result[0].txs[0], 'vin')
|
||||
assert.property(result[0].txs[0], 'vout')
|
||||
})
|
||||
it('should POST transactions history for an array of addresses', async () => {
|
||||
const addr = [
|
||||
'bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7',
|
||||
'bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr'
|
||||
]
|
||||
|
||||
const result = await bchjs.Ninsight.transactions(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'cashAddress')
|
||||
assert.property(result[0], 'legacyAddress')
|
||||
assert.property(result[0], 'txs')
|
||||
assert.isArray(result[0].txs)
|
||||
assert.property(result[0].txs[0], 'txid')
|
||||
assert.property(result[0].txs[0], 'vin')
|
||||
assert.property(result[0].txs[0], 'vout')
|
||||
})
|
||||
})
|
||||
describe('#txDetails', () => {
|
||||
it('should POST transactions details for a single address', async () => {
|
||||
const txid = 'fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33'
|
||||
|
||||
const result = await bchjs.Ninsight.txDetails(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'txid')
|
||||
assert.property(result[0], 'version')
|
||||
assert.property(result[0], 'locktime')
|
||||
assert.property(result[0], 'vin')
|
||||
assert.property(result[0], 'vout')
|
||||
assert.property(result[0], 'blockhash')
|
||||
assert.property(result[0], 'blockheight')
|
||||
assert.property(result[0], 'confirmations')
|
||||
assert.property(result[0], 'time')
|
||||
assert.property(result[0], 'blocktime')
|
||||
assert.property(result[0], 'valueOut')
|
||||
assert.property(result[0], 'size')
|
||||
})
|
||||
it('should POST transactions details for an array of addresses', async () => {
|
||||
const txid = [
|
||||
'fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33',
|
||||
'4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251'
|
||||
]
|
||||
|
||||
const result = await bchjs.Ninsight.txDetails(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'txid')
|
||||
assert.property(result[0], 'vin')
|
||||
assert.property(result[0], 'vout')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -175,10 +175,124 @@ const mockOpReturnData03 = {
|
||||
amounts: ['1000000000', '99883400000000']
|
||||
}
|
||||
|
||||
const genesisTestInputTx = {
|
||||
txid: '874306bda204d3a5dd15e03ea5732cccdca4c33a52df35162cdd64e30ea7f04e',
|
||||
hash: '874306bda204d3a5dd15e03ea5732cccdca4c33a52df35162cdd64e30ea7f04e',
|
||||
version: 1,
|
||||
size: 480,
|
||||
locktime: 543408,
|
||||
vin: [
|
||||
{
|
||||
txid: '323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d35',
|
||||
vout: 1,
|
||||
scriptSig: {
|
||||
asm:
|
||||
'30440220268dacee1117975d904dd0d45ef8de42b86030d825a9522bae196a38bbf6b271022001ae1ce2536ab300040e597bcfaa8ef9fb2beaf702d0842f3161aae8e9867f55[ALL|FORKID] 028ff9e32b0dbc82c1d5e0fc945b2537b00420513b10684726f312f1b717c0ae11',
|
||||
hex:
|
||||
'4730440220268dacee1117975d904dd0d45ef8de42b86030d825a9522bae196a38bbf6b271022001ae1ce2536ab300040e597bcfaa8ef9fb2beaf702d0842f3161aae8e9867f554121028ff9e32b0dbc82c1d5e0fc945b2537b00420513b10684726f312f1b717c0ae11'
|
||||
},
|
||||
sequence: 4294967294,
|
||||
address: 'bitcoincash:qp2jesd06k8ycj4wvkpl9lcwaemtr04f5yphjsa07v',
|
||||
value: 0.00000546
|
||||
},
|
||||
{
|
||||
txid: '323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d35',
|
||||
vout: 3,
|
||||
scriptSig: {
|
||||
asm:
|
||||
'3045022100fa241bb2de46f68688451bfcae3f165b724e3ccf13b219e7bf2d8d2df7712ad60220353017d6e581a06efce478adfcd2047cea2f92531e283845f3d0a345ef101519[ALL|FORKID] 02cc48ad10516f97e914b8836ff25448d07ad96ebb4704c6a828339880280831bc',
|
||||
hex:
|
||||
'483045022100fa241bb2de46f68688451bfcae3f165b724e3ccf13b219e7bf2d8d2df7712ad60220353017d6e581a06efce478adfcd2047cea2f92531e283845f3d0a345ef101519412102cc48ad10516f97e914b8836ff25448d07ad96ebb4704c6a828339880280831bc'
|
||||
},
|
||||
sequence: 4294967294,
|
||||
address: 'bitcoincash:qppj3euc36x5u6twr5cxrrea2rca53vsfu3dxwr86j',
|
||||
value: 0.00172192
|
||||
}
|
||||
],
|
||||
vout: [
|
||||
{
|
||||
value: 0,
|
||||
n: 0,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
'OP_RETURN 5262419 1 1145980243 323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d35 00000000004c4b40 00000000004c4b40',
|
||||
hex:
|
||||
'6a04534c500001010453454e4420323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d350800000000004c4b400800000000004c4b40',
|
||||
type: 'nulldata'
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0.00000546,
|
||||
n: 1,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
'OP_DUP OP_HASH160 0a74cf9c0fb3f6dd62c3f5eecd1ed6e1051428e0 OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a9140a74cf9c0fb3f6dd62c3f5eecd1ed6e1051428e088ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash',
|
||||
addresses: ['bitcoincash:qq98fnuup7eldhtzc067ang76mss29pguqh7qv9eac']
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0.00000546,
|
||||
n: 2,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
'OP_DUP OP_HASH160 d4548261e1be0de7e50b7511597799ec4af2b173 OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a914d4548261e1be0de7e50b7511597799ec4af2b17388ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash',
|
||||
addresses: ['bitcoincash:qr29fqnpuxlqmel9pd63zkthn8ky4u43wv0v7pg5mn']
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0.00171165,
|
||||
n: 3,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
'OP_DUP OP_HASH160 d4548261e1be0de7e50b7511597799ec4af2b173 OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a914d4548261e1be0de7e50b7511597799ec4af2b17388ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash',
|
||||
addresses: ['bitcoincash:qr29fqnpuxlqmel9pd63zkthn8ky4u43wv0v7pg5mn']
|
||||
}
|
||||
}
|
||||
],
|
||||
hex:
|
||||
'0100000002359dab0d9c8ddc788b14c0b51493d195c9fbd9f2203d091663350bae351e3a32010000006a4730440220268dacee1117975d904dd0d45ef8de42b86030d825a9522bae196a38bbf6b271022001ae1ce2536ab300040e597bcfaa8ef9fb2beaf702d0842f3161aae8e9867f554121028ff9e32b0dbc82c1d5e0fc945b2537b00420513b10684726f312f1b717c0ae11feffffff359dab0d9c8ddc788b14c0b51493d195c9fbd9f2203d091663350bae351e3a32030000006b483045022100fa241bb2de46f68688451bfcae3f165b724e3ccf13b219e7bf2d8d2df7712ad60220353017d6e581a06efce478adfcd2047cea2f92531e283845f3d0a345ef101519412102cc48ad10516f97e914b8836ff25448d07ad96ebb4704c6a828339880280831bcfeffffff040000000000000000406a04534c500001010453454e4420323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d350800000000004c4b400800000000004c4b4022020000000000001976a9140a74cf9c0fb3f6dd62c3f5eecd1ed6e1051428e088ac22020000000000001976a914d4548261e1be0de7e50b7511597799ec4af2b17388ac9d9c0200000000001976a914d4548261e1be0de7e50b7511597799ec4af2b17388acb04a0800',
|
||||
blockhash: '000000000000000000292a9c6150fce48e2edd8df346948494fe6249e6e7f63b',
|
||||
confirmations: 163095,
|
||||
time: 1534271330,
|
||||
blocktime: 1534271330
|
||||
}
|
||||
|
||||
genesisTestOpReturnData01 = {
|
||||
tokenType: 1,
|
||||
txType: 'SEND',
|
||||
tokenId: '323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d35',
|
||||
amounts: ['5000000', '5000000']
|
||||
}
|
||||
|
||||
genesisTestOpReturnData02 = {
|
||||
tokenType: 1,
|
||||
txType: 'GENESIS',
|
||||
ticker: '',
|
||||
name: '',
|
||||
tokenId: '323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d35',
|
||||
documentUri: '',
|
||||
documentHash: '',
|
||||
decimals: 0,
|
||||
mintBatonVout: 2,
|
||||
qty: '10000000'
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
nonSlpTxDetails,
|
||||
slpTxDetails,
|
||||
mockOpReturnData01,
|
||||
mockOpReturnData02,
|
||||
mockOpReturnData03
|
||||
mockOpReturnData03,
|
||||
genesisTestInputTx,
|
||||
genesisTestOpReturnData01,
|
||||
genesisTestOpReturnData02
|
||||
}
|
||||
|
||||
@@ -115,5 +115,54 @@ describe('#TransactionLib', () => {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
|
||||
// This test case was created in response to a bug. When the input TX
|
||||
// was a Genesis SLP transaction, the inputs of the transaction were not
|
||||
// being hydrated properly.
|
||||
it('should get input details when input is a genesis tx', async () => {
|
||||
// Mock dependencies
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.rawTransaction, 'getTxData')
|
||||
.resolves(mockData.genesisTestInputTx)
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.slpUtils, 'decodeOpReturn')
|
||||
.onCall(0)
|
||||
.resolves(mockData.genesisTestOpReturnData01)
|
||||
.onCall(1)
|
||||
.resolves(mockData.genesisTestOpReturnData02)
|
||||
.onCall(2)
|
||||
.resolves(mockData.genesisTestOpReturnData02)
|
||||
.onCall(3)
|
||||
.resolves(mockData.genesisTestOpReturnData02)
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.slpUtils, 'waterfallValidateTxid')
|
||||
.resolves(true)
|
||||
|
||||
const txid =
|
||||
'874306bda204d3a5dd15e03ea5732cccdca4c33a52df35162cdd64e30ea7f04e'
|
||||
|
||||
const result = await bchjs.Transaction.get(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
// Assert that there are stanardized properties.
|
||||
assert.property(result, 'txid')
|
||||
assert.property(result, 'vin')
|
||||
assert.property(result, 'vout')
|
||||
assert.property(result.vout[0], 'value')
|
||||
assert.property(result.vout[1].scriptPubKey, 'addresses')
|
||||
|
||||
// Assert that added properties exist.
|
||||
assert.property(result.vout[0], 'tokenQty')
|
||||
assert.equal(result.vout[0].tokenQty, null)
|
||||
assert.property(result.vin[0], 'address')
|
||||
assert.property(result.vin[0], 'value')
|
||||
assert.property(result.vin[0], 'tokenQty')
|
||||
assert.property(result, 'isValidSLPTx')
|
||||
assert.equal(result.isValidSLPTx, true)
|
||||
|
||||
// Assert inputs values unique to a Genesis input have the proper values.
|
||||
assert.equal(result.vin[0].tokenQty, 10000000)
|
||||
assert.equal(result.vin[1].tokenQty, null)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user