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 | |
|---|---|---|---|
|
|
400e7b31a8 | ||
|
|
360fca0475 | ||
|
|
ef7056ee7a | ||
|
|
d221077786 | ||
|
|
046ab78c6a | ||
|
|
29e90915e7 | ||
|
|
3d85dbfb22 | ||
|
|
2c0fa9dfbd | ||
|
|
6ca1d729dc | ||
|
|
85a34a8305 | ||
|
|
ef6cfe4409 | ||
|
|
a29d6ed26a | ||
|
|
fa58a0764c | ||
|
|
2c2fbeaa46 | ||
|
|
1e4cd5f99e | ||
|
|
52c1ebdafe | ||
|
|
2e56d66f48 | ||
|
|
9cf6c7e7a7 | ||
|
|
43043672c6 | ||
|
|
4f4b2c864d | ||
|
|
951fea8f9b | ||
|
|
6d75dceffb | ||
|
|
3a491c7aba | ||
|
|
f03c020e4f | ||
|
|
4aeb1148e5 | ||
|
|
f03ee13a1e | ||
|
|
cb98773d6a | ||
|
|
e8b6d7fb36 |
@@ -118,3 +118,5 @@ Copies of this repository are also published on [IPFS](https://ipfs.io).
|
||||
## License
|
||||
|
||||
[MIT](LICENSE.md)
|
||||
|
||||
test
|
||||
|
||||
Generated
+7381
-12542
File diff suppressed because it is too large
Load Diff
+43
-43
@@ -36,53 +36,53 @@
|
||||
"url": "git+https://github.com/Permissionless-Software-Foundation/bch-js.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"@psf/bip21": "^2.0.1",
|
||||
"@psf/bip32-utils": "^1.0.0",
|
||||
"@psf/bitcoincash-ops": "^2.0.0",
|
||||
"@psf/bitcoincashjs-lib": "^4.0.2",
|
||||
"@psf/coininfo": "^4.0.0",
|
||||
"@uppy/core": "^1.10.4",
|
||||
"@uppy/tus": "^1.5.12",
|
||||
"axios": "^0.21.1",
|
||||
"bc-bip68": "^1.0.5",
|
||||
"bchaddrjs-slp": "^0.2.5",
|
||||
"bigi": "^1.4.2",
|
||||
"bignumber.js": "^9.0.0",
|
||||
"bip-schnorr": "^0.3.0",
|
||||
"bip38": "^2.0.2",
|
||||
"bip39": "^3.0.2",
|
||||
"bip66": "^1.1.5",
|
||||
"bitcoinjs-message": "^2.0.0",
|
||||
"bs58": "^4.0.1",
|
||||
"cashaddrjs": "^0.3.3",
|
||||
"ini": "^1.3.8",
|
||||
"randombytes": "^2.0.6",
|
||||
"safe-buffer": "^5.1.2",
|
||||
"satoshi-bitcoin": "^1.0.4",
|
||||
"@psf/bip21": "2.0.1",
|
||||
"@psf/bip32-utils": "1.0.1",
|
||||
"@psf/bitcoincash-ops": "2.0.0",
|
||||
"@psf/bitcoincashjs-lib": "4.0.2",
|
||||
"@psf/coininfo": "4.0.0",
|
||||
"@uppy/core": "1.10.4",
|
||||
"@uppy/tus": "1.5.12",
|
||||
"axios": "^0.21.4",
|
||||
"bc-bip68": "1.0.5",
|
||||
"bchaddrjs-slp": "0.2.5",
|
||||
"bigi": "1.4.2",
|
||||
"bignumber.js": "9.0.0",
|
||||
"bip-schnorr": "0.3.0",
|
||||
"bip38": "2.0.2",
|
||||
"bip39": "3.0.2",
|
||||
"bip66": "1.1.5",
|
||||
"bitcoinjs-message": "2.0.0",
|
||||
"bs58": "4.0.1",
|
||||
"ecashaddrjs": "1.0.7",
|
||||
"ini": "1.3.8",
|
||||
"randombytes": "2.0.6",
|
||||
"safe-buffer": "5.1.2",
|
||||
"satoshi-bitcoin": "1.0.4",
|
||||
"slp-mdm": "0.0.6",
|
||||
"slp-parser": "0.0.4",
|
||||
"wif": "^2.0.6"
|
||||
"wif": "2.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"apidoc": "^0.17.7",
|
||||
"assert": "^2.0.0",
|
||||
"chai": "^4.1.2",
|
||||
"coveralls": "^3.0.2",
|
||||
"eslint": "5.16.0",
|
||||
"eslint-config-prettier": "^6.0.0",
|
||||
"eslint-config-standard": "^14.1.0",
|
||||
"eslint-plugin-node": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^3.1.0",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"husky": "^4.3.6",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"mocha": "^6.1.4",
|
||||
"node-mocks-http": "^1.7.0",
|
||||
"nyc": "^14.1.0",
|
||||
"prettier": "^1.18.2",
|
||||
"semantic-release": "^17.3.9",
|
||||
"sinon": "^7.3.2",
|
||||
"standard": "^16.0.3"
|
||||
"apidoc": "0.17.7",
|
||||
"assert": "2.0.0",
|
||||
"chai": "4.1.2",
|
||||
"coveralls": "3.0.2",
|
||||
"eslint": "^8.1.0",
|
||||
"eslint-config-prettier": "6.0.0",
|
||||
"eslint-config-standard": "14.1.0",
|
||||
"eslint-plugin-node": "9.1.0",
|
||||
"eslint-plugin-prettier": "3.1.0",
|
||||
"eslint-plugin-standard": "4.0.0",
|
||||
"husky": "^4.3.8",
|
||||
"lodash.clonedeep": "4.5.0",
|
||||
"mocha": "9.1.3",
|
||||
"node-mocks-http": "1.7.0",
|
||||
"nyc": "15.1.0",
|
||||
"prettier": "1.18.2",
|
||||
"semantic-release": "18.0.0",
|
||||
"sinon": "7.3.2",
|
||||
"standard": "^16.0.4"
|
||||
},
|
||||
"apidoc": {
|
||||
"title": "bch-js",
|
||||
|
||||
+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
|
||||
|
||||
+5
-5
@@ -128,7 +128,7 @@ class Price {
|
||||
* @apiGroup Price
|
||||
* @apiDescription Return current price of BCHA in USD.
|
||||
* 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
|
||||
* denominated in BCHA comes from bch-api, so it has a better chance of
|
||||
* working in Tor.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
@@ -150,7 +150,7 @@ class Price {
|
||||
this.axiosOptions
|
||||
)
|
||||
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
|
||||
|
||||
|
||||
const bchaPrice = response.data.usd * 1000000
|
||||
// Convert XEC denomination to BCHA denomination
|
||||
|
||||
@@ -161,7 +161,7 @@ class Price {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @api price.getXecUsd() getXecUsd()
|
||||
* @apiName Price getXecUsd()
|
||||
* @apiGroup Price
|
||||
@@ -179,9 +179,9 @@ class Price {
|
||||
* }
|
||||
*})()
|
||||
*
|
||||
* // 0.00021234
|
||||
* // 0.00021234
|
||||
*/
|
||||
async getXecUsd () {
|
||||
async getXecUsd () {
|
||||
try {
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}price/bchausd`,
|
||||
|
||||
@@ -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()
|
||||
|
||||
+224
-3
@@ -2,15 +2,18 @@
|
||||
High-level functions for working with Transactions
|
||||
*/
|
||||
|
||||
const BigNumber = require('bignumber.js')
|
||||
|
||||
const RawTransaction = require('./raw-transactions')
|
||||
const SlpUtils = require('./slp/utils')
|
||||
const BigNumber = require('bignumber.js')
|
||||
const Blockchain = require('./blockchain')
|
||||
|
||||
class Transaction {
|
||||
constructor (config) {
|
||||
// Encapsulate dependencies
|
||||
this.slpUtils = new SlpUtils(config)
|
||||
this.rawTransaction = new RawTransaction(config)
|
||||
this.blockchain = new Blockchain(config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,6 +38,10 @@ class Transaction {
|
||||
* }
|
||||
* })()
|
||||
*/
|
||||
|
||||
// CT 10/31/21: TODO: this function should be refactored to use get2(), but
|
||||
// add waterfall validation of the TX and its inputs.
|
||||
|
||||
async get (txid) {
|
||||
try {
|
||||
if (typeof txid !== 'string') {
|
||||
@@ -102,6 +109,7 @@ class Transaction {
|
||||
// Loop through each input and retrieve the token data.
|
||||
for (let i = 0; i < txDetails.vin.length; i++) {
|
||||
const thisVin = txDetails.vin[i]
|
||||
// console.log(`thisVin: ${JSON.stringify(thisVin, null, 2)}`)
|
||||
|
||||
try {
|
||||
// If decodeOpReturn() throws an error, then this input is not
|
||||
@@ -112,7 +120,16 @@ class Transaction {
|
||||
// )
|
||||
|
||||
let tokenQty = 0
|
||||
if (inTokenData.txType === 'SEND') {
|
||||
|
||||
// Validate the input. Mark qty as null if not valid.
|
||||
const vinIsValid = await this.slpUtils.waterfallValidateTxid(
|
||||
thisVin.txid
|
||||
)
|
||||
|
||||
if (!vinIsValid) {
|
||||
// If the input is not a valid, then set qty as null.
|
||||
tokenQty = null
|
||||
} else 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.
|
||||
@@ -127,11 +144,18 @@ class Transaction {
|
||||
tokenQty = inTokenData.qty
|
||||
// console.log(`tokenQty: ${JSON.stringify(tokenQty, null, 2)}`)
|
||||
}
|
||||
} else if (inTokenData.txType === 'MINT') {
|
||||
// vout=1 (second output) recieves the newly minted tokens.
|
||||
if (thisVin.vout === 1) {
|
||||
tokenQty = inTokenData.qty
|
||||
} else {
|
||||
tokenQty = null
|
||||
}
|
||||
|
||||
//
|
||||
} else {
|
||||
console.log(
|
||||
'Unexpected code path in Transaction.get(). Is this a MINT transaction?'
|
||||
'Unexpected code path in Transaction.get(). What is the txType?'
|
||||
)
|
||||
console.log(inTokenData)
|
||||
throw new Error('Unexpected code path')
|
||||
@@ -152,6 +176,9 @@ class Transaction {
|
||||
thisVin.tokenQtyStr = realQty
|
||||
thisVin.tokenQty = parseFloat(realQty)
|
||||
// txDetails.vin[i].tokenQty = tokenQty
|
||||
|
||||
// Add token ID to input
|
||||
thisVin.tokenId = inTokenData.tokenId
|
||||
} else {
|
||||
thisVin.tokenQty = null
|
||||
}
|
||||
@@ -167,6 +194,200 @@ class Transaction {
|
||||
// Finally, validate the SLP TX.
|
||||
// this.slpUtils.waterfallValidateTxid(txid, usrObj)
|
||||
txDetails.isValidSLPTx = await this.slpUtils.waterfallValidateTxid(txid)
|
||||
|
||||
// TODO: Convert the block hash to a block height. Add block height
|
||||
// value to the transaction.
|
||||
} catch (err) {
|
||||
// console.log('Error: ', err)
|
||||
|
||||
// This case handles rate limit errors.
|
||||
if (err.response && err.response.data && err.response.data.error) {
|
||||
throw new Error(err.response.data.error)
|
||||
}
|
||||
|
||||
// If decoding the op_return fails, then it's not an SLP transaction,
|
||||
// and the non-hyrated TX details can be returned.
|
||||
return txDetails
|
||||
}
|
||||
|
||||
return txDetails
|
||||
} catch (err) {
|
||||
// console.error('Error in transactions.js/get(): ', err)
|
||||
|
||||
// This case handles rate limit errors.
|
||||
if (err.response && err.response.data && err.response.data.error) {
|
||||
throw new Error(err.response.data.error)
|
||||
}
|
||||
|
||||
if (err.error) throw new Error(err.error)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Transaction.get2() get2()
|
||||
* @apiName get2
|
||||
* @apiGroup Transaction
|
||||
* @apiDescription
|
||||
* Returns an object of transaction data, including addresses for input UTXOs.
|
||||
* If it is a SLP token transaction, the token information for inputs and
|
||||
* outputs will also be included.
|
||||
*
|
||||
* This is an API heavy call. This function will only work with a single txid.
|
||||
* It does not yet support an array of TXIDs.
|
||||
*
|
||||
* This is the same as get(), except it omits DAG validation of the TXID.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* try {
|
||||
* let txData = await bchjs.Transaction.get2("0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098");
|
||||
* console.log(txData);
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*/
|
||||
async get2 (txid) {
|
||||
try {
|
||||
if (typeof txid !== 'string') {
|
||||
throw new Error(
|
||||
'Input to Transaction.get() must be a string containing a TXID.'
|
||||
)
|
||||
}
|
||||
|
||||
const txDetails = await this.rawTransaction.getTxData(txid)
|
||||
// console.log(`txDetails: ${JSON.stringify(txDetails, null, 2)}`)
|
||||
|
||||
// Get the block height the transaction was mined in.
|
||||
const blockHeader = await this.blockchain.getBlockHeader(
|
||||
txDetails.blockhash
|
||||
)
|
||||
txDetails.blockheight = blockHeader.height
|
||||
|
||||
// First get the token information for the output. If that fails, then
|
||||
// this is not an SLP transaction, and this method can return false.
|
||||
let outTokenData
|
||||
try {
|
||||
outTokenData = await this.slpUtils.decodeOpReturn(txid)
|
||||
// console.log(`outTokenData: ${JSON.stringify(outTokenData, null, 2)}`)
|
||||
|
||||
// Get Genesis data for this token.
|
||||
const genesisData = await this.slpUtils.decodeOpReturn(
|
||||
outTokenData.tokenId
|
||||
// decodeOpReturnCache
|
||||
// usrObj // pass user data when making an internal call.
|
||||
)
|
||||
// console.log(`genesisData: ${JSON.stringify(genesisData, null, 2)}`)
|
||||
|
||||
// Add token information to the tx details object.
|
||||
txDetails.tokenTxType = outTokenData.txType
|
||||
txDetails.tokenId = outTokenData.tokenId
|
||||
txDetails.tokenTicker = genesisData.ticker
|
||||
txDetails.tokenName = genesisData.name
|
||||
txDetails.tokenDecimals = genesisData.decimals
|
||||
txDetails.tokenUri = genesisData.documentUri
|
||||
txDetails.tokenDocHash = genesisData.documentHash
|
||||
|
||||
// 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)
|
||||
|
||||
// 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.
|
||||
for (let i = 0; i < txDetails.vout.length; i++) {
|
||||
const thisVout = txDetails.vout[i]
|
||||
|
||||
if (!thisVout.tokenQty && thisVout.tokenQty !== 0) {
|
||||
thisVout.tokenQty = null
|
||||
}
|
||||
}
|
||||
|
||||
// Loop through each input and retrieve the token data.
|
||||
for (let i = 0; i < txDetails.vin.length; i++) {
|
||||
const thisVin = txDetails.vin[i]
|
||||
// console.log(`thisVin: ${JSON.stringify(thisVin, null, 2)}`)
|
||||
|
||||
try {
|
||||
// If decodeOpReturn() throws an error, then this input is not
|
||||
// from an SLP transaction and can be ignored.
|
||||
const inTokenData = await this.slpUtils.decodeOpReturn(thisVin.txid)
|
||||
// console.log(
|
||||
// `vin[${i}] tokenData: ${JSON.stringify(inTokenData, 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 if (inTokenData.txType === 'MINT') {
|
||||
// vout=1 (second output) recieves the newly minted tokens.
|
||||
if (thisVin.vout === 1) {
|
||||
tokenQty = inTokenData.qty
|
||||
} else {
|
||||
tokenQty = null
|
||||
}
|
||||
|
||||
//
|
||||
} else {
|
||||
console.log(
|
||||
'Unexpected code path in Transaction.get2(). What is the txType?'
|
||||
)
|
||||
console.log(inTokenData)
|
||||
throw new Error('Unexpected code path')
|
||||
}
|
||||
|
||||
if (tokenQty) {
|
||||
// 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
|
||||
|
||||
// Add token ID to input
|
||||
thisVin.tokenId = inTokenData.tokenId
|
||||
} else {
|
||||
thisVin.tokenQty = null
|
||||
}
|
||||
} catch (err) {
|
||||
// If decodeOpReturn() throws an error, then this input is not
|
||||
// from an SLP transaction and can be ignored.
|
||||
// thisVin.tokenQty = null
|
||||
thisVin.tokenQty = null
|
||||
continue
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
// console.log('Error: ', err)
|
||||
|
||||
|
||||
@@ -56,5 +56,26 @@ describe('#Transaction', () => {
|
||||
assert.property(result, 'isValidSLPTx')
|
||||
assert.equal(result.isValidSLPTx, true)
|
||||
})
|
||||
|
||||
// it('should get problematic transaction', async () => {
|
||||
// const txid = 'a55515de32577e296c512840bcaabed5823bb773fb4f8fd8e5197cc96cbc54d1'
|
||||
//
|
||||
// const result = await bchjs.Transaction.get(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
// })
|
||||
|
||||
// TX a19f2f395a8b0e15b6202944c56834367d128f1e3630486a4756de53424a46fe has
|
||||
// an input TXID (bd84bc1dd5ecd976165892306992401272f6bedeb37d7b2cdbf74fc4a55967a6)
|
||||
// that is also a valid SLP tx, but is unrelated. Both TXs pass DAG validation,
|
||||
// but for separate tokens.
|
||||
it('should get problematic transaction', async () => {
|
||||
const txid = 'a19f2f395a8b0e15b6202944c56834367d128f1e3630486a4756de53424a46fe'
|
||||
|
||||
const result = await bchjs.Transaction.get(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
// The token ID should equal the txid for this Vin.
|
||||
assert.equal(result.vin[2].txid, result.vin[2].tokenId)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -266,14 +266,117 @@ const genesisTestInputTx = {
|
||||
blocktime: 1534271330
|
||||
}
|
||||
|
||||
genesisTestOpReturnData01 = {
|
||||
const mintTestInputTx = {
|
||||
txid: '4640a734063ea79fa587a3cac38a70a2f6f3db0011e23514024185982110d0fa',
|
||||
hash: '4640a734063ea79fa587a3cac38a70a2f6f3db0011e23514024185982110d0fa',
|
||||
version: 1,
|
||||
size: 585,
|
||||
locktime: 543613,
|
||||
vin: [
|
||||
{
|
||||
txid: '938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8',
|
||||
vout: 1,
|
||||
scriptSig: {
|
||||
asm: '3045022100e3d5f9a48f9aa1cf7e9ed1992e0281e7300b734ba0e4bd5bb9265b2be60bd71002200ccde53ce7ea9da9df3e834f234f3bea65c2e58c96f8436f93333fd8946a1db2[ALL|FORKID] 02056220984cc2cf5261a27d4f66d31c9ef601a688ca1a5ab81e55b6f0d311be74',
|
||||
hex: '483045022100e3d5f9a48f9aa1cf7e9ed1992e0281e7300b734ba0e4bd5bb9265b2be60bd71002200ccde53ce7ea9da9df3e834f234f3bea65c2e58c96f8436f93333fd8946a1db2412102056220984cc2cf5261a27d4f66d31c9ef601a688ca1a5ab81e55b6f0d311be74'
|
||||
},
|
||||
sequence: 4294967294,
|
||||
address: 'bitcoincash:qpaf9wltgmpjlg2vxwwu7zdw5y4z7m277ckxn8cufl',
|
||||
value: 0.00000546,
|
||||
tokenQtyStr: '43545.34534',
|
||||
tokenQty: 43545.34534
|
||||
},
|
||||
{
|
||||
txid: 'ee9d3cf5153599c134147e3fac9844c68e216843f4452a1ce15a29452af6db34',
|
||||
vout: 1,
|
||||
scriptSig: {
|
||||
asm: '3045022100bb90d52be9b568f643fdb1a302e9f063be27a9f914e2a6b192cbabf2cbdeaf9302203c275fc8d1b82390bc1726390d361c5266056bddd54dec23efa207c79eacea4a[ALL|FORKID] 024146cfcd0c02e99d6451dc48ad0f97114aeda18fe55c52a10bfc0490f314e6a2',
|
||||
hex: '483045022100bb90d52be9b568f643fdb1a302e9f063be27a9f914e2a6b192cbabf2cbdeaf9302203c275fc8d1b82390bc1726390d361c5266056bddd54dec23efa207c79eacea4a4121024146cfcd0c02e99d6451dc48ad0f97114aeda18fe55c52a10bfc0490f314e6a2'
|
||||
},
|
||||
sequence: 4294967294,
|
||||
address: 'bitcoincash:qqf89zzwd0fqc3npkks997r5l7dpfjf9kgx2rqu500',
|
||||
value: 0.00000546,
|
||||
tokenQtyStr: '2.34123',
|
||||
tokenQty: 2.34123
|
||||
},
|
||||
{
|
||||
txid: 'ee9d3cf5153599c134147e3fac9844c68e216843f4452a1ce15a29452af6db34',
|
||||
vout: 3,
|
||||
scriptSig: {
|
||||
asm: '3044022029ab770c249f467b40bb90410429f6d657f9be299baa19a6838d04d972436b450220143660297e8e836bc16d317649fad8c310bdadb4fb61d4e9f6ba11203abe5dae[ALL|FORKID] 02eed4ac9dda3405d9b1ccbbf09f8056f3e7c615924274bd5643238b543d0a1d56',
|
||||
hex: '473044022029ab770c249f467b40bb90410429f6d657f9be299baa19a6838d04d972436b450220143660297e8e836bc16d317649fad8c310bdadb4fb61d4e9f6ba11203abe5dae412102eed4ac9dda3405d9b1ccbbf09f8056f3e7c615924274bd5643238b543d0a1d56'
|
||||
},
|
||||
sequence: 4294967294,
|
||||
address: 'bitcoincash:qqt30r33k0jx3sxe34tmupaujpaljnglmvqgrrfp2x',
|
||||
value: 0.00054848,
|
||||
tokenQtyStr: '2.34123',
|
||||
tokenQty: 2.34123
|
||||
}
|
||||
],
|
||||
vout: [
|
||||
{
|
||||
value: 0,
|
||||
n: 0,
|
||||
scriptPubKey: {
|
||||
asm: 'OP_RETURN 5262419 1 1145980243 938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8 0000000103907f11',
|
||||
hex: '6a04534c500001010453454e4420938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8080000000103907f11',
|
||||
type: 'nulldata'
|
||||
},
|
||||
tokenQty: null
|
||||
},
|
||||
{
|
||||
value: 0.00000546,
|
||||
n: 1,
|
||||
scriptPubKey: {
|
||||
asm: 'OP_DUP OP_HASH160 059775ff94f65c04e8a6847e74eb9809d8cd779b OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a914059775ff94f65c04e8a6847e74eb9809d8cd779b88ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash',
|
||||
addresses: [
|
||||
'bitcoincash:qqzewa0ljnm9cp8g56z8ua8tnqya3nthnvhv5hpu8y'
|
||||
]
|
||||
},
|
||||
tokenQtyStr: '43547.68657',
|
||||
tokenQty: 43547.68657
|
||||
},
|
||||
{
|
||||
value: 0.00054808,
|
||||
n: 2,
|
||||
scriptPubKey: {
|
||||
asm: 'OP_DUP OP_HASH160 0e330dc9009e1e07831f5a22d4ade8977ab674c8 OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a9140e330dc9009e1e07831f5a22d4ade8977ab674c888ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash',
|
||||
addresses: [
|
||||
'bitcoincash:qq8rxrwfqz0pupurradz949dazth4dn5eqs3mhrucv'
|
||||
]
|
||||
},
|
||||
tokenQty: null
|
||||
}
|
||||
],
|
||||
hex: '0100000003f8cda53b43b0ea49991a9bc6c74eb901d2a8b964bc7b8987d76789618ec18c93010000006b483045022100e3d5f9a48f9aa1cf7e9ed1992e0281e7300b734ba0e4bd5bb9265b2be60bd71002200ccde53ce7ea9da9df3e834f234f3bea65c2e58c96f8436f93333fd8946a1db2412102056220984cc2cf5261a27d4f66d31c9ef601a688ca1a5ab81e55b6f0d311be74feffffff34dbf62a45295ae11c2a45f44368218ec64498ac3f7e1434c1993515f53c9dee010000006b483045022100bb90d52be9b568f643fdb1a302e9f063be27a9f914e2a6b192cbabf2cbdeaf9302203c275fc8d1b82390bc1726390d361c5266056bddd54dec23efa207c79eacea4a4121024146cfcd0c02e99d6451dc48ad0f97114aeda18fe55c52a10bfc0490f314e6a2feffffff34dbf62a45295ae11c2a45f44368218ec64498ac3f7e1434c1993515f53c9dee030000006a473044022029ab770c249f467b40bb90410429f6d657f9be299baa19a6838d04d972436b450220143660297e8e836bc16d317649fad8c310bdadb4fb61d4e9f6ba11203abe5dae412102eed4ac9dda3405d9b1ccbbf09f8056f3e7c615924274bd5643238b543d0a1d56feffffff030000000000000000376a04534c500001010453454e4420938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8080000000103907f1122020000000000001976a914059775ff94f65c04e8a6847e74eb9809d8cd779b88ac18d60000000000001976a9140e330dc9009e1e07831f5a22d4ade8977ab674c888ac7d4b0800',
|
||||
blockhash: '00000000000000000140f0d813052da59c811a936494a8d8b2d60b215d19e3dc',
|
||||
confirmations: 167007,
|
||||
time: 1534391953,
|
||||
blocktime: 1534391953,
|
||||
isValidSLPTx: true,
|
||||
tokenTxType: 'SEND',
|
||||
tokenId: '938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8',
|
||||
tokenTicker: 'Bubb2',
|
||||
tokenName: 'the new bubbles!',
|
||||
tokenDecimals: 5,
|
||||
tokenUri: '',
|
||||
tokenDocHash: ''
|
||||
}
|
||||
|
||||
const genesisTestOpReturnData01 = {
|
||||
tokenType: 1,
|
||||
txType: 'SEND',
|
||||
tokenId: '323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d35',
|
||||
amounts: ['5000000', '5000000']
|
||||
}
|
||||
|
||||
genesisTestOpReturnData02 = {
|
||||
const genesisTestOpReturnData02 = {
|
||||
tokenType: 1,
|
||||
txType: 'GENESIS',
|
||||
ticker: '',
|
||||
@@ -286,6 +389,175 @@ genesisTestOpReturnData02 = {
|
||||
qty: '10000000'
|
||||
}
|
||||
|
||||
const mintTestOpReturnData01 = {
|
||||
tokenType: 1,
|
||||
txType: 'SEND',
|
||||
tokenId: '938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8',
|
||||
amounts: [
|
||||
'4354768657'
|
||||
]
|
||||
}
|
||||
|
||||
const mintTestOpReturnData02 = {
|
||||
tokenType: 1,
|
||||
txType: 'GENESIS',
|
||||
ticker: 'Bubb2',
|
||||
name: 'the new bubbles!',
|
||||
tokenId: '938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8',
|
||||
documentUri: '',
|
||||
documentHash: '',
|
||||
decimals: 5,
|
||||
mintBatonVout: 2,
|
||||
qty: '4354534534'
|
||||
}
|
||||
|
||||
const mintTestOpReturnData03 = {
|
||||
tokenType: 1,
|
||||
txType: 'MINT',
|
||||
tokenId: '938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8',
|
||||
mintBatonVout: 2,
|
||||
qty: '234123'
|
||||
}
|
||||
|
||||
const sendTestInputTx01 = {
|
||||
txid: '6bc111fbf5b118021d68355ca19a0e77fa358dd931f284b2550f79a51ab4792a',
|
||||
hash: '6bc111fbf5b118021d68355ca19a0e77fa358dd931f284b2550f79a51ab4792a',
|
||||
version: 1,
|
||||
size: 627,
|
||||
locktime: 543956,
|
||||
vin: [
|
||||
{
|
||||
txid: 'b36b0c7485ad569b98cc9b9614dc68a5208495f22ec3b00effcf963b135a5215',
|
||||
vout: 1,
|
||||
scriptSig: {
|
||||
asm: '3045022100934ca9732bf6c1b146f09e6198142a79a80788b576c6b94e2052df5bcdc86ad902205ef6205192200ea93f6c97f966b838ee785529b694eb61e576e3452470613847[ALL|FORKID] 02b23484341cf36ec00184e045d54e6ffca97da7a8f8a6fd719cead192132306b1',
|
||||
hex: '483045022100934ca9732bf6c1b146f09e6198142a79a80788b576c6b94e2052df5bcdc86ad902205ef6205192200ea93f6c97f966b838ee785529b694eb61e576e3452470613847412102b23484341cf36ec00184e045d54e6ffca97da7a8f8a6fd719cead192132306b1'
|
||||
},
|
||||
sequence: 4294967294,
|
||||
address: 'bitcoincash:qqxj7p2jatt8h3tcpadyxw8a2mr7myqk2qm57u4rdf',
|
||||
value: 0.00000546
|
||||
},
|
||||
{
|
||||
txid: 'b36b0c7485ad569b98cc9b9614dc68a5208495f22ec3b00effcf963b135a5215',
|
||||
vout: 3,
|
||||
scriptSig: {
|
||||
asm: '3044022004d4a95658ef140561ae3a936fb01511778a5376a499bcd6f47b64074a6ca4430220273a4bf553ca17c7e10f393582f980e17a6a98ada867633faad9dbcc595dfd23[ALL|FORKID] 0324fe3b895cfa09523e8ec529eb15c681e3a20f96df85175c54a952b68ac018df',
|
||||
hex: '473044022004d4a95658ef140561ae3a936fb01511778a5376a499bcd6f47b64074a6ca4430220273a4bf553ca17c7e10f393582f980e17a6a98ada867633faad9dbcc595dfd2341210324fe3b895cfa09523e8ec529eb15c681e3a20f96df85175c54a952b68ac018df'
|
||||
},
|
||||
sequence: 4294967294,
|
||||
address: 'bitcoincash:qrcdncgpnv3s8lekcamv4yekp8sghnk37qtsxdyzla',
|
||||
value: 0.00153976
|
||||
},
|
||||
{
|
||||
txid: '95d460512143b636bbc5780d8b27b04fca3bfd2f22003ab48da594e2bab9cfc1',
|
||||
vout: 2,
|
||||
scriptSig: {
|
||||
asm: '3044022079f239216f8d806a084221e841227e55d23a1b90aaf5b5ab54d6f865fbeacf8b022053568f10afc00459af083e4c77d0b85229eb8973a1de406aaa699557f05c7fed[ALL|FORKID] 02035f98ff79d6f3a8ec5a2738c103bbb7796e94fcaffdfaae8f5b7a7fae5d93e3',
|
||||
hex: '473044022079f239216f8d806a084221e841227e55d23a1b90aaf5b5ab54d6f865fbeacf8b022053568f10afc00459af083e4c77d0b85229eb8973a1de406aaa699557f05c7fed412102035f98ff79d6f3a8ec5a2738c103bbb7796e94fcaffdfaae8f5b7a7fae5d93e3'
|
||||
},
|
||||
sequence: 4294967294,
|
||||
address: 'bitcoincash:qrcukahsm53lsywcdarehh73vqazpdu8zv547nym9g',
|
||||
value: 0.00000546
|
||||
}
|
||||
],
|
||||
vout: [
|
||||
{
|
||||
value: 0,
|
||||
n: 0,
|
||||
scriptPubKey: {
|
||||
asm: 'OP_RETURN 5262419 1 1145980243 550d19eb820e616a54b8a73372c4420b5a0567d8dc00f613b71c5234dc884b35 00005af3107a4000 004657febe8d8000',
|
||||
hex: '6a04534c500001010453454e4420550d19eb820e616a54b8a73372c4420b5a0567d8dc00f613b71c5234dc884b350800005af3107a400008004657febe8d8000',
|
||||
type: 'nulldata'
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0.00000546,
|
||||
n: 1,
|
||||
scriptPubKey: {
|
||||
asm: 'OP_DUP OP_HASH160 268dadd7c7becc11782ad3d956342442d8eae92a OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a914268dadd7c7becc11782ad3d956342442d8eae92a88ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash',
|
||||
addresses: [
|
||||
'bitcoincash:qqngmtwhc7lvcytc9tfaj435y3pd36hf9gtdq8nsuu'
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0.00000546,
|
||||
n: 2,
|
||||
scriptPubKey: {
|
||||
asm: 'OP_DUP OP_HASH160 9fb45b370f9ff38a775ee95cabcad7615817924e OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a9149fb45b370f9ff38a775ee95cabcad7615817924e88ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash',
|
||||
addresses: [
|
||||
'bitcoincash:qz0mgkehp70l8znhtm54e2726as4s9ujfc9s2szctr'
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0.00153347,
|
||||
n: 3,
|
||||
scriptPubKey: {
|
||||
asm: 'OP_DUP OP_HASH160 9fb45b370f9ff38a775ee95cabcad7615817924e OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a9149fb45b370f9ff38a775ee95cabcad7615817924e88ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash',
|
||||
addresses: [
|
||||
'bitcoincash:qz0mgkehp70l8znhtm54e2726as4s9ujfc9s2szctr'
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
hex: '010000000315525a133b96cfff0eb0c32ef2958420a568dc14969bcc989b56ad85740c6bb3010000006b483045022100934ca9732bf6c1b146f09e6198142a79a80788b576c6b94e2052df5bcdc86ad902205ef6205192200ea93f6c97f966b838ee785529b694eb61e576e3452470613847412102b23484341cf36ec00184e045d54e6ffca97da7a8f8a6fd719cead192132306b1feffffff15525a133b96cfff0eb0c32ef2958420a568dc14969bcc989b56ad85740c6bb3030000006a473044022004d4a95658ef140561ae3a936fb01511778a5376a499bcd6f47b64074a6ca4430220273a4bf553ca17c7e10f393582f980e17a6a98ada867633faad9dbcc595dfd2341210324fe3b895cfa09523e8ec529eb15c681e3a20f96df85175c54a952b68ac018dffeffffffc1cfb9bae294a58db43a00222ffd3bca4fb0278b0d78c5bb36b643215160d495020000006a473044022079f239216f8d806a084221e841227e55d23a1b90aaf5b5ab54d6f865fbeacf8b022053568f10afc00459af083e4c77d0b85229eb8973a1de406aaa699557f05c7fed412102035f98ff79d6f3a8ec5a2738c103bbb7796e94fcaffdfaae8f5b7a7fae5d93e3feffffff040000000000000000406a04534c500001010453454e4420550d19eb820e616a54b8a73372c4420b5a0567d8dc00f613b71c5234dc884b350800005af3107a400008004657febe8d800022020000000000001976a914268dadd7c7becc11782ad3d956342442d8eae92a88ac22020000000000001976a9149fb45b370f9ff38a775ee95cabcad7615817924e88ac03570200000000001976a9149fb45b370f9ff38a775ee95cabcad7615817924e88acd44c0800',
|
||||
blockhash: '000000000000000001882548bbd9a41bc53a039634f2afa4a12d653434347d04',
|
||||
confirmations: 166670,
|
||||
time: 1534593905,
|
||||
blocktime: 1534593905
|
||||
}
|
||||
|
||||
const sendTestOpReturnData01 = {
|
||||
tokenType: 1,
|
||||
txType: 'SEND',
|
||||
tokenId: '550d19eb820e616a54b8a73372c4420b5a0567d8dc00f613b71c5234dc884b35',
|
||||
amounts: [
|
||||
'100000000000000',
|
||||
'19800000000000000'
|
||||
]
|
||||
}
|
||||
|
||||
const sendTestOpReturnData02 = {
|
||||
tokenType: 1,
|
||||
txType: 'GENESIS',
|
||||
ticker: 'USDT',
|
||||
name: 'Tether Ltd. US dollar backed tokens',
|
||||
tokenId: '550d19eb820e616a54b8a73372c4420b5a0567d8dc00f613b71c5234dc884b35',
|
||||
documentUri: 'https://tether.to/wp-content/uploads/2016/06/TetherWhitePaper.pdf',
|
||||
documentHash: '�DQ�\u001e�3�\u0006p���pM�\u0001\u0017�pW(;\u0003,��wy19\u0016',
|
||||
decimals: 8,
|
||||
mintBatonVout: 2,
|
||||
qty: '10000000000000000'
|
||||
}
|
||||
|
||||
const sendTestOpReturnData03 = {
|
||||
tokenType: 1,
|
||||
txType: 'MINT',
|
||||
tokenId: '550d19eb820e616a54b8a73372c4420b5a0567d8dc00f613b71c5234dc884b35',
|
||||
mintBatonVout: 2,
|
||||
qty: '10000000000000000'
|
||||
}
|
||||
|
||||
const sendTestOpReturnData04 = {
|
||||
tokenType: 1,
|
||||
txType: 'SEND',
|
||||
tokenId: '550d19eb820e616a54b8a73372c4420b5a0567d8dc00f613b71c5234dc884b35',
|
||||
amounts: [
|
||||
'100000000000000',
|
||||
'9900000000000000'
|
||||
]
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
nonSlpTxDetails,
|
||||
slpTxDetails,
|
||||
@@ -293,6 +565,15 @@ module.exports = {
|
||||
mockOpReturnData02,
|
||||
mockOpReturnData03,
|
||||
genesisTestInputTx,
|
||||
mintTestInputTx,
|
||||
genesisTestOpReturnData01,
|
||||
genesisTestOpReturnData02
|
||||
genesisTestOpReturnData02,
|
||||
mintTestOpReturnData01,
|
||||
mintTestOpReturnData02,
|
||||
mintTestOpReturnData03,
|
||||
sendTestInputTx01,
|
||||
sendTestOpReturnData01,
|
||||
sendTestOpReturnData02,
|
||||
sendTestOpReturnData03,
|
||||
sendTestOpReturnData04
|
||||
}
|
||||
|
||||
@@ -164,5 +164,365 @@ describe('#TransactionLib', () => {
|
||||
assert.equal(result.vin[0].tokenQty, 10000000)
|
||||
assert.equal(result.vin[1].tokenQty, null)
|
||||
})
|
||||
|
||||
it('should get input details when input is a mint tx', async () => {
|
||||
// Mock dependencies
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.rawTransaction, 'getTxData')
|
||||
.resolves(mockData.mintTestInputTx)
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.slpUtils, 'decodeOpReturn')
|
||||
.onCall(0)
|
||||
.resolves(mockData.mintTestOpReturnData01)
|
||||
.onCall(1)
|
||||
.resolves(mockData.mintTestOpReturnData02)
|
||||
.onCall(2)
|
||||
.resolves(mockData.mintTestOpReturnData02)
|
||||
.onCall(3)
|
||||
.resolves(mockData.mintTestOpReturnData03)
|
||||
.onCall(4)
|
||||
.resolves(mockData.mintTestOpReturnData03)
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.slpUtils, 'waterfallValidateTxid')
|
||||
.resolves(true)
|
||||
|
||||
const txid =
|
||||
'4640a734063ea79fa587a3cac38a70a2f6f3db0011e23514024185982110d0fa'
|
||||
|
||||
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 Mint input have the proper values.
|
||||
assert.equal(result.vin[0].tokenQty, 43545.34534)
|
||||
assert.equal(result.vin[1].tokenQty, 2.34123)
|
||||
assert.equal(result.vin[2].tokenQty, null)
|
||||
})
|
||||
|
||||
// This test case was generated from the problematic transaction that
|
||||
// used inputs in a 'non-standard' way.
|
||||
it('should correctly assign quantities to mixed mint inputs', async () => {
|
||||
// Mock dependencies
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.rawTransaction, 'getTxData')
|
||||
.resolves(mockData.sendTestInputTx01)
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.slpUtils, 'decodeOpReturn')
|
||||
.onCall(0)
|
||||
.resolves(mockData.sendTestOpReturnData01)
|
||||
.onCall(1)
|
||||
.resolves(mockData.sendTestOpReturnData02)
|
||||
.onCall(2)
|
||||
.resolves(mockData.sendTestOpReturnData03)
|
||||
.onCall(3)
|
||||
.resolves(mockData.sendTestOpReturnData03)
|
||||
.onCall(4)
|
||||
.resolves(mockData.sendTestOpReturnData04)
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.slpUtils, 'waterfallValidateTxid')
|
||||
.resolves(true)
|
||||
|
||||
const txid =
|
||||
'6bc111fbf5b118021d68355ca19a0e77fa358dd931f284b2550f79a51ab4792a'
|
||||
|
||||
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 Mint input have the proper values.
|
||||
assert.equal(result.vin[0].tokenQty, 100000000)
|
||||
assert.equal(result.vin[1].tokenQty, null)
|
||||
assert.equal(result.vin[2].tokenQty, 99000000)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#get2', () => {
|
||||
it('should throw an error if txid is not specified', async () => {
|
||||
try {
|
||||
await bchjs.Transaction.get2()
|
||||
|
||||
assert.fail('Unexpected code path!')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Input to Transaction.get() must be a string containing a TXID.'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('should get details about a non-SLP transaction', async () => {
|
||||
const txid =
|
||||
'2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7'
|
||||
|
||||
// Mock dependencies
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.rawTransaction, 'getTxData')
|
||||
.resolves(mockData.nonSlpTxDetails)
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.blockchain, 'getBlockHeader')
|
||||
.resolves({ height: 602405 })
|
||||
|
||||
const result = await bchjs.Transaction.get2(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[0].scriptPubKey, 'addresses')
|
||||
|
||||
// Assert that added properties exist.
|
||||
assert.property(result.vin[0], 'address')
|
||||
assert.property(result.vin[0], 'value')
|
||||
assert.property(result, 'isValidSLPTx')
|
||||
assert.equal(result.isValidSLPTx, false)
|
||||
|
||||
// Assert blockheight is added
|
||||
assert.equal(result.blockheight, 602405)
|
||||
})
|
||||
|
||||
it('should get details about a SLP transaction', async () => {
|
||||
// Mock dependencies
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.rawTransaction, 'getTxData')
|
||||
.resolves(mockData.slpTxDetails)
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.blockchain, 'getBlockHeader')
|
||||
.resolves({ height: 603424 })
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.slpUtils, 'decodeOpReturn')
|
||||
.onCall(0)
|
||||
.resolves(mockData.mockOpReturnData01)
|
||||
.onCall(1)
|
||||
.resolves(mockData.mockOpReturnData02)
|
||||
.onCall(2)
|
||||
.resolves(mockData.mockOpReturnData03)
|
||||
.onCall(3)
|
||||
.rejects(new Error('No OP_RETURN'))
|
||||
|
||||
const txid =
|
||||
'266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1'
|
||||
|
||||
const result = await bchjs.Transaction.get2(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 blockheight is added
|
||||
assert.equal(result.blockheight, 603424)
|
||||
})
|
||||
|
||||
it('should catch and throw error on network error', async () => {
|
||||
try {
|
||||
const txid =
|
||||
'2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7'
|
||||
|
||||
// Force an error
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.rawTransaction, 'getTxData')
|
||||
.rejects(new Error('test error'))
|
||||
|
||||
await bchjs.Transaction.get(txid)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
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.blockchain, 'getBlockHeader')
|
||||
.resolves({ height: 543409 })
|
||||
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)
|
||||
|
||||
const txid =
|
||||
'874306bda204d3a5dd15e03ea5732cccdca4c33a52df35162cdd64e30ea7f04e'
|
||||
|
||||
const result = await bchjs.Transaction.get2(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 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)
|
||||
|
||||
// Assert blockheight is added
|
||||
assert.equal(result.blockheight, 543409)
|
||||
})
|
||||
|
||||
it('should get input details when input is a mint tx', async () => {
|
||||
// Mock dependencies
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.rawTransaction, 'getTxData')
|
||||
.resolves(mockData.mintTestInputTx)
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.blockchain, 'getBlockHeader')
|
||||
.resolves({ height: 543614 })
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.slpUtils, 'decodeOpReturn')
|
||||
.onCall(0)
|
||||
.resolves(mockData.mintTestOpReturnData01)
|
||||
.onCall(1)
|
||||
.resolves(mockData.mintTestOpReturnData02)
|
||||
.onCall(2)
|
||||
.resolves(mockData.mintTestOpReturnData02)
|
||||
.onCall(3)
|
||||
.resolves(mockData.mintTestOpReturnData03)
|
||||
.onCall(4)
|
||||
.resolves(mockData.mintTestOpReturnData03)
|
||||
|
||||
const txid =
|
||||
'4640a734063ea79fa587a3cac38a70a2f6f3db0011e23514024185982110d0fa'
|
||||
|
||||
const result = await bchjs.Transaction.get2(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 inputs values unique to a Mint input have the proper values.
|
||||
assert.equal(result.vin[0].tokenQty, 43545.34534)
|
||||
assert.equal(result.vin[1].tokenQty, 2.34123)
|
||||
assert.equal(result.vin[2].tokenQty, null)
|
||||
|
||||
// Assert blockheight is added
|
||||
assert.equal(result.blockheight, 543614)
|
||||
})
|
||||
|
||||
// This test case was generated from the problematic transaction that
|
||||
// used inputs in a 'non-standard' way.
|
||||
it('should correctly assign quantities to mixed mint inputs', async () => {
|
||||
// Mock dependencies
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.rawTransaction, 'getTxData')
|
||||
.resolves(mockData.sendTestInputTx01)
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.blockchain, 'getBlockHeader')
|
||||
.resolves({ height: 543957 })
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.slpUtils, 'decodeOpReturn')
|
||||
.onCall(0)
|
||||
.resolves(mockData.sendTestOpReturnData01)
|
||||
.onCall(1)
|
||||
.resolves(mockData.sendTestOpReturnData02)
|
||||
.onCall(2)
|
||||
.resolves(mockData.sendTestOpReturnData03)
|
||||
.onCall(3)
|
||||
.resolves(mockData.sendTestOpReturnData03)
|
||||
.onCall(4)
|
||||
.resolves(mockData.sendTestOpReturnData04)
|
||||
|
||||
const txid =
|
||||
'6bc111fbf5b118021d68355ca19a0e77fa358dd931f284b2550f79a51ab4792a'
|
||||
|
||||
const result = await bchjs.Transaction.get2(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 inputs values unique to a Mint input have the proper values.
|
||||
assert.equal(result.vin[0].tokenQty, 100000000)
|
||||
assert.equal(result.vin[1].tokenQty, null)
|
||||
assert.equal(result.vin[2].tokenQty, 99000000)
|
||||
|
||||
// Assert blockheight is added
|
||||
assert.equal(result.blockheight, 543957)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user