Making progress on Transaction.get3()

This commit is contained in:
Chris Troutner
2021-11-03 07:53:42 -07:00
parent 92960b6957
commit dc85bb4cfe
3 changed files with 332 additions and 59 deletions
+231
View File
@@ -435,6 +435,237 @@ class Transaction {
throw err
}
}
// Refactoring code in a more structured way
async get3(txid) {
try {
if (typeof txid !== 'string') {
throw new Error(
'Input to Transaction.get() must be a string containing a TXID.'
)
}
// Get TX data
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
// Set default as not an SLP tx
txDetails.isSlpTx = false
// Get Token Data
const txTokenData = await this.getTokenInfo(txid)
console.log(`txTokenData: ${JSON.stringify(txTokenData, null, 2)}`)
// If not a token, return the tx data. Processing is complete.
if(!txTokenData) return txDetails
// Mark TX as an SLP tx. This does not mean it's valid, it just means
// the OP_RETURN passes a basic check.
txDetails.isSlpTx = true
// Get Genesis data
const genesisData = await this.getTokenInfo(txTokenData.tokenId)
console.log(`genesisData: ${JSON.stringify(genesisData, null, 2)}`)
// Add token information to the tx details object.
txDetails.tokenTxType = txTokenData.txType
txDetails.tokenId = txTokenData.tokenId
txDetails.tokenTicker = genesisData.ticker
txDetails.tokenName = genesisData.name
txDetails.tokenDecimals = genesisData.decimals
txDetails.tokenUri = genesisData.documentUri
txDetails.tokenDocHash = genesisData.documentHash
// console.log(`txDetails before processing input and outputs: ${JSON.stringify(txDetails, null, 2)}`)
// Process TX Outputs
// Add the token quantity to each output.
// 'i' starts at 1, because vout[0] is the OP_RETURN
for (let i = 0; i < txDetails.vout.length; i++) {
const thisVout = txDetails.vout[i]
if (txTokenData.txType === 'SEND') {
console.log(`txTokenData: ${JSON.stringify(txTokenData, null, 2)}`)
// First output is OP_RETURN, so tokenQty is null.
if(i === 0) {
thisVout.tokenQty = null
thisVout.tokenQtyStr = null
continue
}
// Non SLP outputs.
if(i > txTokenData.amounts.length) {
thisVout.tokenQty = null
thisVout.tokenQtyStr = null
continue
}
const rawQty = txTokenData.amounts[i-1]
// 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].tokenQtyStr = realQty
txDetails.vout[i].tokenQty = parseFloat(realQty)
console.log(
`thisVout ${i}: ${JSON.stringify(txDetails.vout[i], null, 2)}`
)
} else if(txTokenData.txType === 'GENESIS' || txTokenData.txType === 'MINT') {
console.log(`txTokenData: ${JSON.stringify(txTokenData, null, 2)}`)
let tokenQty = 0 // Default value
// Only vout[1] of a Genesis or Mint transaction represents the tokens.
// Any other outputs in that transaction are normal BCH UTXOs.
if (i === 1) {
tokenQty = txTokenData.qty
console.log(`tokenQty: ${JSON.stringify(tokenQty, null, 2)}`)
// 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)
thisVout.tokenQtyStr = realQty
thisVout.tokenQty = parseFloat(realQty)
console.log(`thisVout[${i}]: ${JSON.stringify(thisVout, null, 2)}`)
} else if(i === txTokenData.mintBatonVout) {
// Optional Mint baton
thisVout.tokenQtyStr = "0"
thisVout.tokenQty = 0
thisVout.isMintBaton = true
} else {
thisVout.tokenQtyStr = "0"
thisVout.tokenQty = 0
}
} else {
throw new Error('Unknown SLP TX type for TX')
}
}
// Process TX inputs
for(let i=0; i < txDetails.vin.length; i++) {
const thisVin = txDetails.vin[i]
const vinTokenData = await this.getTokenInfo(thisVin.txid)
console.log(`vinTokenData: ${JSON.stringify(vinTokenData, null, 2)}`)
// Corner case: Ensure the token ID is the same.
const vinTokenIdIsTheSame = vinTokenData.tokenId === txDetails.tokenId
// If the input is not a token input, or if the tokenID is not the same,
// then mark the token output as null.
if(!vinTokenData || !vinTokenIdIsTheSame) {
thisVin.tokenQty = 0
thisVin.tokenQtyStr = "0"
thisVin.tokenId = null
continue
}
if(vinTokenData.txType === 'SEND') {
console.log(`vinTokenData: ${JSON.stringify(vinTokenData, null, 2)}`)
const tokenQty = vinTokenData.amounts[thisVin.vout - 1]
// console.log(`tokenQty: ${JSON.stringify(tokenQty, null, 2)}`)
// 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)
thisVin.tokenId = vinTokenData.tokenId
} else if(vinTokenData.txType === 'GENESIS' || vinTokenData.txType === 'MINT') {
console.log(`vinTokenData: ${JSON.stringify(vinTokenData, null, 2)}`)
let tokenQty = 0 // Default value
// 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 = vinTokenData.qty
// console.log(`tokenQty: ${JSON.stringify(tokenQty, null, 2)}`)
// 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)
thisVin.tokenId = vinTokenData.tokenId
} else if(thisVin.vout === vinTokenData.mintBatonVout) {
// Optional Mint baton
thisVin.tokenQtyStr = "0"
thisVin.tokenQty = 0
thisVin.tokenId = vinTokenData.tokenId
thisVin.isMintBaton = true
} else {
thisVin.tokenQtyStr = "0"
thisVin.tokenQty = 0
thisVin.tokenId = null
}
} else {
console.log(`vinTokenData: ${JSON.stringify(vinTokenData, null, 2)}`)
throw new Error('Unknown token type in input')
}
}
// if SEND
// if GENSIS
// if MINT
// Update Inputs
// if not SLP
// Ensure tokenID matches
// if SEND
// if GENESIS
// if MINT
return txDetails
} catch(err) {
console.error('Error in get3()')
// 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
}
}
// A wrapper for decodeOpReturn(). Returns false if txid is not an SLP tx.
// Returns the token data if the txid is an SLP tx.
async getTokenInfo (txid) {
try {
const tokenData = await this.slpUtils.decodeOpReturn(txid)
return tokenData
} catch(err) {
return false
}
}
}
module.exports = Transaction