Changeset View
Changeset View
Standalone View
Standalone View
web/cashtab/src/utils/chronik.js
// Chronik methods | // Chronik methods | ||||
import BigNumber from 'bignumber.js'; | import BigNumber from 'bignumber.js'; | ||||
import { currency } from 'components/Common/Ticker'; | import { currency } from 'components/Common/Ticker'; | ||||
import { | import { | ||||
parseOpReturn, | parseOpReturn, | ||||
convertToEncryptStruct, | convertToEncryptStruct, | ||||
getHashArrayFromWallet, | getHashArrayFromWallet, | ||||
getUtxoWif, | getUtxoWif, | ||||
} from 'utils/cashMethods'; | } from 'utils/cashMethods'; | ||||
import ecies from 'ecies-lite'; | import ecies from 'ecies-lite'; | ||||
import wif from 'wif'; | import wif from 'wif'; | ||||
import cashaddr from 'ecashaddrjs'; | |||||
// Return false if do not get a valid response | // Return false if do not get a valid response | ||||
export const getTokenStats = async (chronik, tokenId) => { | export const getTokenStats = async (chronik, tokenId) => { | ||||
try { | try { | ||||
// token attributes available via chronik's token() method | // token attributes available via chronik's token() method | ||||
let tokenResponseObj = await chronik.token(tokenId); | let tokenResponseObj = await chronik.token(tokenId); | ||||
const tokenDecimals = tokenResponseObj.slpTxData.genesisInfo.decimals; | const tokenDecimals = tokenResponseObj.slpTxData.genesisInfo.decimals; | ||||
▲ Show 20 Lines • Show All 398 Lines • ▼ Show 20 Lines | return new Promise((resolve, reject) => { | ||||
}, | }, | ||||
err => { | err => { | ||||
reject(err); | reject(err); | ||||
}, | }, | ||||
); | ); | ||||
}); | }); | ||||
}; | }; | ||||
export const parseChronikTx = (tx, wallet) => { | export const parseChronikTx = (BCH, tx, wallet) => { | ||||
const walletHash160s = getHashArrayFromWallet(wallet); | const walletHash160s = getHashArrayFromWallet(wallet); | ||||
const { inputs, outputs } = tx; | const { inputs, outputs } = tx; | ||||
// Assign defaults | // Assign defaults | ||||
let incoming = true; | let incoming = true; | ||||
let xecAmount = new BigNumber(0); | let xecAmount = new BigNumber(0); | ||||
let originatingHash160 = ''; | let originatingHash160 = ''; | ||||
let etokenAmount = new BigNumber(0); | let etokenAmount = new BigNumber(0); | ||||
const isEtokenTx = 'slpTxData' in tx && typeof tx.slpTxData !== 'undefined'; | const isEtokenTx = 'slpTxData' in tx && typeof tx.slpTxData !== 'undefined'; | ||||
// Defining variables used in lines legacy parseTxData function from useBCH.js | // Defining variables used in lines legacy parseTxData function from useBCH.js | ||||
let substring = ''; | let substring = ''; | ||||
let airdropFlag = false; | let airdropFlag = false; | ||||
let airdropTokenId = ''; | let airdropTokenId = ''; | ||||
let opReturnMessage = ''; | let opReturnMessage = ''; | ||||
let isCashtabMessage = false; | let isCashtabMessage = false; | ||||
let isEncryptedMessage = false; | let isEncryptedMessage = false; | ||||
let decryptionSuccess = false; | let decryptionSuccess = false; | ||||
let replyAddress = ''; | |||||
// Iterate over inputs to see if this is an incoming tx (incoming === true) | // Iterate over inputs to see if this is an incoming tx (incoming === true) | ||||
for (let i = 0; i < inputs.length; i += 1) { | for (let i = 0; i < inputs.length; i += 1) { | ||||
const thisInput = inputs[i]; | const thisInput = inputs[i]; | ||||
const thisInputSendingHash160 = thisInput.outputScript; | const thisInputSendingHash160 = thisInput.outputScript; | ||||
/* | /* | ||||
Assume the first input is the originating address | Assume the first input is the originating address | ||||
https://en.bitcoin.it/wiki/Script for reference | https://en.bitcoin.it/wiki/Script for reference | ||||
Assume standard pay-to-pubkey-hash tx | Assume standard pay-to-pubkey-hash tx | ||||
scriptPubKey: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG | scriptPubKey: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG | ||||
76 + a9 + 14 = OP_DUP + OP_HASH160 + 14 Bytes to push | 76 + a9 + 14 = OP_DUP + OP_HASH160 + 14 Bytes to push | ||||
88 + ac = OP_EQUALVERIFY + OP_CHECKSIG | 88 + ac = OP_EQUALVERIFY + OP_CHECKSIG | ||||
So, the hash160 we want will be in between '76a914' and '88ac' | So, the hash160 we want will be in between '76a914' and '88ac' | ||||
...most of the time ;) | ...most of the time ;) | ||||
*/ | */ | ||||
try { | try { | ||||
originatingHash160 = thisInputSendingHash160.substring( | originatingHash160 = thisInputSendingHash160.substring( | ||||
thisInputSendingHash160.indexOf('76a914') + '76a914'.length, | thisInputSendingHash160.indexOf('76a914') + '76a914'.length, | ||||
thisInputSendingHash160.lastIndexOf('88ac'), | thisInputSendingHash160.lastIndexOf('88ac'), | ||||
); | ); | ||||
let replyAddressBchFormat = | |||||
BCH.Address.hash160ToCash(originatingHash160); | |||||
const { type, hash } = cashaddr.decode(replyAddressBchFormat); | |||||
replyAddress = cashaddr.encode('ecash', type, hash); | |||||
console.log(`replyAddressXecFormat`, replyAddress); | |||||
} catch (err) { | } catch (err) { | ||||
console.log(`err from ${originatingHash160}`, err); | |||||
// If the transaction is nonstandard, don't worry about a reply address for now | // If the transaction is nonstandard, don't worry about a reply address for now | ||||
originatingHash160 = 'N/A'; | originatingHash160 = 'N/A'; | ||||
} | } | ||||
for (let j = 0; j < walletHash160s.length; j += 1) { | for (let j = 0; j < walletHash160s.length; j += 1) { | ||||
const thisWalletHash160 = walletHash160s[j]; | const thisWalletHash160 = walletHash160s[j]; | ||||
if (thisInputSendingHash160.includes(thisWalletHash160)) { | if (thisInputSendingHash160.includes(thisWalletHash160)) { | ||||
// Then this is an outgoing tx | // Then this is an outgoing tx | ||||
incoming = false; | incoming = false; | ||||
▲ Show 20 Lines • Show All 202 Lines • ▼ Show 20 Lines | if (isEtokenTx) { | ||||
outgoingTx: !incoming, | outgoingTx: !incoming, | ||||
tokenTx: true, | tokenTx: true, | ||||
airdropFlag, | airdropFlag, | ||||
airdropTokenId, | airdropTokenId, | ||||
opReturnMessage: '', | opReturnMessage: '', | ||||
isCashtabMessage, | isCashtabMessage, | ||||
isEncryptedMessage, | isEncryptedMessage, | ||||
decryptionSuccess, | decryptionSuccess, | ||||
replyAddress, | |||||
}, | }, | ||||
}; | }; | ||||
} | } | ||||
// Otherwise do not include these fields | // Otherwise do not include these fields | ||||
return { | return { | ||||
incoming, | incoming, | ||||
xecAmount, | xecAmount, | ||||
originatingHash160, | originatingHash160, | ||||
isEtokenTx, | isEtokenTx, | ||||
legacy: { | legacy: { | ||||
amountSent: incoming ? 0 : xecAmount, | amountSent: incoming ? 0 : xecAmount, | ||||
amountReceived: incoming ? xecAmount : 0, | amountReceived: incoming ? xecAmount : 0, | ||||
outgoingTx: !incoming, | outgoingTx: !incoming, | ||||
tokenTx: false, | tokenTx: false, | ||||
airdropFlag, | airdropFlag, | ||||
airdropTokenId, | airdropTokenId, | ||||
opReturnMessage, | opReturnMessage, | ||||
isCashtabMessage, | isCashtabMessage, | ||||
isEncryptedMessage, | isEncryptedMessage, | ||||
decryptionSuccess, | decryptionSuccess, | ||||
replyAddress, | |||||
}, | }, | ||||
}; | }; | ||||
}; | }; | ||||
export const getTxHistoryChronik = async (chronik, wallet) => { | export const getTxHistoryChronik = async (chronik, BCH, wallet) => { | ||||
// Create array of promises to get chronik history for each address | // Create array of promises to get chronik history for each address | ||||
// Combine them all and sort by blockheight and firstSeen | // Combine them all and sort by blockheight and firstSeen | ||||
// Add all the info cashtab needs to make them useful | // Add all the info cashtab needs to make them useful | ||||
const hash160AndAddressObjArray = [ | const hash160AndAddressObjArray = [ | ||||
{ | { | ||||
address: wallet.Path145.cashAddress, | address: wallet.Path145.cashAddress, | ||||
hash160: wallet.Path145.hash160, | hash160: wallet.Path145.hash160, | ||||
Show All 29 Lines | const sortedTxHistoryArray = sortAndTrimChronikTxHistory( | ||||
flatTxHistoryArray, | flatTxHistoryArray, | ||||
currency.txHistoryCount, | currency.txHistoryCount, | ||||
); | ); | ||||
// Parse txs | // Parse txs | ||||
const parsedTxs = []; | const parsedTxs = []; | ||||
for (let i = 0; i < sortedTxHistoryArray.length; i += 1) { | for (let i = 0; i < sortedTxHistoryArray.length; i += 1) { | ||||
const sortedTx = sortedTxHistoryArray[i]; | const sortedTx = sortedTxHistoryArray[i]; | ||||
sortedTx.parsed = parseChronikTx(sortedTx, wallet); | sortedTx.parsed = parseChronikTx(BCH, sortedTx, wallet); | ||||
parsedTxs.push(sortedTx); | parsedTxs.push(sortedTx); | ||||
} | } | ||||
return parsedTxs; | return parsedTxs; | ||||
}; | }; |