Changeset View
Changeset View
Standalone View
Standalone View
web/cashtab/src/hooks/useBCH.js
import BigNumber from 'bignumber.js'; | import BigNumber from 'bignumber.js'; | ||||
import { currency } from '@components/Common/Ticker'; | import { | ||||
currency, | |||||
isCashtabOutput, | |||||
isEtokenOutput, | |||||
extractCashtabMessage, | |||||
extractExternalMessage, | |||||
} from '@components/Common/Ticker'; | |||||
import { isValidTokenStats } from '@utils/validation'; | import { isValidTokenStats } from '@utils/validation'; | ||||
import SlpWallet from 'minimal-slp-wallet'; | import SlpWallet from 'minimal-slp-wallet'; | ||||
import { | import { | ||||
toSmallestDenomination, | toSmallestDenomination, | ||||
fromSmallestDenomination, | fromSmallestDenomination, | ||||
batchArray, | batchArray, | ||||
flattenBatchedHydratedUtxos, | flattenBatchedHydratedUtxos, | ||||
isValidStoredWallet, | isValidStoredWallet, | ||||
Show All 14 Lines | const getRestUrl = (apiIndex = 0) => { | ||||
const apiString = | const apiString = | ||||
process.env.REACT_APP_NETWORK === `mainnet` | process.env.REACT_APP_NETWORK === `mainnet` | ||||
? process.env.REACT_APP_BCHA_APIS | ? process.env.REACT_APP_BCHA_APIS | ||||
: process.env.REACT_APP_BCHA_APIS_TEST; | : process.env.REACT_APP_BCHA_APIS_TEST; | ||||
const apiArray = apiString.split(','); | const apiArray = apiString.split(','); | ||||
return apiArray[apiIndex]; | return apiArray[apiIndex]; | ||||
}; | }; | ||||
// filter out prefixes for OP_RETURN encoded messages | |||||
// Note: only for use with encoded message strings | |||||
const removeOpReturnPrefixes = asmStr => { | |||||
if (asmStr.includes(' 621')) { | |||||
//strip out the 621 (6d02) prefix if exists | |||||
asmStr = asmStr.replace(' 621', ''); | |||||
} | |||||
return asmStr; | |||||
}; | |||||
const flattenTransactions = ( | const flattenTransactions = ( | ||||
txHistory, | txHistory, | ||||
txCount = currency.txHistoryCount, | txCount = currency.txHistoryCount, | ||||
) => { | ) => { | ||||
/* | /* | ||||
Convert txHistory, format | Convert txHistory, format | ||||
[{address: '', transactions: [{height: '', tx_hash: ''}, ...{}]}, {}, {}] | [{address: '', transactions: [{height: '', tx_hash: ''}, ...{}]}, {}, {}] | ||||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | const parseTxData = txData => { | ||||
continue; | continue; | ||||
} | } | ||||
parsedTx.confirmations = tx.confirmations; | parsedTx.confirmations = tx.confirmations; | ||||
parsedTx.blocktime = tx.blocktime; | parsedTx.blocktime = tx.blocktime; | ||||
let amountSent = 0; | let amountSent = 0; | ||||
let amountReceived = 0; | let amountReceived = 0; | ||||
let opReturnMessage = ''; | let opReturnMessage = ''; | ||||
let isCashtabMessage = false; | |||||
// Assume an incoming transaction | // Assume an incoming transaction | ||||
let outgoingTx = false; | let outgoingTx = false; | ||||
let tokenTx = false; | let tokenTx = false; | ||||
let substring = ''; | |||||
// If vin includes tx address, this is an outgoing tx | // If vin includes tx address, this is an outgoing tx | ||||
// Note that with bch-input data, we do not have input amounts | // Note that with bch-input data, we do not have input amounts | ||||
for (let j = 0; j < tx.vin.length; j += 1) { | for (let j = 0; j < tx.vin.length; j += 1) { | ||||
const thisInput = tx.vin[j]; | const thisInput = tx.vin[j]; | ||||
if (thisInput.address === tx.address) { | if (thisInput.address === tx.address) { | ||||
// This is an outgoing transaction | // This is an outgoing transaction | ||||
outgoingTx = true; | outgoingTx = true; | ||||
} | } | ||||
} | } | ||||
// Iterate over vout to find how much was sent or received | // Iterate over vout to find how much was sent or received | ||||
for (let j = 0; j < tx.vout.length; j += 1) { | for (let j = 0; j < tx.vout.length; j += 1) { | ||||
const thisOutput = tx.vout[j]; | const thisOutput = tx.vout[j]; | ||||
// If there is no addresses object in the output, it's either an OP_RETURN msg or token tx | // If there is no addresses object in the output, it's either an OP_RETURN msg or token tx | ||||
if ( | if ( | ||||
!Object.keys(thisOutput.scriptPubKey).includes('addresses') | !Object.keys(thisOutput.scriptPubKey).includes('addresses') | ||||
) { | ) { | ||||
let asm = thisOutput.scriptPubKey.asm; | let hex = thisOutput.scriptPubKey.hex; | ||||
if (asm.includes('OP_RETURN 5262419')) { | |||||
// assume this is an eToken tx for now | if (isEtokenOutput(hex)) { | ||||
// future diffs will add additional NFT parsing logic in this segment | // this is an eToken transaction | ||||
tokenTx = true; | tokenTx = true; | ||||
} else if (isCashtabOutput(hex)) { | |||||
// this is a cashtab.com generated message | |||||
try { | |||||
substring = extractCashtabMessage(hex); | |||||
opReturnMessage = Buffer.from(substring, 'hex'); | |||||
isCashtabMessage = true; | |||||
} catch (err) { | |||||
// soft error if an unexpected or invalid cashtab hex is encountered | |||||
opReturnMessage = ''; | |||||
console.log( | |||||
'useBCH.parsedTxHistory() error: invalid cashtab msg hex: ' + | |||||
substring, | |||||
); | |||||
} | |||||
} else { | } else { | ||||
// if this is not an eToken tx and does not contain addresses, then assume encoded message | // this is an externally generated message | ||||
asm = removeOpReturnPrefixes(asm); | |||||
let msgBody = asm.substr(asm.indexOf(' ') + 1); // extract everything after the OP_RETURN opcode | |||||
try { | try { | ||||
opReturnMessage = Buffer.from(msgBody, 'hex'); | substring = extractExternalMessage(hex); | ||||
opReturnMessage = Buffer.from(substring, 'hex'); | |||||
} catch (err) { | } catch (err) { | ||||
// soft error if an unexpected or invalid cashtab hex is encountered | |||||
opReturnMessage = ''; | opReturnMessage = ''; | ||||
console.log( | |||||
'useBCH.parsedTxHistory() error: invalid external msg hex: ' + | |||||
substring, | |||||
); | |||||
} | } | ||||
} | } | ||||
continue; // skipping the remainder of tx data parsing logic in both token and OP_RETURN tx cases | continue; // skipping the remainder of tx data parsing logic in both token and OP_RETURN tx cases | ||||
} | } | ||||
if ( | if ( | ||||
thisOutput.scriptPubKey.addresses && | thisOutput.scriptPubKey.addresses && | ||||
thisOutput.scriptPubKey.addresses[0] === tx.address | thisOutput.scriptPubKey.addresses[0] === tx.address | ||||
) { | ) { | ||||
Show All 10 Lines | const parseTxData = txData => { | ||||
} | } | ||||
// Construct parsedTx | // Construct parsedTx | ||||
parsedTx.amountSent = amountSent; | parsedTx.amountSent = amountSent; | ||||
parsedTx.amountReceived = amountReceived; | parsedTx.amountReceived = amountReceived; | ||||
parsedTx.tokenTx = tokenTx; | parsedTx.tokenTx = tokenTx; | ||||
parsedTx.outgoingTx = outgoingTx; | parsedTx.outgoingTx = outgoingTx; | ||||
parsedTx.destinationAddress = destinationAddress; | parsedTx.destinationAddress = destinationAddress; | ||||
parsedTx.opReturnMessage = opReturnMessage; | parsedTx.opReturnMessage = opReturnMessage; | ||||
parsedTx.isCashtabMessage = isCashtabMessage; | |||||
parsedTxHistory.push(parsedTx); | parsedTxHistory.push(parsedTx); | ||||
} | } | ||||
return parsedTxHistory; | return parsedTxHistory; | ||||
}; | }; | ||||
const getTxHistory = async (BCH, addresses) => { | const getTxHistory = async (BCH, addresses) => { | ||||
let txHistoryResponse; | let txHistoryResponse; | ||||
try { | try { | ||||
▲ Show 20 Lines • Show All 786 Lines • ▼ Show 20 Lines | ) => { | ||||
// Start of building the OP_RETURN output. | // Start of building the OP_RETURN output. | ||||
// only build the OP_RETURN output if the user supplied it | // only build the OP_RETURN output if the user supplied it | ||||
if ( | if ( | ||||
typeof optionalOpReturnMsg !== 'undefined' && | typeof optionalOpReturnMsg !== 'undefined' && | ||||
optionalOpReturnMsg.trim() !== '' | optionalOpReturnMsg.trim() !== '' | ||||
) { | ) { | ||||
const script = [ | const script = [ | ||||
BCH.Script.opcodes.OP_RETURN, | BCH.Script.opcodes.OP_RETURN, // 6a | ||||
Buffer.from('6d02', 'hex'), | Buffer.from( | ||||
currency.opReturn.appPrefixesHex.cashtab, | |||||
'hex', | |||||
), // 00746162 | |||||
Buffer.from(optionalOpReturnMsg), | Buffer.from(optionalOpReturnMsg), | ||||
]; | ]; | ||||
const data = BCH.Script.encode(script); | const data = BCH.Script.encode(script); | ||||
transactionBuilder.addOutput(data, 0); | transactionBuilder.addOutput(data, 0); | ||||
} | } | ||||
// End of building the OP_RETURN output. | // End of building the OP_RETURN output. | ||||
let originalAmount = new BigNumber(0); | let originalAmount = new BigNumber(0); | ||||
▲ Show 20 Lines • Show All 135 Lines • Show Last 20 Lines |