diff --git a/web/cashtab/src/components/Common/Ticker.js b/web/cashtab/src/components/Common/Ticker.js index 08c5b4b2c..63b825365 100644 --- a/web/cashtab/src/components/Common/Ticker.js +++ b/web/cashtab/src/components/Common/Ticker.js @@ -1,142 +1,143 @@ import mainLogo from '@assets/12-bitcoin-cash-square-crop.svg'; import tokenLogo from '@assets/simple-ledger-protocol-logo.png'; import cashaddr from 'cashaddrjs'; import BigNumber from 'bignumber.js'; export const currency = { name: 'Bitcoin ABC', ticker: 'BCHA', logo: mainLogo, legacyPrefix: 'bitcoincash', prefixes: ['bitcoincash', 'ecash'], coingeckoId: 'bitcoin-cash-abc-2', defaultFee: 5.01, dust: '0.00000546', // The minimum amount of BCHA that can be sent by the app cashDecimals: 8, blockExplorerUrl: 'https://explorer.bitcoinabc.org', blockExplorerUrlTestnet: 'https://texplorer.bitcoinabc.org', tokenName: 'Bitcoin ABC SLP', tokenTicker: 'SLPA', tokenLogo: tokenLogo, tokenPrefixes: ['simpleledger', 'etoken'], tokenIconsUrl: '', //https://tokens.bitcoin.com/32 for BCH SLP useBlockchainWs: false, txHistoryCount: 5, + hydrateUtxoBatchSize: 20, }; export function isValidCashPrefix(addressString) { // Note that this function validates prefix only // Check for prefix included in currency.prefixes array // For now, validation is handled by converting to bitcoincash: prefix and checksum // and relying on legacy validation methods of bitcoincash: prefix addresses // Also accept an address with no prefix, as some exchanges provide these for (let i = 0; i < currency.prefixes.length; i += 1) { // If the addressString being tested starts with an accepted prefix or no prefix at all if ( addressString.startsWith(currency.prefixes[i] + ':') || !addressString.includes(':') ) { return true; } } return false; } export function isValidTokenPrefix(addressString) { // Check for prefix included in currency.tokenPrefixes array // For now, validation is handled by converting to simpleledger: prefix and checksum // and relying on legacy validation methods of simpleledger: prefix addresses // For token addresses, do not accept an address with no prefix for (let i = 0; i < currency.tokenPrefixes.length; i += 1) { if (addressString.startsWith(currency.tokenPrefixes[i] + ':')) { return true; } } return false; } export function toLegacy(address) { let testedAddress; let legacyAddress; try { if (isValidCashPrefix(address)) { // Prefix-less addresses may be valid, but the cashaddr.decode function used below // will throw an error without a prefix. Hence, must ensure prefix to use that function. const hasPrefix = address.includes(':'); if (!hasPrefix) { testedAddress = currency.legacyPrefix + ':' + address; } else { testedAddress = address; } // Note: an `ecash:` checksum address with no prefix will not be validated by // parseAddress in Send.js // Only handle the case of prefixless address that is valid `bitcoincash:` address const { type, hash } = cashaddr.decode(testedAddress); legacyAddress = cashaddr.encode(currency.legacyPrefix, type, hash); } else { console.log(`Error: ${address} is not a cash address`); throw new Error( 'Address prefix is not a valid cash address with a prefix from the Ticker.prefixes array', ); } } catch (err) { return err; } return legacyAddress; } export function parseAddress(BCH, addressString) { // Build return obj const addressInfo = { address: '', isValid: false, queryString: null, amount: null, }; // Parse address string for parameters const paramCheck = addressString.split('?'); let cleanAddress = paramCheck[0]; addressInfo.address = cleanAddress; // Validate address let isValidAddress; try { isValidAddress = BCH.Address.isCashAddress(cleanAddress); } catch (err) { isValidAddress = false; } addressInfo.isValid = isValidAddress; // Check for parameters // only the amount param is currently supported let queryString = null; let amount = null; if (paramCheck.length > 1) { queryString = paramCheck[1]; addressInfo.queryString = queryString; const addrParams = new URLSearchParams(queryString); if (addrParams.has('amount')) { // Amount in satoshis try { amount = new BigNumber(parseInt(addrParams.get('amount'))) .div(1e8) .toString(); } catch (err) { amount = null; } } } addressInfo.amount = amount; return addressInfo; } diff --git a/web/cashtab/src/hooks/__mocks__/mockHydrateUtxosBatched.js b/web/cashtab/src/hooks/__mocks__/mockHydrateUtxosBatched.js new file mode 100644 index 000000000..517ff7eab --- /dev/null +++ b/web/cashtab/src/hooks/__mocks__/mockHydrateUtxosBatched.js @@ -0,0 +1,1688 @@ +// @generated + +export const flattenedHydrateUtxosResponse = { + slpUtxos: [ + { + utxos: [ + { + height: 681187, + tx_hash: + '0d391574918bf5ecbb00fa0c48d2a88be80c4b86a421992309f28871186b40fe', + tx_pos: 0, + value: 1000, + txid: + '0d391574918bf5ecbb00fa0c48d2a88be80c4b86a421992309f28871186b40fe', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '09eb70948f37e22eda0e425daed577cbb665794fea8b69da558700aabf95d9ab', + tx_pos: 0, + value: 2000, + txid: + '09eb70948f37e22eda0e425daed577cbb665794fea8b69da558700aabf95d9ab', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '0bdfe5a8eae0b00ad18d4fe2dba0ec20e661a8739348163bef484a90e049fa17', + tx_pos: 0, + value: 9000, + txid: + '0bdfe5a8eae0b00ad18d4fe2dba0ec20e661a8739348163bef484a90e049fa17', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '12db7f983196388991f901bb76da6f00cbb7ce8261d5a3194ea34bc4ee03b218', + tx_pos: 0, + value: 11000, + txid: + '12db7f983196388991f901bb76da6f00cbb7ce8261d5a3194ea34bc4ee03b218', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '31ad22a45f2510044407df031f97816006295d0a4f1e424a38835865010a107b', + tx_pos: 0, + value: 7000, + txid: + '31ad22a45f2510044407df031f97816006295d0a4f1e424a38835865010a107b', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '5b74e05ced6b7d862fe9cab94071b2ccfa475c0cef94b90c7edb8a06f90e5ad6', + tx_pos: 1, + value: 546, + txid: + '5b74e05ced6b7d862fe9cab94071b2ccfa475c0cef94b90c7edb8a06f90e5ad6', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '1e-7', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '76c473666913b517a34c25a00a06e8da128267b832a8be900db59cbe3de36b77', + tx_pos: 0, + value: 12000, + txid: + '76c473666913b517a34c25a00a06e8da128267b832a8be900db59cbe3de36b77', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '9d5399046bf89de7d1d1f725066d1c9a9eb26877d622f0236b5bd0b59dbc55c9', + tx_pos: 0, + value: 8000, + txid: + '9d5399046bf89de7d1d1f725066d1c9a9eb26877d622f0236b5bd0b59dbc55c9', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'a6347e8b522835ef1592996b668a87290f44cc26eec7f41a20f7b3a2f1e7ae31', + tx_pos: 0, + value: 10000, + txid: + 'a6347e8b522835ef1592996b668a87290f44cc26eec7f41a20f7b3a2f1e7ae31', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'cc3f8684f9fbeffa8e9142c3c29c411d267a20bc758e0230f3ac60082b1409c4', + tx_pos: 0, + value: 3000, + txid: + 'cc3f8684f9fbeffa8e9142c3c29c411d267a20bc758e0230f3ac60082b1409c4', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + utxos: [ + { + height: 681188, + tx_hash: + 'd491dc4ae9959bd6e95ad733eec1f97977b7d7fe400e83a47277a337d4e2ea43', + tx_pos: 0, + value: 6000, + txid: + 'd491dc4ae9959bd6e95ad733eec1f97977b7d7fe400e83a47277a337d4e2ea43', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'd736a55663aa176581b6484e0d3b499cbf7ad1a57e6fc9ac547cec67b41fd0ba', + tx_pos: 0, + value: 4000, + txid: + 'd736a55663aa176581b6484e0d3b499cbf7ad1a57e6fc9ac547cec67b41fd0ba', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'e7a70afaf07ca689066ed36facc7c86b0e24da2d4c5fa6f5e1fd1806f5a39ec2', + tx_pos: 0, + value: 5000, + txid: + 'e7a70afaf07ca689066ed36facc7c86b0e24da2d4c5fa6f5e1fd1806f5a39ec2', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '0aacdb7d85c466a7d6d4edf127883da40b05617d9c4ff7493bde3c973f22231d', + tx_pos: 1, + value: 546, + txid: + '0aacdb7d85c466a7d6d4edf127883da40b05617d9c4ff7493bde3c973f22231d', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '10', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '2cc8f480e9adfb74aff7351bdbbf12ed8972e35fb8bd0f43b9ea5e4aeaec5693', + tx_pos: 1, + value: 546, + txid: + '2cc8f480e9adfb74aff7351bdbbf12ed8972e35fb8bd0f43b9ea5e4aeaec5693', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '6', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '36bdf8461dbc19ff46681e9bcb6d5312c8d276ef17779ff8016d647594c39991', + tx_pos: 1, + value: 546, + txid: + '36bdf8461dbc19ff46681e9bcb6d5312c8d276ef17779ff8016d647594c39991', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '4', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '6b1476b65d3e29248c3809e18add16cddfee9e1d9a7060df97b35e517e8b7131', + tx_pos: 1, + value: 546, + txid: + '6b1476b65d3e29248c3809e18add16cddfee9e1d9a7060df97b35e517e8b7131', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '7', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '986dc9f9cc91e9976f2a8470805ab3b6bccfd4eaf224cdfa35bb62294bd8aac3', + tx_pos: 1, + value: 546, + txid: + '986dc9f9cc91e9976f2a8470805ab3b6bccfd4eaf224cdfa35bb62294bd8aac3', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '2', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'c4ef58f111ae86c7e1a9be4d5b553de6f6061b4bdca130d360c4e18476679ad7', + tx_pos: 1, + value: 546, + txid: + 'c4ef58f111ae86c7e1a9be4d5b553de6f6061b4bdca130d360c4e18476679ad7', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'c551e9ea96ce844bb1aaee65c99a312bb5fa66f8f822ab45dec63c7c3b77bbe5', + tx_pos: 1, + value: 546, + txid: + 'c551e9ea96ce844bb1aaee65c99a312bb5fa66f8f822ab45dec63c7c3b77bbe5', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '5', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + utxos: [ + { + height: 681189, + tx_hash: + 'da2af7958ab41e892c63d6a68be0cb4a0fd3315f2d5d5d7c51f92891187b9f1f', + tx_pos: 1, + value: 546, + txid: + 'da2af7958ab41e892c63d6a68be0cb4a0fd3315f2d5d5d7c51f92891187b9f1f', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '3', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'e69c1b507f7ca3dfac790e26fbd132085cf1796648563a5facfe3c82a6401e6c', + tx_pos: 1, + value: 546, + txid: + 'e69c1b507f7ca3dfac790e26fbd132085cf1796648563a5facfe3c82a6401e6c', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '8', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'f38ccfa615e38f0c871f4eb35db420157808014f1f5743f1522529253c0c4c56', + tx_pos: 1, + value: 546, + txid: + 'f38ccfa615e38f0c871f4eb35db420157808014f1f5743f1522529253c0c4c56', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '11', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'f3a106c523a1af4c3d68d3c82a015f3d7c890f590b410bde535b5ad392c447a4', + tx_pos: 1, + value: 546, + txid: + 'f3a106c523a1af4c3d68d3c82a015f3d7c890f590b410bde535b5ad392c447a4', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + '52fe0ccf7b5936095bbdadebc0de9f844a99457096ca4f7b45543a2badefdf35', + tx_pos: 1, + value: 546, + txid: + '52fe0ccf7b5936095bbdadebc0de9f844a99457096ca4f7b45543a2badefdf35', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '4', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + 'aa50baef76708fee1f19bd098c0d7407b64b280afd76a450067a89ab2bddd3e8', + tx_pos: 1, + value: 546, + txid: + 'aa50baef76708fee1f19bd098c0d7407b64b280afd76a450067a89ab2bddd3e8', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '2', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + 'bfc175d1933aed136d7bd887481144ec42112c34e7889cf3f21013409e233e3d', + tx_pos: 1, + value: 546, + txid: + 'bfc175d1933aed136d7bd887481144ec42112c34e7889cf3f21013409e233e3d', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '3', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + 'c2d2e57203f5d66c3bddd3f4fd5ccb053006588bfa0fec76bdbbfd2169984e9c', + tx_pos: 1, + value: 546, + txid: + 'c2d2e57203f5d66c3bddd3f4fd5ccb053006588bfa0fec76bdbbfd2169984e9c', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + 'e9dca9aa954131a0004325fff11dfddcd6e5843c468116cf4d38cb264032cdc0', + tx_pos: 1, + value: 546, + txid: + 'e9dca9aa954131a0004325fff11dfddcd6e5843c468116cf4d38cb264032cdc0', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1f6a65e7a4bde92c0a012de2bcf4007034504a765377cdf08a3ee01d1eaa6901', + tokenTicker: '🍔', + tokenName: 'Burger', + tokenDocumentUrl: + 'https://c4.wallpaperflare.com/wallpaper/58/564/863/giant-hamburger-wallpaper-preview.jpg', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + '091c9f32deb2f4f3733673803f51acf050b65d8042d1561824c6cd22d14bb43b', + tx_pos: 1, + value: 546, + txid: + '091c9f32deb2f4f3733673803f51acf050b65d8042d1561824c6cd22d14bb43b', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '5', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + utxos: [ + { + height: 681191, + tx_hash: + 'b35c502f388cdfbdd6841b7a73e973149b3c8deca76295a3e4665939e0562796', + tx_pos: 1, + value: 546, + txid: + 'b35c502f388cdfbdd6841b7a73e973149b3c8deca76295a3e4665939e0562796', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + 'dd84ca78db4d617221b58eabc6667af8fe2f7eadbfcc213d35be9f1b419beb8d', + tokenTicker: 'TAP', + tokenName: 'Thoughts and Prayers', + tokenDocumentUrl: '', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + 'c70408fca1a5bf48f338f7ef031e586293be6948a5bff1fbbdd4eb923ef11e59', + tx_pos: 1, + value: 546, + txid: + 'c70408fca1a5bf48f338f7ef031e586293be6948a5bff1fbbdd4eb923ef11e59', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb', + tokenTicker: 'NAKAMOTO', + tokenName: 'NAKAMOTO', + tokenDocumentUrl: '', + tokenDocumentHash: '', + decimals: 8, + tokenType: 1, + tokenQty: '1e-8', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + 'e1097932e5a607c100dc73fa18169be2e501e1782c7c94500742974d6353476c', + tx_pos: 1, + value: 546, + txid: + 'e1097932e5a607c100dc73fa18169be2e501e1782c7c94500742974d6353476c', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7f8889682d57369ed0e32336f8b7e0ffec625a35cca183f4e81fde4e71a538a1', + tokenTicker: 'HONK', + tokenName: 'HONK HONK', + tokenDocumentUrl: 'THE REAL HONK SLP TOKEN', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + 'f6ef57f697219aaa576bf43d69a7f8b8753dcbcbb502f602259a7d14fafd52c5', + tx_pos: 1, + value: 546, + txid: + 'f6ef57f697219aaa576bf43d69a7f8b8753dcbcbb502f602259a7d14fafd52c5', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '1e-9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681192, + tx_hash: + '43a925c679debac91183b0ccd08780cc94dc58d79cdb506df92ed5963c6bbb34', + tx_pos: 1, + value: 546, + txid: + '43a925c679debac91183b0ccd08780cc94dc58d79cdb506df92ed5963c6bbb34', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '2e-9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681192, + tx_hash: + '880baf5691c2b4c5a22ae4032e2004c0c54bfabf003468044a2e341846137136', + tx_pos: 1, + value: 546, + txid: + '880baf5691c2b4c5a22ae4032e2004c0c54bfabf003468044a2e341846137136', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '3e-9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681192, + tx_hash: + 'b7f8b23f5ce12842eb655239919b6142052a2fa2b2ce974a4baac36b0137f332', + tx_pos: 1, + value: 546, + txid: + 'b7f8b23f5ce12842eb655239919b6142052a2fa2b2ce974a4baac36b0137f332', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '4e-9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681192, + tx_hash: + 'f27ff24c15b01c30d44218c6dc8706fd33cc7bc9b4b38399075f0f41d8e412af', + tx_pos: 1, + value: 546, + txid: + 'f27ff24c15b01c30d44218c6dc8706fd33cc7bc9b4b38399075f0f41d8e412af', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '5e-9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], +}; + +export const legacyHydrateUtxosResponse = { + slpUtxos: [ + { + utxos: [], + address: 'bitcoincash:qzqpcnas8wpxzgvg52lcs34fxrfnv4xwwvc8vkd3v4', + }, + { + utxos: [], + address: 'bitcoincash:qpg4sucvkh0gy3fv3yd8fqj7grg6gxwyus753nq8c7', + }, + { + utxos: [ + { + height: 681187, + tx_hash: + '0d391574918bf5ecbb00fa0c48d2a88be80c4b86a421992309f28871186b40fe', + tx_pos: 0, + value: 1000, + txid: + '0d391574918bf5ecbb00fa0c48d2a88be80c4b86a421992309f28871186b40fe', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '09eb70948f37e22eda0e425daed577cbb665794fea8b69da558700aabf95d9ab', + tx_pos: 0, + value: 2000, + txid: + '09eb70948f37e22eda0e425daed577cbb665794fea8b69da558700aabf95d9ab', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '0bdfe5a8eae0b00ad18d4fe2dba0ec20e661a8739348163bef484a90e049fa17', + tx_pos: 0, + value: 9000, + txid: + '0bdfe5a8eae0b00ad18d4fe2dba0ec20e661a8739348163bef484a90e049fa17', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '12db7f983196388991f901bb76da6f00cbb7ce8261d5a3194ea34bc4ee03b218', + tx_pos: 0, + value: 11000, + txid: + '12db7f983196388991f901bb76da6f00cbb7ce8261d5a3194ea34bc4ee03b218', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '31ad22a45f2510044407df031f97816006295d0a4f1e424a38835865010a107b', + tx_pos: 0, + value: 7000, + txid: + '31ad22a45f2510044407df031f97816006295d0a4f1e424a38835865010a107b', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '5b74e05ced6b7d862fe9cab94071b2ccfa475c0cef94b90c7edb8a06f90e5ad6', + tx_pos: 1, + value: 546, + txid: + '5b74e05ced6b7d862fe9cab94071b2ccfa475c0cef94b90c7edb8a06f90e5ad6', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '1e-7', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '76c473666913b517a34c25a00a06e8da128267b832a8be900db59cbe3de36b77', + tx_pos: 0, + value: 12000, + txid: + '76c473666913b517a34c25a00a06e8da128267b832a8be900db59cbe3de36b77', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '9d5399046bf89de7d1d1f725066d1c9a9eb26877d622f0236b5bd0b59dbc55c9', + tx_pos: 0, + value: 8000, + txid: + '9d5399046bf89de7d1d1f725066d1c9a9eb26877d622f0236b5bd0b59dbc55c9', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'a6347e8b522835ef1592996b668a87290f44cc26eec7f41a20f7b3a2f1e7ae31', + tx_pos: 0, + value: 10000, + txid: + 'a6347e8b522835ef1592996b668a87290f44cc26eec7f41a20f7b3a2f1e7ae31', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'cc3f8684f9fbeffa8e9142c3c29c411d267a20bc758e0230f3ac60082b1409c4', + tx_pos: 0, + value: 3000, + txid: + 'cc3f8684f9fbeffa8e9142c3c29c411d267a20bc758e0230f3ac60082b1409c4', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'd491dc4ae9959bd6e95ad733eec1f97977b7d7fe400e83a47277a337d4e2ea43', + tx_pos: 0, + value: 6000, + txid: + 'd491dc4ae9959bd6e95ad733eec1f97977b7d7fe400e83a47277a337d4e2ea43', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'd736a55663aa176581b6484e0d3b499cbf7ad1a57e6fc9ac547cec67b41fd0ba', + tx_pos: 0, + value: 4000, + txid: + 'd736a55663aa176581b6484e0d3b499cbf7ad1a57e6fc9ac547cec67b41fd0ba', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'e7a70afaf07ca689066ed36facc7c86b0e24da2d4c5fa6f5e1fd1806f5a39ec2', + tx_pos: 0, + value: 5000, + txid: + 'e7a70afaf07ca689066ed36facc7c86b0e24da2d4c5fa6f5e1fd1806f5a39ec2', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '0aacdb7d85c466a7d6d4edf127883da40b05617d9c4ff7493bde3c973f22231d', + tx_pos: 1, + value: 546, + txid: + '0aacdb7d85c466a7d6d4edf127883da40b05617d9c4ff7493bde3c973f22231d', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '10', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '2cc8f480e9adfb74aff7351bdbbf12ed8972e35fb8bd0f43b9ea5e4aeaec5693', + tx_pos: 1, + value: 546, + txid: + '2cc8f480e9adfb74aff7351bdbbf12ed8972e35fb8bd0f43b9ea5e4aeaec5693', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '6', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '36bdf8461dbc19ff46681e9bcb6d5312c8d276ef17779ff8016d647594c39991', + tx_pos: 1, + value: 546, + txid: + '36bdf8461dbc19ff46681e9bcb6d5312c8d276ef17779ff8016d647594c39991', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '4', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '6b1476b65d3e29248c3809e18add16cddfee9e1d9a7060df97b35e517e8b7131', + tx_pos: 1, + value: 546, + txid: + '6b1476b65d3e29248c3809e18add16cddfee9e1d9a7060df97b35e517e8b7131', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '7', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '986dc9f9cc91e9976f2a8470805ab3b6bccfd4eaf224cdfa35bb62294bd8aac3', + tx_pos: 1, + value: 546, + txid: + '986dc9f9cc91e9976f2a8470805ab3b6bccfd4eaf224cdfa35bb62294bd8aac3', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '2', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'c4ef58f111ae86c7e1a9be4d5b553de6f6061b4bdca130d360c4e18476679ad7', + tx_pos: 1, + value: 546, + txid: + 'c4ef58f111ae86c7e1a9be4d5b553de6f6061b4bdca130d360c4e18476679ad7', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'c551e9ea96ce844bb1aaee65c99a312bb5fa66f8f822ab45dec63c7c3b77bbe5', + tx_pos: 1, + value: 546, + txid: + 'c551e9ea96ce844bb1aaee65c99a312bb5fa66f8f822ab45dec63c7c3b77bbe5', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '5', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'da2af7958ab41e892c63d6a68be0cb4a0fd3315f2d5d5d7c51f92891187b9f1f', + tx_pos: 1, + value: 546, + txid: + 'da2af7958ab41e892c63d6a68be0cb4a0fd3315f2d5d5d7c51f92891187b9f1f', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '3', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'e69c1b507f7ca3dfac790e26fbd132085cf1796648563a5facfe3c82a6401e6c', + tx_pos: 1, + value: 546, + txid: + 'e69c1b507f7ca3dfac790e26fbd132085cf1796648563a5facfe3c82a6401e6c', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '8', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'f38ccfa615e38f0c871f4eb35db420157808014f1f5743f1522529253c0c4c56', + tx_pos: 1, + value: 546, + txid: + 'f38ccfa615e38f0c871f4eb35db420157808014f1f5743f1522529253c0c4c56', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '11', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'f3a106c523a1af4c3d68d3c82a015f3d7c890f590b410bde535b5ad392c447a4', + tx_pos: 1, + value: 546, + txid: + 'f3a106c523a1af4c3d68d3c82a015f3d7c890f590b410bde535b5ad392c447a4', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + '52fe0ccf7b5936095bbdadebc0de9f844a99457096ca4f7b45543a2badefdf35', + tx_pos: 1, + value: 546, + txid: + '52fe0ccf7b5936095bbdadebc0de9f844a99457096ca4f7b45543a2badefdf35', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '4', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + 'aa50baef76708fee1f19bd098c0d7407b64b280afd76a450067a89ab2bddd3e8', + tx_pos: 1, + value: 546, + txid: + 'aa50baef76708fee1f19bd098c0d7407b64b280afd76a450067a89ab2bddd3e8', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '2', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + 'bfc175d1933aed136d7bd887481144ec42112c34e7889cf3f21013409e233e3d', + tx_pos: 1, + value: 546, + txid: + 'bfc175d1933aed136d7bd887481144ec42112c34e7889cf3f21013409e233e3d', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '3', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + 'c2d2e57203f5d66c3bddd3f4fd5ccb053006588bfa0fec76bdbbfd2169984e9c', + tx_pos: 1, + value: 546, + txid: + 'c2d2e57203f5d66c3bddd3f4fd5ccb053006588bfa0fec76bdbbfd2169984e9c', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + 'e9dca9aa954131a0004325fff11dfddcd6e5843c468116cf4d38cb264032cdc0', + tx_pos: 1, + value: 546, + txid: + 'e9dca9aa954131a0004325fff11dfddcd6e5843c468116cf4d38cb264032cdc0', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1f6a65e7a4bde92c0a012de2bcf4007034504a765377cdf08a3ee01d1eaa6901', + tokenTicker: '🍔', + tokenName: 'Burger', + tokenDocumentUrl: + 'https://c4.wallpaperflare.com/wallpaper/58/564/863/giant-hamburger-wallpaper-preview.jpg', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + '091c9f32deb2f4f3733673803f51acf050b65d8042d1561824c6cd22d14bb43b', + tx_pos: 1, + value: 546, + txid: + '091c9f32deb2f4f3733673803f51acf050b65d8042d1561824c6cd22d14bb43b', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '5', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + 'b35c502f388cdfbdd6841b7a73e973149b3c8deca76295a3e4665939e0562796', + tx_pos: 1, + value: 546, + txid: + 'b35c502f388cdfbdd6841b7a73e973149b3c8deca76295a3e4665939e0562796', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + 'dd84ca78db4d617221b58eabc6667af8fe2f7eadbfcc213d35be9f1b419beb8d', + tokenTicker: 'TAP', + tokenName: 'Thoughts and Prayers', + tokenDocumentUrl: '', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + 'c70408fca1a5bf48f338f7ef031e586293be6948a5bff1fbbdd4eb923ef11e59', + tx_pos: 1, + value: 546, + txid: + 'c70408fca1a5bf48f338f7ef031e586293be6948a5bff1fbbdd4eb923ef11e59', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb', + tokenTicker: 'NAKAMOTO', + tokenName: 'NAKAMOTO', + tokenDocumentUrl: '', + tokenDocumentHash: '', + decimals: 8, + tokenType: 1, + tokenQty: '1e-8', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + 'e1097932e5a607c100dc73fa18169be2e501e1782c7c94500742974d6353476c', + tx_pos: 1, + value: 546, + txid: + 'e1097932e5a607c100dc73fa18169be2e501e1782c7c94500742974d6353476c', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7f8889682d57369ed0e32336f8b7e0ffec625a35cca183f4e81fde4e71a538a1', + tokenTicker: 'HONK', + tokenName: 'HONK HONK', + tokenDocumentUrl: 'THE REAL HONK SLP TOKEN', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + 'f6ef57f697219aaa576bf43d69a7f8b8753dcbcbb502f602259a7d14fafd52c5', + tx_pos: 1, + value: 546, + txid: + 'f6ef57f697219aaa576bf43d69a7f8b8753dcbcbb502f602259a7d14fafd52c5', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '1e-9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681192, + tx_hash: + '43a925c679debac91183b0ccd08780cc94dc58d79cdb506df92ed5963c6bbb34', + tx_pos: 1, + value: 546, + txid: + '43a925c679debac91183b0ccd08780cc94dc58d79cdb506df92ed5963c6bbb34', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '2e-9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681192, + tx_hash: + '880baf5691c2b4c5a22ae4032e2004c0c54bfabf003468044a2e341846137136', + tx_pos: 1, + value: 546, + txid: + '880baf5691c2b4c5a22ae4032e2004c0c54bfabf003468044a2e341846137136', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '3e-9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681192, + tx_hash: + 'b7f8b23f5ce12842eb655239919b6142052a2fa2b2ce974a4baac36b0137f332', + tx_pos: 1, + value: 546, + txid: + 'b7f8b23f5ce12842eb655239919b6142052a2fa2b2ce974a4baac36b0137f332', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '4e-9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681192, + tx_hash: + 'f27ff24c15b01c30d44218c6dc8706fd33cc7bc9b4b38399075f0f41d8e412af', + tx_pos: 1, + value: 546, + txid: + 'f27ff24c15b01c30d44218c6dc8706fd33cc7bc9b4b38399075f0f41d8e412af', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '5e-9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], +}; diff --git a/web/cashtab/src/hooks/__tests__/useBCH.test.js b/web/cashtab/src/hooks/__tests__/useBCH.test.js index 9407486b1..8164052be 100644 --- a/web/cashtab/src/hooks/__tests__/useBCH.test.js +++ b/web/cashtab/src/hooks/__tests__/useBCH.test.js @@ -1,343 +1,361 @@ /* eslint-disable no-native-reassign */ import useBCH from '../useBCH'; import mockReturnGetHydratedUtxoDetails from '../__mocks__/mockReturnGetHydratedUtxoDetails'; import mockReturnGetSlpBalancesAndUtxos from '../__mocks__/mockReturnGetSlpBalancesAndUtxos'; import mockReturnGetHydratedUtxoDetailsWithZeroBalance from '../__mocks__/mockReturnGetHydratedUtxoDetailsWithZeroBalance'; import mockReturnGetSlpBalancesAndUtxosNoZeroBalance from '../__mocks__/mockReturnGetSlpBalancesAndUtxosNoZeroBalance'; import sendBCHMock from '../__mocks__/sendBCH'; import mockTxHistory from '../__mocks__/mockTxHistory'; import mockFlatTxHistory from '../__mocks__/mockFlatTxHistory'; import mockTxDataWithPassthrough from '../__mocks__/mockTxDataWithPassthrough'; +import { + flattenedHydrateUtxosResponse, + legacyHydrateUtxosResponse, +} from '../__mocks__/mockHydrateUtxosBatched'; import { tokenSendWdt, tokenReceiveTBS, } from '../__mocks__/mockParseTokenInfoForTxHistory'; import { mockSentCashTx, mockReceivedCashTx, mockSentTokenTx, mockReceivedTokenTx, } from '../__mocks__/mockParsedTxs'; import BCHJS from '@psf/bch-js'; // TODO: should be removed when external lib not needed anymore import { currency } from '../../components/Common/Ticker'; import BigNumber from 'bignumber.js'; describe('useBCH hook', () => { it('gets Rest Api Url on testnet', () => { process = { env: { REACT_APP_NETWORK: `testnet`, REACT_APP_BCHA_APIS: 'https://rest.kingbch.com/v3/,https://wallet-service-prod.bitframe.org/v3/,notevenaurl,https://rest.kingbch.com/v3/', REACT_APP_BCHA_APIS_TEST: 'https://free-test.fullstack.cash/v3/', }, }; const { getRestUrl } = useBCH(); const expectedApiUrl = `https://free-test.fullstack.cash/v3/`; expect(getRestUrl(0)).toBe(expectedApiUrl); }); it('gets primary Rest API URL on mainnet', () => { process = { env: { REACT_APP_BCHA_APIS: 'https://rest.kingbch.com/v3/,https://wallet-service-prod.bitframe.org/v3/,notevenaurl,https://rest.kingbch.com/v3/', REACT_APP_NETWORK: 'mainnet', }, }; const { getRestUrl } = useBCH(); const expectedApiUrl = `https://rest.kingbch.com/v3/`; expect(getRestUrl(0)).toBe(expectedApiUrl); }); it('calculates fee correctly for 2 P2PKH outputs', () => { const { calcFee } = useBCH(); const BCH = new BCHJS(); const utxosMock = [{}, {}]; expect(calcFee(BCH, utxosMock, 2, 1.01)).toBe(378); }); it('gets SLP and BCH balances and utxos from hydrated utxo details', async () => { const { getSlpBalancesAndUtxos } = useBCH(); const result = await getSlpBalancesAndUtxos( mockReturnGetHydratedUtxoDetails, ); expect(result).toStrictEqual(mockReturnGetSlpBalancesAndUtxos); }); it(`Ignores SLP utxos with utxo.tokenQty === '0'`, async () => { const { getSlpBalancesAndUtxos } = useBCH(); const result = await getSlpBalancesAndUtxos( mockReturnGetHydratedUtxoDetailsWithZeroBalance, ); expect(result).toStrictEqual( mockReturnGetSlpBalancesAndUtxosNoZeroBalance, ); }); + it(`Parses flattened batched hydrateUtxosResponse to yield same result as legacy unbatched hydrateUtxosResponse`, async () => { + const { getSlpBalancesAndUtxos } = useBCH(); + + const batchedResult = await getSlpBalancesAndUtxos( + flattenedHydrateUtxosResponse, + ); + + const legacyResult = await getSlpBalancesAndUtxos( + legacyHydrateUtxosResponse, + ); + + expect(batchedResult).toStrictEqual(legacyResult); + }); + it('sends BCH correctly', async () => { const { sendBch } = useBCH(); const BCH = new BCHJS(); const { expectedTxId, expectedHex, utxos, wallet, destinationAddress, sendAmount, } = sendBCHMock; BCH.RawTransactions.sendRawTransaction = jest .fn() .mockResolvedValue(expectedTxId); expect( await sendBch( BCH, wallet, utxos, destinationAddress, sendAmount, 1.01, ), ).toBe(`${currency.blockExplorerUrl}/tx/${expectedTxId}`); expect(BCH.RawTransactions.sendRawTransaction).toHaveBeenCalledWith( expectedHex, ); }); it('sends BCH correctly with callback', async () => { const { sendBch } = useBCH(); const BCH = new BCHJS(); const callback = jest.fn(); const { expectedTxId, expectedHex, utxos, wallet, destinationAddress, sendAmount, } = sendBCHMock; BCH.RawTransactions.sendRawTransaction = jest .fn() .mockResolvedValue(expectedTxId); expect( await sendBch( BCH, wallet, utxos, destinationAddress, sendAmount, 1.01, callback, ), ).toBe(`${currency.blockExplorerUrl}/tx/${expectedTxId}`); expect(BCH.RawTransactions.sendRawTransaction).toHaveBeenCalledWith( expectedHex, ); expect(callback).toHaveBeenCalledWith(expectedTxId); }); it(`Throws error if called trying to send one base unit ${currency.ticker} more than available in utxo set`, async () => { const { sendBch } = useBCH(); const BCH = new BCHJS(); const { expectedTxId, utxos, wallet, destinationAddress } = sendBCHMock; const expectedTxFeeInSats = 229; BCH.RawTransactions.sendRawTransaction = jest .fn() .mockResolvedValue(expectedTxId); const oneBaseUnitMoreThanBalance = new BigNumber(utxos[0].value) .minus(expectedTxFeeInSats) .plus(1) .div(10 ** currency.cashDecimals) .toString(); const failedSendBch = sendBch( BCH, wallet, utxos, destinationAddress, oneBaseUnitMoreThanBalance, 1.01, ); expect(failedSendBch).rejects.toThrow(new Error('Insufficient funds')); const nullValuesSendBch = await sendBch( BCH, wallet, utxos, destinationAddress, null, 1.01, ); expect(nullValuesSendBch).toBe(null); }); it('Throws error on attempt to send one satoshi less than backend dust limit', async () => { const { sendBch } = useBCH(); const BCH = new BCHJS(); const { expectedTxId, utxos, wallet, destinationAddress } = sendBCHMock; BCH.RawTransactions.sendRawTransaction = jest .fn() .mockResolvedValue(expectedTxId); const failedSendBch = sendBch( BCH, wallet, utxos, destinationAddress, new BigNumber(currency.dust) .minus(new BigNumber('0.00000001')) .toString(), 1.01, ); expect(failedSendBch).rejects.toThrow(new Error('dust')); const nullValuesSendBch = await sendBch( BCH, wallet, utxos, destinationAddress, null, 1.01, ); expect(nullValuesSendBch).toBe(null); }); it('receives errors from the network and parses it', async () => { const { sendBch } = useBCH(); const BCH = new BCHJS(); const { sendAmount, utxos, wallet, destinationAddress } = sendBCHMock; BCH.RawTransactions.sendRawTransaction = jest .fn() .mockImplementation(async () => { throw new Error('insufficient priority (code 66)'); }); const insufficientPriority = sendBch( BCH, wallet, utxos, destinationAddress, sendAmount, 1.01, ); await expect(insufficientPriority).rejects.toThrow( new Error('insufficient priority (code 66)'), ); BCH.RawTransactions.sendRawTransaction = jest .fn() .mockImplementation(async () => { throw new Error('txn-mempool-conflict (code 18)'); }); const txnMempoolConflict = sendBch( BCH, wallet, utxos, destinationAddress, sendAmount, 1.01, ); await expect(txnMempoolConflict).rejects.toThrow( new Error('txn-mempool-conflict (code 18)'), ); BCH.RawTransactions.sendRawTransaction = jest .fn() .mockImplementation(async () => { throw new Error('Network Error'); }); const networkError = sendBch( BCH, wallet, utxos, destinationAddress, sendAmount, 1.01, ); await expect(networkError).rejects.toThrow(new Error('Network Error')); BCH.RawTransactions.sendRawTransaction = jest .fn() .mockImplementation(async () => { const err = new Error( 'too-long-mempool-chain, too many unconfirmed ancestors [limit: 25] (code 64)', ); throw err; }); const tooManyAncestorsMempool = sendBch( BCH, wallet, utxos, destinationAddress, sendAmount, 1.01, ); await expect(tooManyAncestorsMempool).rejects.toThrow( new Error( 'too-long-mempool-chain, too many unconfirmed ancestors [limit: 25] (code 64)', ), ); }); it('Correctly flattens transaction history', () => { const { flattenTransactions } = useBCH(); expect(flattenTransactions(mockTxHistory, 10)).toStrictEqual( mockFlatTxHistory, ); }); it(`Correctly parses a "send ${currency.ticker}" transaction`, () => { const { parseTxData } = useBCH(); expect(parseTxData([mockTxDataWithPassthrough[0]])).toStrictEqual( mockSentCashTx, ); }); it(`Correctly parses a "receive ${currency.ticker}" transaction`, () => { const { parseTxData } = useBCH(); expect(parseTxData([mockTxDataWithPassthrough[5]])).toStrictEqual( mockReceivedCashTx, ); }); it(`Correctly parses a "send ${currency.tokenTicker}" transaction`, () => { const { parseTxData } = useBCH(); expect(parseTxData([mockTxDataWithPassthrough[1]])).toStrictEqual( mockSentTokenTx, ); }); it(`Correctly parses a "receive ${currency.tokenTicker}" transaction`, () => { const { parseTxData } = useBCH(); expect(parseTxData([mockTxDataWithPassthrough[3]])).toStrictEqual( mockReceivedTokenTx, ); }); it(`Correctly parses a "send ${currency.tokenTicker}" transaction with token details`, () => { const { parseTokenInfoForTxHistory } = useBCH(); expect( parseTokenInfoForTxHistory( tokenSendWdt.parsedTx, tokenSendWdt.tokenInfo, ), ).toStrictEqual(tokenSendWdt.cashtabTokenInfo); }); it(`Correctly parses a "receive ${currency.tokenTicker}" transaction with token details and 9 decimals of precision`, () => { const { parseTokenInfoForTxHistory } = useBCH(); expect( parseTokenInfoForTxHistory( tokenReceiveTBS.parsedTx, tokenReceiveTBS.tokenInfo, ), ).toStrictEqual(tokenReceiveTBS.cashtabTokenInfo); }); }); diff --git a/web/cashtab/src/hooks/useBCH.js b/web/cashtab/src/hooks/useBCH.js index e9528ed0b..e4942ca62 100644 --- a/web/cashtab/src/hooks/useBCH.js +++ b/web/cashtab/src/hooks/useBCH.js @@ -1,829 +1,854 @@ import BigNumber from 'bignumber.js'; import { currency } from '@components/Common/Ticker'; import SlpWallet from 'minimal-slp-wallet'; -import { toSmallestDenomination } from '@utils/cashMethods'; +import { + toSmallestDenomination, + batchArray, + flattenBatchedHydratedUtxos, +} from '@utils/cashMethods'; export default function useBCH() { const SEND_BCH_ERRORS = { INSUFFICIENT_FUNDS: 0, NETWORK_ERROR: 1, INSUFFICIENT_PRIORITY: 66, // ~insufficient fee DOUBLE_SPENDING: 18, MAX_UNCONFIRMED_TXS: 64, }; const getRestUrl = (apiIndex = 0) => { const apiString = process.env.REACT_APP_NETWORK === `mainnet` ? process.env.REACT_APP_BCHA_APIS : process.env.REACT_APP_BCHA_APIS_TEST; const apiArray = apiString.split(','); return apiArray[apiIndex]; }; const flattenTransactions = ( txHistory, txCount = currency.txHistoryCount, ) => { /* Convert txHistory, format [{address: '', transactions: [{height: '', tx_hash: ''}, ...{}]}, {}, {}] to flatTxHistory [{txid: '', blockheight: '', address: ''}] sorted by blockheight, newest transactions to oldest transactions */ let flatTxHistory = []; let includedTxids = []; for (let i = 0; i < txHistory.length; i += 1) { const { address, transactions } = txHistory[i]; for (let j = transactions.length - 1; j >= 0; j -= 1) { let flatTx = {}; flatTx.address = address; // If tx is unconfirmed, give arbitrarily high blockheight flatTx.height = transactions[j].height <= 0 ? 10000000 : transactions[j].height; flatTx.txid = transactions[j].tx_hash; // Only add this tx if the same transaction is not already in the array // This edge case can happen with older wallets, txs can be on multiple paths if (!includedTxids.includes(flatTx.txid)) { includedTxids.push(flatTx.txid); flatTxHistory.push(flatTx); } } } // Sort with most recent transaction at index 0 flatTxHistory.sort((a, b) => b.height - a.height); // Only return 10 return flatTxHistory.splice(0, txCount); }; const parseTxData = txData => { /* Desired output [ { txid: '', type: send, receive receivingAddress: '', quantity: amount bcha token: true/false tokenInfo: { tokenId: tokenQty: txType: mint, send, other } } ] */ const parsedTxHistory = []; for (let i = 0; i < txData.length; i += 1) { const tx = txData[i]; const parsedTx = {}; // Move over info that does not need to be calculated parsedTx.txid = tx.txid; parsedTx.confirmations = tx.confirmations; parsedTx.height = tx.height; parsedTx.blocktime = tx.blocktime; let amountSent = 0; let amountReceived = 0; // Assume an incoming transaction let outgoingTx = false; let tokenTx = false; let destinationAddress = tx.address; // If vin includes tx address, this is an outgoing tx // Note that with bch-input data, we do not have input amounts for (let j = 0; j < tx.vin.length; j += 1) { const thisInput = tx.vin[j]; if (thisInput.address === tx.address) { // This is an outgoing transaction outgoingTx = true; } } // Iterate over vout to find how much was sent or received for (let j = 0; j < tx.vout.length; j += 1) { const thisOutput = tx.vout[j]; // If there is no addresses object in the output, OP_RETURN or token tx if ( !Object.keys(thisOutput.scriptPubKey).includes('addresses') ) { // For now, assume this is a token tx tokenTx = true; continue; } if ( thisOutput.scriptPubKey.addresses && thisOutput.scriptPubKey.addresses[0] === tx.address ) { if (outgoingTx) { // This amount is change continue; } amountReceived += thisOutput.value; } else if (outgoingTx) { amountSent += thisOutput.value; // Assume there's only one destination address, i.e. it was sent by a Cashtab wallet destinationAddress = thisOutput.scriptPubKey.addresses[0]; } } // Construct parsedTx parsedTx.txid = tx.txid; parsedTx.amountSent = amountSent; parsedTx.amountReceived = amountReceived; parsedTx.tokenTx = tokenTx; parsedTx.outgoingTx = outgoingTx; parsedTx.destinationAddress = destinationAddress; parsedTxHistory.push(parsedTx); } return parsedTxHistory; }; const getTxHistory = async (BCH, addresses) => { let txHistoryResponse; try { //console.log(`API Call: BCH.Electrumx.utxo(addresses)`); //console.log(addresses); txHistoryResponse = await BCH.Electrumx.transactions(addresses); //console.log(`BCH.Electrumx.transactions(addresses) succeeded`); //console.log(`txHistoryResponse`, txHistoryResponse); if (txHistoryResponse.success && txHistoryResponse.transactions) { return txHistoryResponse.transactions; } else { // eslint-disable-next-line no-throw-literal throw new Error('Error in getTxHistory'); } } catch (err) { console.log(`Error in BCH.Electrumx.transactions(addresses):`); console.log(err); return err; } }; const getTxDataWithPassThrough = async (BCH, flatTx) => { // necessary as BCH.RawTransactions.getTxData does not return address or blockheight const txDataWithPassThrough = await BCH.RawTransactions.getTxData( flatTx.txid, ); txDataWithPassThrough.height = flatTx.height; txDataWithPassThrough.address = flatTx.address; return txDataWithPassThrough; }; const getTxData = async (BCH, txHistory) => { // Flatten tx history let flatTxs = flattenTransactions(txHistory); // Build array of promises to get tx data for all 10 transactions let txDataPromises = []; for (let i = 0; i < flatTxs.length; i += 1) { const txDataPromise = await getTxDataWithPassThrough( BCH, flatTxs[i], ); txDataPromises.push(txDataPromise); } // Get txData for the 10 most recent transactions let txDataPromiseResponse; try { txDataPromiseResponse = await Promise.all(txDataPromises); const parsed = parseTxData(txDataPromiseResponse); return parsed; } catch (err) { console.log(`Error in Promise.all(txDataPromises):`); console.log(err); return err; } }; const parseTokenInfoForTxHistory = (parsedTx, tokenInfo) => { // Scan over inputs to find out originating addresses const { sendInputsFull, sendOutputsFull } = tokenInfo; const sendingTokenAddresses = []; for (let i = 0; i < sendInputsFull.length; i += 1) { const sendingAddress = sendInputsFull[i].address; sendingTokenAddresses.push(sendingAddress); } // Scan over outputs to find out how much was sent let qtySent = new BigNumber(0); let qtyReceived = new BigNumber(0); for (let i = 0; i < sendOutputsFull.length; i += 1) { if (sendingTokenAddresses.includes(sendOutputsFull[i].address)) { // token change continue; } if (parsedTx.outgoingTx) { qtySent = qtySent.plus( new BigNumber(sendOutputsFull[i].amount), ); } else { qtyReceived = qtyReceived.plus( new BigNumber(sendOutputsFull[i].amount), ); } } const cashtabTokenInfo = {}; cashtabTokenInfo.qtySent = qtySent.toString(); cashtabTokenInfo.qtyReceived = qtyReceived.toString(); cashtabTokenInfo.tokenId = tokenInfo.tokenIdHex; cashtabTokenInfo.tokenName = tokenInfo.tokenName; cashtabTokenInfo.tokenTicker = tokenInfo.tokenTicker; return cashtabTokenInfo; }; const addTokenTxDataToSingleTx = async (BCH, parsedTx) => { // Accept one parsedTx // If it's a token tx, do an API call to get token info and return it // If it's not a token tx, just return it if (!parsedTx.tokenTx) { return parsedTx; } const tokenData = await BCH.SLP.Utils.txDetails(parsedTx.txid); const { tokenInfo } = tokenData; parsedTx.tokenInfo = parseTokenInfoForTxHistory(parsedTx, tokenInfo); return parsedTx; }; const addTokenTxData = async (BCH, parsedTxs) => { // Collect all txids for token transactions into array of promises // Promise.all to get their tx history // Add a tokeninfo object to parsedTxs for token txs // Get txData for the 10 most recent transactions // Build array of promises to get tx data for all 10 transactions let tokenTxDataPromises = []; for (let i = 0; i < parsedTxs.length; i += 1) { const txDataPromise = await addTokenTxDataToSingleTx( BCH, parsedTxs[i], ); tokenTxDataPromises.push(txDataPromise); } let tokenTxDataPromiseResponse; try { tokenTxDataPromiseResponse = await Promise.all(tokenTxDataPromises); return tokenTxDataPromiseResponse; } catch (err) { console.log(`Error in Promise.all(tokenTxDataPromises):`); console.log(err); return err; } }; // Split out the BCH.Electrumx.utxo(addresses) call from the getSlpBalancesandUtxos function // If utxo set has not changed, you do not need to hydrate the utxo set // This drastically reduces calls to the API const getUtxos = async (BCH, addresses) => { let utxosResponse; try { //console.log(`API Call: BCH.Electrumx.utxo(addresses)`); //console.log(addresses); utxosResponse = await BCH.Electrumx.utxo(addresses); //console.log(`BCH.Electrumx.utxo(addresses) succeeded`); //console.log(`utxosResponse`, utxosResponse); return utxosResponse.utxos; } catch (err) { console.log(`Error in BCH.Electrumx.utxo(addresses):`); return err; } }; const getHydratedUtxoDetails = async (BCH, utxos) => { + const hydrateUtxosPromises = []; + for (let i = 0; i < utxos.length; i += 1) { + let thisAddress = utxos[i].address; + let theseUtxos = utxos[i].utxos; + const batchedUtxos = batchArray( + theseUtxos, + currency.hydrateUtxoBatchSize, + ); + + // Iterate over each utxo in this address field + for (let j = 0; j < batchedUtxos.length; j += 1) { + const utxoSetForThisPromise = [ + { utxos: batchedUtxos[j], address: thisAddress }, + ]; + const thisPromise = BCH.SLP.Utils.hydrateUtxos( + utxoSetForThisPromise, + ); + hydrateUtxosPromises.push(thisPromise); + } + } let hydratedUtxoDetails; try { - hydratedUtxoDetails = await BCH.SLP.Utils.hydrateUtxos(utxos); - return hydratedUtxoDetails; - } catch (err) { - console.log( - `Error in BCH.SLP.Utils.hydrateUtxos(utxosResponse.utxos)`, + hydratedUtxoDetails = await Promise.all(hydrateUtxosPromises); + const flattenedBatchedHydratedUtxos = flattenBatchedHydratedUtxos( + hydratedUtxoDetails, ); + return flattenedBatchedHydratedUtxos; + } catch (err) { + console.log(`Error in Promise.all(hydrateUtxosPromises)`); console.log(err); return err; } }; const getSlpBalancesAndUtxos = hydratedUtxoDetails => { const hydratedUtxos = []; for (let i = 0; i < hydratedUtxoDetails.slpUtxos.length; i += 1) { const hydratedUtxosAtAddress = hydratedUtxoDetails.slpUtxos[i]; for (let j = 0; j < hydratedUtxosAtAddress.utxos.length; j += 1) { const hydratedUtxo = hydratedUtxosAtAddress.utxos[j]; hydratedUtxo.address = hydratedUtxosAtAddress.address; hydratedUtxos.push(hydratedUtxo); } } //console.log(`hydratedUtxos`, hydratedUtxos); // WARNING // If you hit rate limits, your above utxos object will come back with `isValid` as null, but otherwise ok // You need to throw an error before setting nonSlpUtxos and slpUtxos in this case const nullUtxos = hydratedUtxos.filter(utxo => utxo.isValid === null); //console.log(`nullUtxos`, nullUtxos); if (nullUtxos.length > 0) { console.log( `${nullUtxos.length} null utxos found, ignoring results`, ); throw new Error('Null utxos found, ignoring results'); } // Prevent app from treating slpUtxos as nonSlpUtxos // Must enforce === false as api will occasionally return utxo.isValid === null // Do not classify utxos with 546 satoshis as nonSlpUtxos as a precaution // Do not classify any utxos that include token information as nonSlpUtxos const nonSlpUtxos = hydratedUtxos.filter( utxo => utxo.isValid === false && utxo.value !== 546 && !utxo.tokenName, ); // To be included in slpUtxos, the utxo must // have utxo.isValid = true // If utxo has a utxo.tokenQty field, i.e. not a minting baton, then utxo.tokenQty !== '0' const slpUtxos = hydratedUtxos.filter( utxo => utxo.isValid && !(utxo.tokenQty === '0'), ); let tokensById = {}; slpUtxos.forEach(slpUtxo => { let token = tokensById[slpUtxo.tokenId]; if (token) { // Minting baton does nto have a slpUtxo.tokenQty type if (slpUtxo.tokenQty) { token.balance = token.balance.plus( new BigNumber(slpUtxo.tokenQty), ); } //token.hasBaton = slpUtxo.transactionType === "genesis"; if (slpUtxo.utxoType && !token.hasBaton) { token.hasBaton = slpUtxo.utxoType === 'minting-baton'; } // Examples of slpUtxo /* Genesis transaction: { address: "bitcoincash:qrhzv5t79e2afc3rdutcu0d3q20gl7ul3ue58whah6" decimals: 9 height: 617564 isValid: true satoshis: 546 tokenDocumentHash: "" tokenDocumentUrl: "developer.bitcoin.com" tokenId: "6c41f244676ecfcbe3b4fabee2c72c2dadf8d74f8849afabc8a549157db69199" tokenName: "PiticoLaunch" tokenTicker: "PTCL" tokenType: 1 tx_hash: "6c41f244676ecfcbe3b4fabee2c72c2dadf8d74f8849afabc8a549157db69199" tx_pos: 2 txid: "6c41f244676ecfcbe3b4fabee2c72c2dadf8d74f8849afabc8a549157db69199" utxoType: "minting-baton" value: 546 vout: 2 } Send transaction: { address: "bitcoincash:qrhzv5t79e2afc3rdutcu0d3q20gl7ul3ue58whah6" decimals: 9 height: 655115 isValid: true satoshis: 546 tokenDocumentHash: "" tokenDocumentUrl: "developer.bitcoin.com" tokenId: "6c41f244676ecfcbe3b4fabee2c72c2dadf8d74f8849afabc8a549157db69199" tokenName: "PiticoLaunch" tokenQty: 1.123456789 tokenTicker: "PTCL" tokenType: 1 transactionType: "send" tx_hash: "dea400f963bc9f51e010f88533010f8d1f82fc2bcc485ff8500c3a82b25abd9e" tx_pos: 1 txid: "dea400f963bc9f51e010f88533010f8d1f82fc2bcc485ff8500c3a82b25abd9e" utxoType: "token" value: 546 vout: 1 } */ } else { token = {}; token.info = slpUtxo; token.tokenId = slpUtxo.tokenId; if (slpUtxo.tokenQty) { token.balance = new BigNumber(slpUtxo.tokenQty); } else { token.balance = new BigNumber(0); } if (slpUtxo.utxoType) { token.hasBaton = slpUtxo.utxoType === 'minting-baton'; } else { token.hasBaton = false; } tokensById[slpUtxo.tokenId] = token; } }); const tokens = Object.values(tokensById); // console.log(`tokens`, tokens); return { tokens, nonSlpUtxos, slpUtxos, }; }; const calcFee = ( BCH, utxos, p2pkhOutputNumber = 2, satoshisPerByte = currency.defaultFee, ) => { const byteCount = BCH.BitcoinCash.getByteCount( { P2PKH: utxos.length }, { P2PKH: p2pkhOutputNumber }, ); const txFee = Math.ceil(satoshisPerByte * byteCount); return txFee; }; const sendToken = async ( BCH, wallet, slpBalancesAndUtxos, { tokenId, amount, tokenReceiverAddress }, ) => { // Handle error of user having no BCH if (slpBalancesAndUtxos.nonSlpUtxos.length === 0) { throw new Error( `You need some ${currency.ticker} to send ${currency.tokenTicker}`, ); } const largestBchUtxo = slpBalancesAndUtxos.nonSlpUtxos.reduce( (previous, current) => previous.value > current.value ? previous : current, ); const bchECPair = BCH.ECPair.fromWIF(largestBchUtxo.wif); const tokenUtxos = slpBalancesAndUtxos.slpUtxos.filter( (utxo, index) => { if ( utxo && // UTXO is associated with a token. utxo.tokenId === tokenId && // UTXO matches the token ID. utxo.utxoType === 'token' // UTXO is not a minting baton. ) { return true; } return false; }, ); if (tokenUtxos.length === 0) { throw new Error( 'No token UTXOs for the specified token could be found.', ); } // BEGIN transaction construction. // instance of transaction builder let transactionBuilder; if (process.env.REACT_APP_NETWORK === 'mainnet') { transactionBuilder = new BCH.TransactionBuilder(); } else transactionBuilder = new BCH.TransactionBuilder('testnet'); const originalAmount = largestBchUtxo.value; transactionBuilder.addInput( largestBchUtxo.tx_hash, largestBchUtxo.tx_pos, ); let finalTokenAmountSent = new BigNumber(0); let tokenAmountBeingSentToAddress = new BigNumber(amount); let tokenUtxosBeingSpent = []; for (let i = 0; i < tokenUtxos.length; i++) { finalTokenAmountSent = finalTokenAmountSent.plus( new BigNumber(tokenUtxos[i].tokenQty), ); transactionBuilder.addInput( tokenUtxos[i].tx_hash, tokenUtxos[i].tx_pos, ); tokenUtxosBeingSpent.push(tokenUtxos[i]); if (tokenAmountBeingSentToAddress.lte(finalTokenAmountSent)) { break; } } const slpSendObj = BCH.SLP.TokenType1.generateSendOpReturn( tokenUtxosBeingSpent, tokenAmountBeingSentToAddress.toString(), ); const slpData = slpSendObj.script; // Add OP_RETURN as first output. transactionBuilder.addOutput(slpData, 0); // Send dust transaction representing tokens being sent. transactionBuilder.addOutput( BCH.SLP.Address.toLegacyAddress(tokenReceiverAddress), 546, ); // Return any token change back to the sender. if (slpSendObj.outputs > 1) { // Try to send this to Path1899 to move all utxos off legacy addresses if (wallet.Path1899.legacyAddress) { transactionBuilder.addOutput( wallet.Path1899.legacyAddress, 546, ); } else { // If you can't, send it back from whence it came transactionBuilder.addOutput( BCH.SLP.Address.toLegacyAddress( tokenUtxosBeingSpent[0].address, ), 546, ); } } // get byte count to calculate fee. paying 1 sat // Note: This may not be totally accurate. Just guessing on the byteCount size. const txFee = calcFee( BCH, tokenUtxosBeingSpent, 5, 1.1 * currency.defaultFee, ); // amount to send back to the sending address. It's the original amount - 1 sat/byte for tx size const remainder = originalAmount - txFee - 546 * 2; if (remainder < 1) { throw new Error('Selected UTXO does not have enough satoshis'); } // Last output: send the BCH change back to the wallet. // If Path1899, send it to Path1899 address if (wallet.Path1899.legacyAddress) { transactionBuilder.addOutput( wallet.Path1899.legacyAddress, remainder, ); } else { // Otherwise send it back from whence it came transactionBuilder.addOutput( BCH.Address.toLegacyAddress(largestBchUtxo.address), remainder, ); } // Sign the transaction with the private key for the BCH UTXO paying the fees. let redeemScript; transactionBuilder.sign( 0, bchECPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount, ); // Sign each token UTXO being consumed. for (let i = 0; i < tokenUtxosBeingSpent.length; i++) { const thisUtxo = tokenUtxosBeingSpent[i]; const accounts = [wallet.Path245, wallet.Path145, wallet.Path1899]; const utxoEcPair = BCH.ECPair.fromWIF( accounts .filter(acc => acc.cashAddress === thisUtxo.address) .pop().fundingWif, ); transactionBuilder.sign( 1 + i, utxoEcPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, thisUtxo.value, ); } // build tx const tx = transactionBuilder.build(); // output rawhex const hex = tx.toHex(); // console.log(`Transaction raw hex: `, hex); // END transaction construction. const txidStr = await BCH.RawTransactions.sendRawTransaction([hex]); if (txidStr && txidStr[0]) { console.log(`${currency.tokenTicker} txid`, txidStr[0]); } let link; if (process.env.REACT_APP_NETWORK === `mainnet`) { link = `${currency.blockExplorerUrl}/tx/${txidStr}`; } else { link = `${currency.blockExplorerUrlTestnet}/tx/${txidStr}`; } //console.log(`link`, link); return link; }; const sendBch = async ( BCH, wallet, utxos, destinationAddress, sendAmount, feeInSatsPerByte, callbackTxId, encodedOpReturn, ) => { // Note: callbackTxId is a callback function that accepts a txid as its only parameter try { if (!sendAmount) { return null; } const value = new BigNumber(sendAmount); // If user is attempting to send less than minimum accepted by the backend if (value.lt(new BigNumber(currency.dust))) { // Throw the same error given by the backend attempting to broadcast such a tx throw new Error('dust'); } const REMAINDER_ADDR = wallet.Path1899.cashAddress; const inputUtxos = []; let transactionBuilder; // instance of transaction builder if (process.env.REACT_APP_NETWORK === `mainnet`) transactionBuilder = new BCH.TransactionBuilder(); else transactionBuilder = new BCH.TransactionBuilder('testnet'); const satoshisToSend = toSmallestDenomination(value); // Throw validation error if toSmallestDenomination returns false if (!satoshisToSend) { const error = new Error( `Invalid decimal places for send amount`, ); throw error; } let originalAmount = new BigNumber(0); let txFee = 0; for (let i = 0; i < utxos.length; i++) { const utxo = utxos[i]; originalAmount = originalAmount.plus(utxo.value); const vout = utxo.vout; const txid = utxo.txid; // add input with txid and index of vout transactionBuilder.addInput(txid, vout); inputUtxos.push(utxo); txFee = encodedOpReturn ? calcFee(BCH, inputUtxos, 3, feeInSatsPerByte) : calcFee(BCH, inputUtxos, 2, feeInSatsPerByte); if (originalAmount.minus(satoshisToSend).minus(txFee).gte(0)) { break; } } // amount to send back to the remainder address. const remainder = originalAmount.minus(satoshisToSend).minus(txFee); if (remainder.lt(0)) { const error = new Error(`Insufficient funds`); error.code = SEND_BCH_ERRORS.INSUFFICIENT_FUNDS; throw error; } if (encodedOpReturn) { transactionBuilder.addOutput(encodedOpReturn, 0); } // add output w/ address and amount to send transactionBuilder.addOutput( BCH.Address.toCashAddress(destinationAddress), parseInt(toSmallestDenomination(value)), ); if ( remainder.gte( toSmallestDenomination(new BigNumber(currency.dust)), ) ) { transactionBuilder.addOutput( REMAINDER_ADDR, parseInt(remainder), ); } // Sign the transactions with the HD node. for (let i = 0; i < inputUtxos.length; i++) { const utxo = inputUtxos[i]; transactionBuilder.sign( i, BCH.ECPair.fromWIF(utxo.wif), undefined, transactionBuilder.hashTypes.SIGHASH_ALL, utxo.value, ); } // build tx const tx = transactionBuilder.build(); // output rawhex const hex = tx.toHex(); // Broadcast transaction to the network const txidStr = await BCH.RawTransactions.sendRawTransaction([hex]); if (txidStr && txidStr[0]) { console.log(`${currency.ticker} txid`, txidStr[0]); } let link; if (callbackTxId) { callbackTxId(txidStr); } if (process.env.REACT_APP_NETWORK === `mainnet`) { link = `${currency.blockExplorerUrl}/tx/${txidStr}`; } else { link = `${currency.blockExplorerUrlTestnet}/tx/${txidStr}`; } //console.log(`link`, link); return link; } catch (err) { if (err.error === 'insufficient priority (code 66)') { err.code = SEND_BCH_ERRORS.INSUFFICIENT_PRIORITY; } else if (err.error === 'txn-mempool-conflict (code 18)') { err.code = SEND_BCH_ERRORS.DOUBLE_SPENDING; } else if (err.error === 'Network Error') { err.code = SEND_BCH_ERRORS.NETWORK_ERROR; } else if ( err.error === 'too-long-mempool-chain, too many unconfirmed ancestors [limit: 25] (code 64)' ) { err.code = SEND_BCH_ERRORS.MAX_UNCONFIRMED_TXS; } console.log(`error: `, err); throw err; } }; const getBCH = (apiIndex = 0) => { let ConstructedSlpWallet; ConstructedSlpWallet = new SlpWallet('', { restURL: getRestUrl(apiIndex), }); return ConstructedSlpWallet.bchjs; }; return { getBCH, calcFee, getUtxos, getHydratedUtxoDetails, getSlpBalancesAndUtxos, getTxHistory, flattenTransactions, parseTxData, addTokenTxData, parseTokenInfoForTxHistory, getTxData, getRestUrl, sendBch, sendToken, }; } diff --git a/web/cashtab/src/utils/__mocks__/flattenBatchedHydratedUtxosMocks.js b/web/cashtab/src/utils/__mocks__/flattenBatchedHydratedUtxosMocks.js new file mode 100644 index 000000000..ccb9db72a --- /dev/null +++ b/web/cashtab/src/utils/__mocks__/flattenBatchedHydratedUtxosMocks.js @@ -0,0 +1,2721 @@ +// @generated + +export const unflattenedHydrateUtxosResponse = [ + { + slpUtxos: [ + { + utxos: [ + { + height: 681187, + tx_hash: + '0d391574918bf5ecbb00fa0c48d2a88be80c4b86a421992309f28871186b40fe', + tx_pos: 0, + value: 1000, + txid: + '0d391574918bf5ecbb00fa0c48d2a88be80c4b86a421992309f28871186b40fe', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '09eb70948f37e22eda0e425daed577cbb665794fea8b69da558700aabf95d9ab', + tx_pos: 0, + value: 2000, + txid: + '09eb70948f37e22eda0e425daed577cbb665794fea8b69da558700aabf95d9ab', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '0bdfe5a8eae0b00ad18d4fe2dba0ec20e661a8739348163bef484a90e049fa17', + tx_pos: 0, + value: 9000, + txid: + '0bdfe5a8eae0b00ad18d4fe2dba0ec20e661a8739348163bef484a90e049fa17', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '12db7f983196388991f901bb76da6f00cbb7ce8261d5a3194ea34bc4ee03b218', + tx_pos: 0, + value: 11000, + txid: + '12db7f983196388991f901bb76da6f00cbb7ce8261d5a3194ea34bc4ee03b218', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '31ad22a45f2510044407df031f97816006295d0a4f1e424a38835865010a107b', + tx_pos: 0, + value: 7000, + txid: + '31ad22a45f2510044407df031f97816006295d0a4f1e424a38835865010a107b', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '5b74e05ced6b7d862fe9cab94071b2ccfa475c0cef94b90c7edb8a06f90e5ad6', + tx_pos: 1, + value: 546, + txid: + '5b74e05ced6b7d862fe9cab94071b2ccfa475c0cef94b90c7edb8a06f90e5ad6', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '1e-7', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '76c473666913b517a34c25a00a06e8da128267b832a8be900db59cbe3de36b77', + tx_pos: 0, + value: 12000, + txid: + '76c473666913b517a34c25a00a06e8da128267b832a8be900db59cbe3de36b77', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '9d5399046bf89de7d1d1f725066d1c9a9eb26877d622f0236b5bd0b59dbc55c9', + tx_pos: 0, + value: 8000, + txid: + '9d5399046bf89de7d1d1f725066d1c9a9eb26877d622f0236b5bd0b59dbc55c9', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'a6347e8b522835ef1592996b668a87290f44cc26eec7f41a20f7b3a2f1e7ae31', + tx_pos: 0, + value: 10000, + txid: + 'a6347e8b522835ef1592996b668a87290f44cc26eec7f41a20f7b3a2f1e7ae31', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'cc3f8684f9fbeffa8e9142c3c29c411d267a20bc758e0230f3ac60082b1409c4', + tx_pos: 0, + value: 3000, + txid: + 'cc3f8684f9fbeffa8e9142c3c29c411d267a20bc758e0230f3ac60082b1409c4', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], + }, + { + slpUtxos: [ + { + utxos: [ + { + height: 681188, + tx_hash: + 'd491dc4ae9959bd6e95ad733eec1f97977b7d7fe400e83a47277a337d4e2ea43', + tx_pos: 0, + value: 6000, + txid: + 'd491dc4ae9959bd6e95ad733eec1f97977b7d7fe400e83a47277a337d4e2ea43', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'd736a55663aa176581b6484e0d3b499cbf7ad1a57e6fc9ac547cec67b41fd0ba', + tx_pos: 0, + value: 4000, + txid: + 'd736a55663aa176581b6484e0d3b499cbf7ad1a57e6fc9ac547cec67b41fd0ba', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'e7a70afaf07ca689066ed36facc7c86b0e24da2d4c5fa6f5e1fd1806f5a39ec2', + tx_pos: 0, + value: 5000, + txid: + 'e7a70afaf07ca689066ed36facc7c86b0e24da2d4c5fa6f5e1fd1806f5a39ec2', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '0aacdb7d85c466a7d6d4edf127883da40b05617d9c4ff7493bde3c973f22231d', + tx_pos: 1, + value: 546, + txid: + '0aacdb7d85c466a7d6d4edf127883da40b05617d9c4ff7493bde3c973f22231d', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '10', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '2cc8f480e9adfb74aff7351bdbbf12ed8972e35fb8bd0f43b9ea5e4aeaec5693', + tx_pos: 1, + value: 546, + txid: + '2cc8f480e9adfb74aff7351bdbbf12ed8972e35fb8bd0f43b9ea5e4aeaec5693', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '6', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '36bdf8461dbc19ff46681e9bcb6d5312c8d276ef17779ff8016d647594c39991', + tx_pos: 1, + value: 546, + txid: + '36bdf8461dbc19ff46681e9bcb6d5312c8d276ef17779ff8016d647594c39991', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '4', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '6b1476b65d3e29248c3809e18add16cddfee9e1d9a7060df97b35e517e8b7131', + tx_pos: 1, + value: 546, + txid: + '6b1476b65d3e29248c3809e18add16cddfee9e1d9a7060df97b35e517e8b7131', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '7', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '986dc9f9cc91e9976f2a8470805ab3b6bccfd4eaf224cdfa35bb62294bd8aac3', + tx_pos: 1, + value: 546, + txid: + '986dc9f9cc91e9976f2a8470805ab3b6bccfd4eaf224cdfa35bb62294bd8aac3', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '2', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'c4ef58f111ae86c7e1a9be4d5b553de6f6061b4bdca130d360c4e18476679ad7', + tx_pos: 1, + value: 546, + txid: + 'c4ef58f111ae86c7e1a9be4d5b553de6f6061b4bdca130d360c4e18476679ad7', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'c551e9ea96ce844bb1aaee65c99a312bb5fa66f8f822ab45dec63c7c3b77bbe5', + tx_pos: 1, + value: 546, + txid: + 'c551e9ea96ce844bb1aaee65c99a312bb5fa66f8f822ab45dec63c7c3b77bbe5', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '5', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], + }, + { + slpUtxos: [ + { + utxos: [ + { + height: 681189, + tx_hash: + 'da2af7958ab41e892c63d6a68be0cb4a0fd3315f2d5d5d7c51f92891187b9f1f', + tx_pos: 1, + value: 546, + txid: + 'da2af7958ab41e892c63d6a68be0cb4a0fd3315f2d5d5d7c51f92891187b9f1f', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '3', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'e69c1b507f7ca3dfac790e26fbd132085cf1796648563a5facfe3c82a6401e6c', + tx_pos: 1, + value: 546, + txid: + 'e69c1b507f7ca3dfac790e26fbd132085cf1796648563a5facfe3c82a6401e6c', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '8', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'f38ccfa615e38f0c871f4eb35db420157808014f1f5743f1522529253c0c4c56', + tx_pos: 1, + value: 546, + txid: + 'f38ccfa615e38f0c871f4eb35db420157808014f1f5743f1522529253c0c4c56', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '11', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'f3a106c523a1af4c3d68d3c82a015f3d7c890f590b410bde535b5ad392c447a4', + tx_pos: 1, + value: 546, + txid: + 'f3a106c523a1af4c3d68d3c82a015f3d7c890f590b410bde535b5ad392c447a4', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + '52fe0ccf7b5936095bbdadebc0de9f844a99457096ca4f7b45543a2badefdf35', + tx_pos: 1, + value: 546, + txid: + '52fe0ccf7b5936095bbdadebc0de9f844a99457096ca4f7b45543a2badefdf35', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '4', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + 'aa50baef76708fee1f19bd098c0d7407b64b280afd76a450067a89ab2bddd3e8', + tx_pos: 1, + value: 546, + txid: + 'aa50baef76708fee1f19bd098c0d7407b64b280afd76a450067a89ab2bddd3e8', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '2', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + 'bfc175d1933aed136d7bd887481144ec42112c34e7889cf3f21013409e233e3d', + tx_pos: 1, + value: 546, + txid: + 'bfc175d1933aed136d7bd887481144ec42112c34e7889cf3f21013409e233e3d', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '3', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + 'c2d2e57203f5d66c3bddd3f4fd5ccb053006588bfa0fec76bdbbfd2169984e9c', + tx_pos: 1, + value: 546, + txid: + 'c2d2e57203f5d66c3bddd3f4fd5ccb053006588bfa0fec76bdbbfd2169984e9c', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + 'e9dca9aa954131a0004325fff11dfddcd6e5843c468116cf4d38cb264032cdc0', + tx_pos: 1, + value: 546, + txid: + 'e9dca9aa954131a0004325fff11dfddcd6e5843c468116cf4d38cb264032cdc0', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1f6a65e7a4bde92c0a012de2bcf4007034504a765377cdf08a3ee01d1eaa6901', + tokenTicker: '🍔', + tokenName: 'Burger', + tokenDocumentUrl: + 'https://c4.wallpaperflare.com/wallpaper/58/564/863/giant-hamburger-wallpaper-preview.jpg', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + '091c9f32deb2f4f3733673803f51acf050b65d8042d1561824c6cd22d14bb43b', + tx_pos: 1, + value: 546, + txid: + '091c9f32deb2f4f3733673803f51acf050b65d8042d1561824c6cd22d14bb43b', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '5', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], + }, + { + slpUtxos: [ + { + utxos: [ + { + height: 681191, + tx_hash: + 'b35c502f388cdfbdd6841b7a73e973149b3c8deca76295a3e4665939e0562796', + tx_pos: 1, + value: 546, + txid: + 'b35c502f388cdfbdd6841b7a73e973149b3c8deca76295a3e4665939e0562796', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + 'dd84ca78db4d617221b58eabc6667af8fe2f7eadbfcc213d35be9f1b419beb8d', + tokenTicker: 'TAP', + tokenName: 'Thoughts and Prayers', + tokenDocumentUrl: '', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + 'c70408fca1a5bf48f338f7ef031e586293be6948a5bff1fbbdd4eb923ef11e59', + tx_pos: 1, + value: 546, + txid: + 'c70408fca1a5bf48f338f7ef031e586293be6948a5bff1fbbdd4eb923ef11e59', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb', + tokenTicker: 'NAKAMOTO', + tokenName: 'NAKAMOTO', + tokenDocumentUrl: '', + tokenDocumentHash: '', + decimals: 8, + tokenType: 1, + tokenQty: '1e-8', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + 'e1097932e5a607c100dc73fa18169be2e501e1782c7c94500742974d6353476c', + tx_pos: 1, + value: 546, + txid: + 'e1097932e5a607c100dc73fa18169be2e501e1782c7c94500742974d6353476c', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7f8889682d57369ed0e32336f8b7e0ffec625a35cca183f4e81fde4e71a538a1', + tokenTicker: 'HONK', + tokenName: 'HONK HONK', + tokenDocumentUrl: 'THE REAL HONK SLP TOKEN', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + 'f6ef57f697219aaa576bf43d69a7f8b8753dcbcbb502f602259a7d14fafd52c5', + tx_pos: 1, + value: 546, + txid: + 'f6ef57f697219aaa576bf43d69a7f8b8753dcbcbb502f602259a7d14fafd52c5', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '1e-9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681192, + tx_hash: + '43a925c679debac91183b0ccd08780cc94dc58d79cdb506df92ed5963c6bbb34', + tx_pos: 1, + value: 546, + txid: + '43a925c679debac91183b0ccd08780cc94dc58d79cdb506df92ed5963c6bbb34', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '2e-9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681192, + tx_hash: + '880baf5691c2b4c5a22ae4032e2004c0c54bfabf003468044a2e341846137136', + tx_pos: 1, + value: 546, + txid: + '880baf5691c2b4c5a22ae4032e2004c0c54bfabf003468044a2e341846137136', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '3e-9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681192, + tx_hash: + 'b7f8b23f5ce12842eb655239919b6142052a2fa2b2ce974a4baac36b0137f332', + tx_pos: 1, + value: 546, + txid: + 'b7f8b23f5ce12842eb655239919b6142052a2fa2b2ce974a4baac36b0137f332', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '4e-9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681192, + tx_hash: + 'f27ff24c15b01c30d44218c6dc8706fd33cc7bc9b4b38399075f0f41d8e412af', + tx_pos: 1, + value: 546, + txid: + 'f27ff24c15b01c30d44218c6dc8706fd33cc7bc9b4b38399075f0f41d8e412af', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '5e-9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], + }, +]; + +export const flattenedHydrateUtxosResponse = { + slpUtxos: [ + { + utxos: [ + { + height: 681187, + tx_hash: + '0d391574918bf5ecbb00fa0c48d2a88be80c4b86a421992309f28871186b40fe', + tx_pos: 0, + value: 1000, + txid: + '0d391574918bf5ecbb00fa0c48d2a88be80c4b86a421992309f28871186b40fe', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '09eb70948f37e22eda0e425daed577cbb665794fea8b69da558700aabf95d9ab', + tx_pos: 0, + value: 2000, + txid: + '09eb70948f37e22eda0e425daed577cbb665794fea8b69da558700aabf95d9ab', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '0bdfe5a8eae0b00ad18d4fe2dba0ec20e661a8739348163bef484a90e049fa17', + tx_pos: 0, + value: 9000, + txid: + '0bdfe5a8eae0b00ad18d4fe2dba0ec20e661a8739348163bef484a90e049fa17', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '12db7f983196388991f901bb76da6f00cbb7ce8261d5a3194ea34bc4ee03b218', + tx_pos: 0, + value: 11000, + txid: + '12db7f983196388991f901bb76da6f00cbb7ce8261d5a3194ea34bc4ee03b218', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '31ad22a45f2510044407df031f97816006295d0a4f1e424a38835865010a107b', + tx_pos: 0, + value: 7000, + txid: + '31ad22a45f2510044407df031f97816006295d0a4f1e424a38835865010a107b', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '5b74e05ced6b7d862fe9cab94071b2ccfa475c0cef94b90c7edb8a06f90e5ad6', + tx_pos: 1, + value: 546, + txid: + '5b74e05ced6b7d862fe9cab94071b2ccfa475c0cef94b90c7edb8a06f90e5ad6', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '1e-7', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '76c473666913b517a34c25a00a06e8da128267b832a8be900db59cbe3de36b77', + tx_pos: 0, + value: 12000, + txid: + '76c473666913b517a34c25a00a06e8da128267b832a8be900db59cbe3de36b77', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '9d5399046bf89de7d1d1f725066d1c9a9eb26877d622f0236b5bd0b59dbc55c9', + tx_pos: 0, + value: 8000, + txid: + '9d5399046bf89de7d1d1f725066d1c9a9eb26877d622f0236b5bd0b59dbc55c9', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'a6347e8b522835ef1592996b668a87290f44cc26eec7f41a20f7b3a2f1e7ae31', + tx_pos: 0, + value: 10000, + txid: + 'a6347e8b522835ef1592996b668a87290f44cc26eec7f41a20f7b3a2f1e7ae31', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'cc3f8684f9fbeffa8e9142c3c29c411d267a20bc758e0230f3ac60082b1409c4', + tx_pos: 0, + value: 3000, + txid: + 'cc3f8684f9fbeffa8e9142c3c29c411d267a20bc758e0230f3ac60082b1409c4', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + utxos: [ + { + height: 681188, + tx_hash: + 'd491dc4ae9959bd6e95ad733eec1f97977b7d7fe400e83a47277a337d4e2ea43', + tx_pos: 0, + value: 6000, + txid: + 'd491dc4ae9959bd6e95ad733eec1f97977b7d7fe400e83a47277a337d4e2ea43', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'd736a55663aa176581b6484e0d3b499cbf7ad1a57e6fc9ac547cec67b41fd0ba', + tx_pos: 0, + value: 4000, + txid: + 'd736a55663aa176581b6484e0d3b499cbf7ad1a57e6fc9ac547cec67b41fd0ba', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'e7a70afaf07ca689066ed36facc7c86b0e24da2d4c5fa6f5e1fd1806f5a39ec2', + tx_pos: 0, + value: 5000, + txid: + 'e7a70afaf07ca689066ed36facc7c86b0e24da2d4c5fa6f5e1fd1806f5a39ec2', + vout: 0, + isValid: false, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '0aacdb7d85c466a7d6d4edf127883da40b05617d9c4ff7493bde3c973f22231d', + tx_pos: 1, + value: 546, + txid: + '0aacdb7d85c466a7d6d4edf127883da40b05617d9c4ff7493bde3c973f22231d', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '10', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '2cc8f480e9adfb74aff7351bdbbf12ed8972e35fb8bd0f43b9ea5e4aeaec5693', + tx_pos: 1, + value: 546, + txid: + '2cc8f480e9adfb74aff7351bdbbf12ed8972e35fb8bd0f43b9ea5e4aeaec5693', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '6', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '36bdf8461dbc19ff46681e9bcb6d5312c8d276ef17779ff8016d647594c39991', + tx_pos: 1, + value: 546, + txid: + '36bdf8461dbc19ff46681e9bcb6d5312c8d276ef17779ff8016d647594c39991', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '4', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '6b1476b65d3e29248c3809e18add16cddfee9e1d9a7060df97b35e517e8b7131', + tx_pos: 1, + value: 546, + txid: + '6b1476b65d3e29248c3809e18add16cddfee9e1d9a7060df97b35e517e8b7131', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '7', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '986dc9f9cc91e9976f2a8470805ab3b6bccfd4eaf224cdfa35bb62294bd8aac3', + tx_pos: 1, + value: 546, + txid: + '986dc9f9cc91e9976f2a8470805ab3b6bccfd4eaf224cdfa35bb62294bd8aac3', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '2', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'c4ef58f111ae86c7e1a9be4d5b553de6f6061b4bdca130d360c4e18476679ad7', + tx_pos: 1, + value: 546, + txid: + 'c4ef58f111ae86c7e1a9be4d5b553de6f6061b4bdca130d360c4e18476679ad7', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'c551e9ea96ce844bb1aaee65c99a312bb5fa66f8f822ab45dec63c7c3b77bbe5', + tx_pos: 1, + value: 546, + txid: + 'c551e9ea96ce844bb1aaee65c99a312bb5fa66f8f822ab45dec63c7c3b77bbe5', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '5', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + utxos: [ + { + height: 681189, + tx_hash: + 'da2af7958ab41e892c63d6a68be0cb4a0fd3315f2d5d5d7c51f92891187b9f1f', + tx_pos: 1, + value: 546, + txid: + 'da2af7958ab41e892c63d6a68be0cb4a0fd3315f2d5d5d7c51f92891187b9f1f', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '3', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'e69c1b507f7ca3dfac790e26fbd132085cf1796648563a5facfe3c82a6401e6c', + tx_pos: 1, + value: 546, + txid: + 'e69c1b507f7ca3dfac790e26fbd132085cf1796648563a5facfe3c82a6401e6c', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '8', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'f38ccfa615e38f0c871f4eb35db420157808014f1f5743f1522529253c0c4c56', + tx_pos: 1, + value: 546, + txid: + 'f38ccfa615e38f0c871f4eb35db420157808014f1f5743f1522529253c0c4c56', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '11', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'f3a106c523a1af4c3d68d3c82a015f3d7c890f590b410bde535b5ad392c447a4', + tx_pos: 1, + value: 546, + txid: + 'f3a106c523a1af4c3d68d3c82a015f3d7c890f590b410bde535b5ad392c447a4', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + '52fe0ccf7b5936095bbdadebc0de9f844a99457096ca4f7b45543a2badefdf35', + tx_pos: 1, + value: 546, + txid: + '52fe0ccf7b5936095bbdadebc0de9f844a99457096ca4f7b45543a2badefdf35', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '4', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + 'aa50baef76708fee1f19bd098c0d7407b64b280afd76a450067a89ab2bddd3e8', + tx_pos: 1, + value: 546, + txid: + 'aa50baef76708fee1f19bd098c0d7407b64b280afd76a450067a89ab2bddd3e8', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '2', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + 'bfc175d1933aed136d7bd887481144ec42112c34e7889cf3f21013409e233e3d', + tx_pos: 1, + value: 546, + txid: + 'bfc175d1933aed136d7bd887481144ec42112c34e7889cf3f21013409e233e3d', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '3', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + 'c2d2e57203f5d66c3bddd3f4fd5ccb053006588bfa0fec76bdbbfd2169984e9c', + tx_pos: 1, + value: 546, + txid: + 'c2d2e57203f5d66c3bddd3f4fd5ccb053006588bfa0fec76bdbbfd2169984e9c', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + 'e9dca9aa954131a0004325fff11dfddcd6e5843c468116cf4d38cb264032cdc0', + tx_pos: 1, + value: 546, + txid: + 'e9dca9aa954131a0004325fff11dfddcd6e5843c468116cf4d38cb264032cdc0', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1f6a65e7a4bde92c0a012de2bcf4007034504a765377cdf08a3ee01d1eaa6901', + tokenTicker: '🍔', + tokenName: 'Burger', + tokenDocumentUrl: + 'https://c4.wallpaperflare.com/wallpaper/58/564/863/giant-hamburger-wallpaper-preview.jpg', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + '091c9f32deb2f4f3733673803f51acf050b65d8042d1561824c6cd22d14bb43b', + tx_pos: 1, + value: 546, + txid: + '091c9f32deb2f4f3733673803f51acf050b65d8042d1561824c6cd22d14bb43b', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '5', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + utxos: [ + { + height: 681191, + tx_hash: + 'b35c502f388cdfbdd6841b7a73e973149b3c8deca76295a3e4665939e0562796', + tx_pos: 1, + value: 546, + txid: + 'b35c502f388cdfbdd6841b7a73e973149b3c8deca76295a3e4665939e0562796', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + 'dd84ca78db4d617221b58eabc6667af8fe2f7eadbfcc213d35be9f1b419beb8d', + tokenTicker: 'TAP', + tokenName: 'Thoughts and Prayers', + tokenDocumentUrl: '', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + 'c70408fca1a5bf48f338f7ef031e586293be6948a5bff1fbbdd4eb923ef11e59', + tx_pos: 1, + value: 546, + txid: + 'c70408fca1a5bf48f338f7ef031e586293be6948a5bff1fbbdd4eb923ef11e59', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb', + tokenTicker: 'NAKAMOTO', + tokenName: 'NAKAMOTO', + tokenDocumentUrl: '', + tokenDocumentHash: '', + decimals: 8, + tokenType: 1, + tokenQty: '1e-8', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + 'e1097932e5a607c100dc73fa18169be2e501e1782c7c94500742974d6353476c', + tx_pos: 1, + value: 546, + txid: + 'e1097932e5a607c100dc73fa18169be2e501e1782c7c94500742974d6353476c', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7f8889682d57369ed0e32336f8b7e0ffec625a35cca183f4e81fde4e71a538a1', + tokenTicker: 'HONK', + tokenName: 'HONK HONK', + tokenDocumentUrl: 'THE REAL HONK SLP TOKEN', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + 'f6ef57f697219aaa576bf43d69a7f8b8753dcbcbb502f602259a7d14fafd52c5', + tx_pos: 1, + value: 546, + txid: + 'f6ef57f697219aaa576bf43d69a7f8b8753dcbcbb502f602259a7d14fafd52c5', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '1e-9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681192, + tx_hash: + '43a925c679debac91183b0ccd08780cc94dc58d79cdb506df92ed5963c6bbb34', + tx_pos: 1, + value: 546, + txid: + '43a925c679debac91183b0ccd08780cc94dc58d79cdb506df92ed5963c6bbb34', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '2e-9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681192, + tx_hash: + '880baf5691c2b4c5a22ae4032e2004c0c54bfabf003468044a2e341846137136', + tx_pos: 1, + value: 546, + txid: + '880baf5691c2b4c5a22ae4032e2004c0c54bfabf003468044a2e341846137136', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '3e-9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681192, + tx_hash: + 'b7f8b23f5ce12842eb655239919b6142052a2fa2b2ce974a4baac36b0137f332', + tx_pos: 1, + value: 546, + txid: + 'b7f8b23f5ce12842eb655239919b6142052a2fa2b2ce974a4baac36b0137f332', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '4e-9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681192, + tx_hash: + 'f27ff24c15b01c30d44218c6dc8706fd33cc7bc9b4b38399075f0f41d8e412af', + tx_pos: 1, + value: 546, + txid: + 'f27ff24c15b01c30d44218c6dc8706fd33cc7bc9b4b38399075f0f41d8e412af', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '5e-9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], +}; + +export const batchedFinal = { + tokens: [ + { + info: { + height: 681188, + tx_hash: + '5b74e05ced6b7d862fe9cab94071b2ccfa475c0cef94b90c7edb8a06f90e5ad6', + tx_pos: 1, + value: 546, + txid: + '5b74e05ced6b7d862fe9cab94071b2ccfa475c0cef94b90c7edb8a06f90e5ad6', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '1e-7', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + balance: '66.0000001', + hasBaton: false, + }, + { + info: { + height: 681190, + tx_hash: + '52fe0ccf7b5936095bbdadebc0de9f844a99457096ca4f7b45543a2badefdf35', + tx_pos: 1, + value: 546, + txid: + '52fe0ccf7b5936095bbdadebc0de9f844a99457096ca4f7b45543a2badefdf35', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '4', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + balance: '15', + hasBaton: false, + }, + { + info: { + height: 681190, + tx_hash: + 'e9dca9aa954131a0004325fff11dfddcd6e5843c468116cf4d38cb264032cdc0', + tx_pos: 1, + value: 546, + txid: + 'e9dca9aa954131a0004325fff11dfddcd6e5843c468116cf4d38cb264032cdc0', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1f6a65e7a4bde92c0a012de2bcf4007034504a765377cdf08a3ee01d1eaa6901', + tokenTicker: '🍔', + tokenName: 'Burger', + tokenDocumentUrl: + 'https://c4.wallpaperflare.com/wallpaper/58/564/863/giant-hamburger-wallpaper-preview.jpg', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + tokenId: + '1f6a65e7a4bde92c0a012de2bcf4007034504a765377cdf08a3ee01d1eaa6901', + balance: '1', + hasBaton: false, + }, + { + info: { + height: 681191, + tx_hash: + 'b35c502f388cdfbdd6841b7a73e973149b3c8deca76295a3e4665939e0562796', + tx_pos: 1, + value: 546, + txid: + 'b35c502f388cdfbdd6841b7a73e973149b3c8deca76295a3e4665939e0562796', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + 'dd84ca78db4d617221b58eabc6667af8fe2f7eadbfcc213d35be9f1b419beb8d', + tokenTicker: 'TAP', + tokenName: 'Thoughts and Prayers', + tokenDocumentUrl: '', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + tokenId: + 'dd84ca78db4d617221b58eabc6667af8fe2f7eadbfcc213d35be9f1b419beb8d', + balance: '1', + hasBaton: false, + }, + { + info: { + height: 681191, + tx_hash: + 'c70408fca1a5bf48f338f7ef031e586293be6948a5bff1fbbdd4eb923ef11e59', + tx_pos: 1, + value: 546, + txid: + 'c70408fca1a5bf48f338f7ef031e586293be6948a5bff1fbbdd4eb923ef11e59', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb', + tokenTicker: 'NAKAMOTO', + tokenName: 'NAKAMOTO', + tokenDocumentUrl: '', + tokenDocumentHash: '', + decimals: 8, + tokenType: 1, + tokenQty: '1e-8', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + tokenId: + 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb', + balance: '1e-8', + hasBaton: false, + }, + { + info: { + height: 681191, + tx_hash: + 'e1097932e5a607c100dc73fa18169be2e501e1782c7c94500742974d6353476c', + tx_pos: 1, + value: 546, + txid: + 'e1097932e5a607c100dc73fa18169be2e501e1782c7c94500742974d6353476c', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7f8889682d57369ed0e32336f8b7e0ffec625a35cca183f4e81fde4e71a538a1', + tokenTicker: 'HONK', + tokenName: 'HONK HONK', + tokenDocumentUrl: 'THE REAL HONK SLP TOKEN', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + tokenId: + '7f8889682d57369ed0e32336f8b7e0ffec625a35cca183f4e81fde4e71a538a1', + balance: '1', + hasBaton: false, + }, + { + info: { + height: 681191, + tx_hash: + 'f6ef57f697219aaa576bf43d69a7f8b8753dcbcbb502f602259a7d14fafd52c5', + tx_pos: 1, + value: 546, + txid: + 'f6ef57f697219aaa576bf43d69a7f8b8753dcbcbb502f602259a7d14fafd52c5', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '1e-9', + isValid: true, + address: + 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + balance: '1.5e-8', + hasBaton: false, + }, + ], + nonSlpUtxos: [ + { + height: 681187, + tx_hash: + '0d391574918bf5ecbb00fa0c48d2a88be80c4b86a421992309f28871186b40fe', + tx_pos: 0, + value: 1000, + txid: + '0d391574918bf5ecbb00fa0c48d2a88be80c4b86a421992309f28871186b40fe', + vout: 0, + isValid: false, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '09eb70948f37e22eda0e425daed577cbb665794fea8b69da558700aabf95d9ab', + tx_pos: 0, + value: 2000, + txid: + '09eb70948f37e22eda0e425daed577cbb665794fea8b69da558700aabf95d9ab', + vout: 0, + isValid: false, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '0bdfe5a8eae0b00ad18d4fe2dba0ec20e661a8739348163bef484a90e049fa17', + tx_pos: 0, + value: 9000, + txid: + '0bdfe5a8eae0b00ad18d4fe2dba0ec20e661a8739348163bef484a90e049fa17', + vout: 0, + isValid: false, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '12db7f983196388991f901bb76da6f00cbb7ce8261d5a3194ea34bc4ee03b218', + tx_pos: 0, + value: 11000, + txid: + '12db7f983196388991f901bb76da6f00cbb7ce8261d5a3194ea34bc4ee03b218', + vout: 0, + isValid: false, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '31ad22a45f2510044407df031f97816006295d0a4f1e424a38835865010a107b', + tx_pos: 0, + value: 7000, + txid: + '31ad22a45f2510044407df031f97816006295d0a4f1e424a38835865010a107b', + vout: 0, + isValid: false, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '76c473666913b517a34c25a00a06e8da128267b832a8be900db59cbe3de36b77', + tx_pos: 0, + value: 12000, + txid: + '76c473666913b517a34c25a00a06e8da128267b832a8be900db59cbe3de36b77', + vout: 0, + isValid: false, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + '9d5399046bf89de7d1d1f725066d1c9a9eb26877d622f0236b5bd0b59dbc55c9', + tx_pos: 0, + value: 8000, + txid: + '9d5399046bf89de7d1d1f725066d1c9a9eb26877d622f0236b5bd0b59dbc55c9', + vout: 0, + isValid: false, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'a6347e8b522835ef1592996b668a87290f44cc26eec7f41a20f7b3a2f1e7ae31', + tx_pos: 0, + value: 10000, + txid: + 'a6347e8b522835ef1592996b668a87290f44cc26eec7f41a20f7b3a2f1e7ae31', + vout: 0, + isValid: false, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'cc3f8684f9fbeffa8e9142c3c29c411d267a20bc758e0230f3ac60082b1409c4', + tx_pos: 0, + value: 3000, + txid: + 'cc3f8684f9fbeffa8e9142c3c29c411d267a20bc758e0230f3ac60082b1409c4', + vout: 0, + isValid: false, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'd491dc4ae9959bd6e95ad733eec1f97977b7d7fe400e83a47277a337d4e2ea43', + tx_pos: 0, + value: 6000, + txid: + 'd491dc4ae9959bd6e95ad733eec1f97977b7d7fe400e83a47277a337d4e2ea43', + vout: 0, + isValid: false, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'd736a55663aa176581b6484e0d3b499cbf7ad1a57e6fc9ac547cec67b41fd0ba', + tx_pos: 0, + value: 4000, + txid: + 'd736a55663aa176581b6484e0d3b499cbf7ad1a57e6fc9ac547cec67b41fd0ba', + vout: 0, + isValid: false, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681188, + tx_hash: + 'e7a70afaf07ca689066ed36facc7c86b0e24da2d4c5fa6f5e1fd1806f5a39ec2', + tx_pos: 0, + value: 5000, + txid: + 'e7a70afaf07ca689066ed36facc7c86b0e24da2d4c5fa6f5e1fd1806f5a39ec2', + vout: 0, + isValid: false, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], + slpUtxos: [ + { + height: 681188, + tx_hash: + '5b74e05ced6b7d862fe9cab94071b2ccfa475c0cef94b90c7edb8a06f90e5ad6', + tx_pos: 1, + value: 546, + txid: + '5b74e05ced6b7d862fe9cab94071b2ccfa475c0cef94b90c7edb8a06f90e5ad6', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '1e-7', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '0aacdb7d85c466a7d6d4edf127883da40b05617d9c4ff7493bde3c973f22231d', + tx_pos: 1, + value: 546, + txid: + '0aacdb7d85c466a7d6d4edf127883da40b05617d9c4ff7493bde3c973f22231d', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '10', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '2cc8f480e9adfb74aff7351bdbbf12ed8972e35fb8bd0f43b9ea5e4aeaec5693', + tx_pos: 1, + value: 546, + txid: + '2cc8f480e9adfb74aff7351bdbbf12ed8972e35fb8bd0f43b9ea5e4aeaec5693', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '6', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '36bdf8461dbc19ff46681e9bcb6d5312c8d276ef17779ff8016d647594c39991', + tx_pos: 1, + value: 546, + txid: + '36bdf8461dbc19ff46681e9bcb6d5312c8d276ef17779ff8016d647594c39991', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '4', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '6b1476b65d3e29248c3809e18add16cddfee9e1d9a7060df97b35e517e8b7131', + tx_pos: 1, + value: 546, + txid: + '6b1476b65d3e29248c3809e18add16cddfee9e1d9a7060df97b35e517e8b7131', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '7', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + '986dc9f9cc91e9976f2a8470805ab3b6bccfd4eaf224cdfa35bb62294bd8aac3', + tx_pos: 1, + value: 546, + txid: + '986dc9f9cc91e9976f2a8470805ab3b6bccfd4eaf224cdfa35bb62294bd8aac3', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '2', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'c4ef58f111ae86c7e1a9be4d5b553de6f6061b4bdca130d360c4e18476679ad7', + tx_pos: 1, + value: 546, + txid: + 'c4ef58f111ae86c7e1a9be4d5b553de6f6061b4bdca130d360c4e18476679ad7', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'c551e9ea96ce844bb1aaee65c99a312bb5fa66f8f822ab45dec63c7c3b77bbe5', + tx_pos: 1, + value: 546, + txid: + 'c551e9ea96ce844bb1aaee65c99a312bb5fa66f8f822ab45dec63c7c3b77bbe5', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '5', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'da2af7958ab41e892c63d6a68be0cb4a0fd3315f2d5d5d7c51f92891187b9f1f', + tx_pos: 1, + value: 546, + txid: + 'da2af7958ab41e892c63d6a68be0cb4a0fd3315f2d5d5d7c51f92891187b9f1f', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '3', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'e69c1b507f7ca3dfac790e26fbd132085cf1796648563a5facfe3c82a6401e6c', + tx_pos: 1, + value: 546, + txid: + 'e69c1b507f7ca3dfac790e26fbd132085cf1796648563a5facfe3c82a6401e6c', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '8', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'f38ccfa615e38f0c871f4eb35db420157808014f1f5743f1522529253c0c4c56', + tx_pos: 1, + value: 546, + txid: + 'f38ccfa615e38f0c871f4eb35db420157808014f1f5743f1522529253c0c4c56', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '11', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681189, + tx_hash: + 'f3a106c523a1af4c3d68d3c82a015f3d7c890f590b410bde535b5ad392c447a4', + tx_pos: 1, + value: 546, + txid: + 'f3a106c523a1af4c3d68d3c82a015f3d7c890f590b410bde535b5ad392c447a4', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', + tokenTicker: 'WDT', + tokenName: + 'Test Token With Exceptionally Long Name For CSS And Style Revisions', + tokenDocumentUrl: + 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', + tokenDocumentHash: + '����\\�IS\u001e9�����k+���\u0018���\u001b]�߷2��', + decimals: 7, + tokenType: 1, + tokenQty: '9', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + '52fe0ccf7b5936095bbdadebc0de9f844a99457096ca4f7b45543a2badefdf35', + tx_pos: 1, + value: 546, + txid: + '52fe0ccf7b5936095bbdadebc0de9f844a99457096ca4f7b45543a2badefdf35', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '4', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + 'aa50baef76708fee1f19bd098c0d7407b64b280afd76a450067a89ab2bddd3e8', + tx_pos: 1, + value: 546, + txid: + 'aa50baef76708fee1f19bd098c0d7407b64b280afd76a450067a89ab2bddd3e8', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '2', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + 'bfc175d1933aed136d7bd887481144ec42112c34e7889cf3f21013409e233e3d', + tx_pos: 1, + value: 546, + txid: + 'bfc175d1933aed136d7bd887481144ec42112c34e7889cf3f21013409e233e3d', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '3', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + 'c2d2e57203f5d66c3bddd3f4fd5ccb053006588bfa0fec76bdbbfd2169984e9c', + tx_pos: 1, + value: 546, + txid: + 'c2d2e57203f5d66c3bddd3f4fd5ccb053006588bfa0fec76bdbbfd2169984e9c', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681190, + tx_hash: + 'e9dca9aa954131a0004325fff11dfddcd6e5843c468116cf4d38cb264032cdc0', + tx_pos: 1, + value: 546, + txid: + 'e9dca9aa954131a0004325fff11dfddcd6e5843c468116cf4d38cb264032cdc0', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1f6a65e7a4bde92c0a012de2bcf4007034504a765377cdf08a3ee01d1eaa6901', + tokenTicker: '🍔', + tokenName: 'Burger', + tokenDocumentUrl: + 'https://c4.wallpaperflare.com/wallpaper/58/564/863/giant-hamburger-wallpaper-preview.jpg', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + '091c9f32deb2f4f3733673803f51acf050b65d8042d1561824c6cd22d14bb43b', + tx_pos: 1, + value: 546, + txid: + '091c9f32deb2f4f3733673803f51acf050b65d8042d1561824c6cd22d14bb43b', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenTicker: 'NOCOVID', + tokenName: 'Covid19 Lifetime Immunity', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '5', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + 'b35c502f388cdfbdd6841b7a73e973149b3c8deca76295a3e4665939e0562796', + tx_pos: 1, + value: 546, + txid: + 'b35c502f388cdfbdd6841b7a73e973149b3c8deca76295a3e4665939e0562796', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + 'dd84ca78db4d617221b58eabc6667af8fe2f7eadbfcc213d35be9f1b419beb8d', + tokenTicker: 'TAP', + tokenName: 'Thoughts and Prayers', + tokenDocumentUrl: '', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + 'c70408fca1a5bf48f338f7ef031e586293be6948a5bff1fbbdd4eb923ef11e59', + tx_pos: 1, + value: 546, + txid: + 'c70408fca1a5bf48f338f7ef031e586293be6948a5bff1fbbdd4eb923ef11e59', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb', + tokenTicker: 'NAKAMOTO', + tokenName: 'NAKAMOTO', + tokenDocumentUrl: '', + tokenDocumentHash: '', + decimals: 8, + tokenType: 1, + tokenQty: '1e-8', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + 'e1097932e5a607c100dc73fa18169be2e501e1782c7c94500742974d6353476c', + tx_pos: 1, + value: 546, + txid: + 'e1097932e5a607c100dc73fa18169be2e501e1782c7c94500742974d6353476c', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '7f8889682d57369ed0e32336f8b7e0ffec625a35cca183f4e81fde4e71a538a1', + tokenTicker: 'HONK', + tokenName: 'HONK HONK', + tokenDocumentUrl: 'THE REAL HONK SLP TOKEN', + tokenDocumentHash: '', + decimals: 0, + tokenType: 1, + tokenQty: '1', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681191, + tx_hash: + 'f6ef57f697219aaa576bf43d69a7f8b8753dcbcbb502f602259a7d14fafd52c5', + tx_pos: 1, + value: 546, + txid: + 'f6ef57f697219aaa576bf43d69a7f8b8753dcbcbb502f602259a7d14fafd52c5', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '1e-9', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681192, + tx_hash: + '43a925c679debac91183b0ccd08780cc94dc58d79cdb506df92ed5963c6bbb34', + tx_pos: 1, + value: 546, + txid: + '43a925c679debac91183b0ccd08780cc94dc58d79cdb506df92ed5963c6bbb34', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '2e-9', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681192, + tx_hash: + '880baf5691c2b4c5a22ae4032e2004c0c54bfabf003468044a2e341846137136', + tx_pos: 1, + value: 546, + txid: + '880baf5691c2b4c5a22ae4032e2004c0c54bfabf003468044a2e341846137136', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '3e-9', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681192, + tx_hash: + 'b7f8b23f5ce12842eb655239919b6142052a2fa2b2ce974a4baac36b0137f332', + tx_pos: 1, + value: 546, + txid: + 'b7f8b23f5ce12842eb655239919b6142052a2fa2b2ce974a4baac36b0137f332', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '4e-9', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + { + height: 681192, + tx_hash: + 'f27ff24c15b01c30d44218c6dc8706fd33cc7bc9b4b38399075f0f41d8e412af', + tx_pos: 1, + value: 546, + txid: + 'f27ff24c15b01c30d44218c6dc8706fd33cc7bc9b4b38399075f0f41d8e412af', + vout: 1, + utxoType: 'token', + transactionType: 'send', + tokenId: + '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', + tokenTicker: 'XBIT', + tokenName: 'eBits', + tokenDocumentUrl: 'https://boomertakes.com/', + tokenDocumentHash: '', + decimals: 9, + tokenType: 1, + tokenQty: '5e-9', + isValid: true, + address: 'bitcoincash:qqartrrq3npyzpcqswq2hcslstzu38mq8gvgtuqfpf', + }, + ], +}; diff --git a/web/cashtab/src/utils/__mocks__/mockBatchedArrays.js b/web/cashtab/src/utils/__mocks__/mockBatchedArrays.js new file mode 100644 index 000000000..711527eb9 --- /dev/null +++ b/web/cashtab/src/utils/__mocks__/mockBatchedArrays.js @@ -0,0 +1,3 @@ +// @generated +export const unbatchedArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; +export const arrayBatchedByThree = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]; diff --git a/web/cashtab/src/utils/__tests__/cashMethods.test.js b/web/cashtab/src/utils/__tests__/cashMethods.test.js index 0c2f6b6c4..2ce1596f9 100644 --- a/web/cashtab/src/utils/__tests__/cashMethods.test.js +++ b/web/cashtab/src/utils/__tests__/cashMethods.test.js @@ -1,40 +1,69 @@ -import { fromSmallestDenomination, formatBalance } from '@utils/cashMethods'; +import { + fromSmallestDenomination, + formatBalance, + batchArray, + flattenBatchedHydratedUtxos, +} from '@utils/cashMethods'; +import { + unbatchedArray, + arrayBatchedByThree, +} from '../__mocks__/mockBatchedArrays'; + +import { + originalFinal, + batchedFinal, + unflattenedHydrateUtxosResponse, + flattenedHydrateUtxosResponse, +} from '../__mocks__/flattenBatchedHydratedUtxosMocks'; describe('Correctly executes cash utility functions', () => { it(`Correctly converts smallest base unit to smallest decimal for cashDecimals = 2`, () => { expect(fromSmallestDenomination(1, 2)).toBe(0.01); }); it(`Correctly converts largest base unit to smallest decimal for cashDecimals = 2`, () => { expect(fromSmallestDenomination(1000000012345678, 2)).toBe( 10000000123456.78, ); }); it(`Correctly converts smallest base unit to smallest decimal for cashDecimals = 8`, () => { expect(fromSmallestDenomination(1, 8)).toBe(0.00000001); }); it(`Correctly converts largest base unit to smallest decimal for cashDecimals = 8`, () => { expect(fromSmallestDenomination(1000000012345678, 8)).toBe( 10000000.12345678, ); }); it(`Formats a large number to add spaces as thousands separator`, () => { expect(formatBalance(1000000012345678)).toBe('1 000 000 012 345 678'); }); it(`Formats a large number with 2 decimal places to add as thousands separator`, () => { expect(formatBalance(10000000123456.78)).toBe('10 000 000 123 456.78'); }); it(`Formats a large number with 9 decimal places to add as thousands separator without adding them to decimals`, () => { expect(formatBalance('10000000123456.789123456')).toBe( '10 000 000 123 456.789123456', ); }); it(`formatBalance handles an input of 0`, () => { expect(formatBalance('0')).toBe('0'); }); it(`formatBalance handles an input of undefined`, () => { expect(formatBalance(undefined)).toBe(undefined); }); it(`formatBalance handles an input of null`, () => { expect(formatBalance(null)).toBe(null); }); + it(`Correctly converts an array of length 10 to an array of 4 arrays, each with max length 3`, () => { + expect(batchArray(unbatchedArray, 3)).toStrictEqual( + arrayBatchedByThree, + ); + }); + it(`If array length is less than batch size, return original array as first and only element of new array`, () => { + expect(batchArray(unbatchedArray, 20)).toStrictEqual([unbatchedArray]); + }); + it(`Flattens hydrateUtxos from Promise.all() response into array that can be parsed by getSlpBalancesAndUtxos`, () => { + expect( + flattenBatchedHydratedUtxos(unflattenedHydrateUtxosResponse), + ).toStrictEqual(flattenedHydrateUtxosResponse); + }); }); diff --git a/web/cashtab/src/utils/cashMethods.js b/web/cashtab/src/utils/cashMethods.js index 77b82f545..4d4d5f80c 100644 --- a/web/cashtab/src/utils/cashMethods.js +++ b/web/cashtab/src/utils/cashMethods.js @@ -1,48 +1,104 @@ import { currency } from '@components/Common/Ticker'; import BigNumber from 'bignumber.js'; export const fromSmallestDenomination = ( amount, cashDecimals = currency.cashDecimals, ) => { const amountBig = new BigNumber(amount); const multiplier = new BigNumber(10 ** (-1 * cashDecimals)); const amountInBaseUnits = amountBig.times(multiplier); return amountInBaseUnits.toNumber(); }; export const toSmallestDenomination = ( sendAmount, cashDecimals = currency.cashDecimals, ) => { // Replace the BCH.toSatoshi method with an equivalent function that works for arbitrary decimal places // Example, for an 8 decimal place currency like Bitcoin // Input: a BigNumber of the amount of Bitcoin to be sent // Output: a BigNumber of the amount of satoshis to be sent, or false if input is invalid // Validate // Input should be a BigNumber with no more decimal places than cashDecimals const isValidSendAmount = BigNumber.isBigNumber(sendAmount) && sendAmount.dp() <= cashDecimals; if (!isValidSendAmount) { return false; } const conversionFactor = new BigNumber(10 ** cashDecimals); const sendAmountSmallestDenomination = sendAmount.times(conversionFactor); return sendAmountSmallestDenomination; }; export const formatBalance = x => { try { let balanceInParts = x.toString().split('.'); balanceInParts[0] = balanceInParts[0].replace( /\B(?=(\d{3})+(?!\d))/g, ' ', ); return balanceInParts.join('.'); } catch (err) { console.log(`Error in formatBalance for ${x}`); console.log(err); return x; } }; + +export const batchArray = (inputArray, batchSize) => { + // take an array of n elements, return an array of arrays each of length batchSize + + const batchedArray = []; + for (let i = 0; i < inputArray.length; i += batchSize) { + const tempArray = inputArray.slice(i, i + batchSize); + batchedArray.push(tempArray); + } + return batchedArray; +}; + +export const flattenBatchedHydratedUtxos = batchedHydratedUtxoDetails => { + // Return same result as if only the bulk API call were made + // to do this, just need to move all utxos under one slpUtxos + /* + given + [ + { + slpUtxos: [ + { + utxos: [], + address: '', + } + ], + }, + { + slpUtxos: [ + { + utxos: [], + address: '', + } + ], + } + ] + return [ + { + slpUtxos: [ + { + utxos: [], + address: '' + }, + { + utxos: [], + address: '' + }, + ] + } + */ + const flattenedBatchedHydratedUtxos = { slpUtxos: [] }; + for (let i = 0; i < batchedHydratedUtxoDetails.length; i += 1) { + const theseSlpUtxos = batchedHydratedUtxoDetails[i].slpUtxos[0]; + flattenedBatchedHydratedUtxos.slpUtxos.push(theseSlpUtxos); + } + return flattenedBatchedHydratedUtxos; +};