Changeset View
Changeset View
Standalone View
Standalone View
web/cashtab/src/utils/cashMethods.js
import { currency } from '@components/Common/Ticker'; | import { currency } from '@components/Common/Ticker'; | ||||
import BigNumber from 'bignumber.js'; | import BigNumber from 'bignumber.js'; | ||||
import isEqual from 'lodash.isequal'; | |||||
import differenceWith from 'lodash.differencewith'; | |||||
import { isEmpty } from 'lodash'; | |||||
import { previousUtxos } from './__mocks__/mockChangingUtxos'; | |||||
export const fromSmallestDenomination = ( | export const fromSmallestDenomination = ( | ||||
amount, | amount, | ||||
cashDecimals = currency.cashDecimals, | cashDecimals = currency.cashDecimals, | ||||
) => { | ) => { | ||||
const amountBig = new BigNumber(amount); | const amountBig = new BigNumber(amount); | ||||
const multiplier = new BigNumber(10 ** (-1 * cashDecimals)); | const multiplier = new BigNumber(10 ** (-1 * cashDecimals)); | ||||
const amountInBaseUnits = amountBig.times(multiplier); | const amountInBaseUnits = amountBig.times(multiplier); | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | export const batchArray = (inputArray, batchSize) => { | ||||
const batchedArray = []; | const batchedArray = []; | ||||
for (let i = 0; i < inputArray.length; i += batchSize) { | for (let i = 0; i < inputArray.length; i += batchSize) { | ||||
const tempArray = inputArray.slice(i, i + batchSize); | const tempArray = inputArray.slice(i, i + batchSize); | ||||
batchedArray.push(tempArray); | batchedArray.push(tempArray); | ||||
} | } | ||||
return batchedArray; | return batchedArray; | ||||
}; | }; | ||||
export const organizeHydratedUtxoDetailsByAddress = hydratedUtxoDetails => { | |||||
/* | |||||
Given | |||||
{ | |||||
slpUtxos: [ | |||||
{ | |||||
utxos: [n existing hydrated utxos at address1], | |||||
address: 'address1', | |||||
} | |||||
{ | |||||
utxos: [k existing hydrated utxos also at address1], | |||||
address: 'address1', | |||||
} | |||||
], | |||||
} | |||||
Return | |||||
Given | |||||
{ | |||||
slpUtxos: [ | |||||
{ | |||||
utxos: [n+k existing hydrated utxos at address1], | |||||
address: 'address1', | |||||
} | |||||
], | |||||
} | |||||
*/ | |||||
// First, get all the addresses | |||||
const addressesInHydratedUtxoDetails = []; | |||||
for (let i = 0; i < hydratedUtxoDetails.slpUtxos.length; i += 1) { | |||||
const thisAddress = hydratedUtxoDetails.slpUtxos[i].address; | |||||
if (addressesInHydratedUtxoDetails.includes(thisAddress)) { | |||||
continue; | |||||
} else { | |||||
addressesInHydratedUtxoDetails.push(thisAddress); | |||||
} | |||||
} | |||||
// If addressesInHydratedUtxoDetails.length === hydratedUtxoDetails.slpUtxos.length, then you have no duplicate addresses, just return the input | |||||
if ( | |||||
addressesInHydratedUtxoDetails.length === | |||||
hydratedUtxoDetails.slpUtxos.length | |||||
) { | |||||
return hydratedUtxoDetails; | |||||
} else { | |||||
const organizedHydratedUtxoDetails = { slpUtxos: [] }; | |||||
// Iterate over all addresses in hydratedUtxoDetails.slpUtxos | |||||
for (let j = 0; j < addressesInHydratedUtxoDetails.length; j += 1) { | |||||
const thisAddress = addressesInHydratedUtxoDetails[j]; | |||||
let utxosAtThisAddress = []; | |||||
// Iterate over hydratedUtxoDetails.slpUtxos and build up a utxos array for this address | |||||
for (let k = 0; k < hydratedUtxoDetails.slpUtxos.length; k += 1) { | |||||
const thisAddressInHydratedUtxoDetails = | |||||
hydratedUtxoDetails.slpUtxos[k].address; | |||||
if (thisAddress === thisAddressInHydratedUtxoDetails) { | |||||
const hydratedUtxosAtThisAddress = | |||||
hydratedUtxoDetails.slpUtxos[k].utxos; | |||||
utxosAtThisAddress = utxosAtThisAddress.concat( | |||||
hydratedUtxosAtThisAddress, | |||||
); | |||||
} | |||||
} | |||||
organizedHydratedUtxoDetails.slpUtxos.push({ | |||||
address: thisAddress, | |||||
utxos: utxosAtThisAddress, | |||||
}); | |||||
} | |||||
return organizedHydratedUtxoDetails; | |||||
} | |||||
}; | |||||
// TODO unit test the fuck out of this, see if replaces mergeHydratedUtxoDetails | |||||
export const addHydratedUtxoDetailsToWalletStateIfNew = ( | |||||
previousHydratedUtxoDetails, | |||||
newHydratedUtxoDetails, | |||||
) => { | |||||
let mergedHydratedUtxoDetails = previousHydratedUtxoDetails; | |||||
// Accepts the output of organizeHydratedUtxoDetailsByAddress(previousHydratedUtxoDetails) | |||||
// For each new utxo in newHydratedUtxoDetails, adds it to previousHydratedUtxoDetails at the correct address (if the utxo does not already exist in previousHydratedUtxoDetails) | |||||
// Iterate over your new utxos | |||||
// First, iterate over the {address: '', utxos: []} object | |||||
for (let i = 0; i < newHydratedUtxoDetails.slpUtxos.length; i += 1) { | |||||
const addressOfTheseNewHydratedUtxos = | |||||
newHydratedUtxoDetails.slpUtxos[i].address; | |||||
const newUtxosAtThisAddress = newHydratedUtxoDetails.slpUtxos[i].utxos; | |||||
// For these utxos, see if you can find a matching address in previousHydratedUtxoDetails | |||||
let addressExistsInPreviouslyHydratedUtxoDetails = false; | |||||
for ( | |||||
let j = 0; | |||||
j < previousHydratedUtxoDetails.slpUtxos.length; | |||||
j += 1 | |||||
) { | |||||
const addressOfThesePreviousHydratedUtxoDetailsUtxos = | |||||
previousHydratedUtxoDetails.slpUtxos[j].address; | |||||
if ( | |||||
addressOfTheseNewHydratedUtxos === | |||||
addressOfThesePreviousHydratedUtxoDetailsUtxos | |||||
) { | |||||
addressExistsInPreviouslyHydratedUtxoDetails = true; | |||||
mergedHydratedUtxoDetails.slpUtxos[ | |||||
j | |||||
].utxos = mergedHydratedUtxoDetails.slpUtxos[j].utxos.concat( | |||||
newUtxosAtThisAddress, | |||||
); | |||||
// Only add it if not a duplicate | |||||
//array3 = [...new Set([...array1,...array2])] | |||||
mergedHydratedUtxoDetails.slpUtxos[j].utxos = [ | |||||
...new Set([ | |||||
...mergedHydratedUtxoDetails.slpUtxos[j].utxos, | |||||
...newUtxosAtThisAddress, | |||||
]), | |||||
]; | |||||
} | |||||
} | |||||
if (!addressExistsInPreviouslyHydratedUtxoDetails) { | |||||
// If these utxos exist at a new address, add a new {utxos: [], address: ''} object to mergedHydratedUtxoDetails.slpUtxos | |||||
mergedHydratedUtxoDetails.slpUtxos.push({ | |||||
address: addressOfTheseNewHydratedUtxos, | |||||
utxos: newUtxosAtThisAddress, | |||||
}); | |||||
} | |||||
} | |||||
return mergedHydratedUtxoDetails; | |||||
}; | |||||
export const mergeHydratedUtxoDetails = ( | |||||
previousHydratedUtxoDetails, | |||||
newHydratedUtxoDetails, | |||||
) => { | |||||
// Rev 3 | |||||
/* | |||||
For each utxo in newHydratedUtxoDetails | |||||
- if it exists anywhere in previousHydratedUtxoDetails, do not add it | |||||
- if it doesn't exist in previousHydratedUtxoDetails | |||||
- if its address exists in previousHydratedUtxoDetails, add it at correct address | |||||
- if not, add it as a new {address: '', utxos: [newUtxo]} entry | |||||
*/ | |||||
// TODO | |||||
// if previousHydratedUtxoDetails has duplicate address objs, flatten it | |||||
// NOTE THIS APPROACH ASSUMES previousHydratedUtxoDetails does not have duplicate address objs...which is not true right now | |||||
// Iterate over the {address: '', utxos: []} objects in newHydratedUtxoDetails.slpUtxos | |||||
for (let i = 0; i < newHydratedUtxoDetails.slpUtxos.length; i += 1) { | |||||
// iterate over the utxos in the address group | |||||
const addressOfThisNewHydratedUtxo = | |||||
newHydratedUtxoDetails.slpUtxos[i].address; | |||||
const newHydratedUtxosAtThisAddress = | |||||
newHydratedUtxoDetails.slpUtxos[i].utxos; | |||||
// Iterate over the new hydrated utxos at this address | |||||
for (let j = 0; j < newHydratedUtxosAtThisAddress.length; j += 1) { | |||||
const thisNewHydratedUtxo = newHydratedUtxosAtThisAddress[j]; | |||||
// Flag variable to check if this address does not exist in previousHydratedUtxoDetails | |||||
let existingWalletAddress = false; | |||||
// Iterate over the {address: '', utxos: []} objects in previousHydratedUtxoDetails.slpUtxos to see if utxos already exist at addressOfThisNewHydratedUtxo | |||||
for ( | |||||
let k = 0; | |||||
k < previousHydratedUtxoDetails.slpUtxos.length; | |||||
k += 1 | |||||
) { | |||||
const addressOfThisPreviousHydratedUtxo = | |||||
previousHydratedUtxoDetails.slpUtxos[k].address; | |||||
// If the thisNewHydratedUtxo is at the same address, determine if it should be added there | |||||
if ( | |||||
addressOfThisNewHydratedUtxo === | |||||
addressOfThisPreviousHydratedUtxo | |||||
) { | |||||
// This is not a new address | |||||
existingWalletAddress = true; | |||||
// If this utxo does not already exist at this address, then add it | |||||
let utxoAlreadyExists = false; | |||||
const previousHydratedUtxosAtThisAddress = | |||||
previousHydratedUtxoDetails.slpUtxos[k].utxos; | |||||
// Iterate over previousHydratedUtxosAtThisAddress to see if there is a utxo with the same tx_hash | |||||
for ( | |||||
let m = 0; | |||||
m < previousHydratedUtxosAtThisAddress.length; | |||||
m += 1 | |||||
) { | |||||
if ( | |||||
previousHydratedUtxosAtThisAddress[m].tx_hash === | |||||
thisNewHydratedUtxo.tx_hash | |||||
) { | |||||
utxoAlreadyExists = true; | |||||
// Do not add it to merged array | |||||
} | |||||
} | |||||
// add thisNewHydratedUtxo if it's not there | |||||
if (!utxoAlreadyExists) { | |||||
previousHydratedUtxosAtThisAddress.push( | |||||
thisNewHydratedUtxo, | |||||
); | |||||
} | |||||
} | |||||
} | |||||
// If this address did not exist, add a new address obj for this utxo | |||||
if (!existingWalletAddress) { | |||||
const newHydratedUtxoObj = { | |||||
address: addressOfThisNewHydratedUtxo, | |||||
utxos: [thisNewHydratedUtxo], | |||||
}; | |||||
previousHydratedUtxoDetails.slpUtxos.push(newHydratedUtxoObj); | |||||
} | |||||
} | |||||
} | |||||
// TODO : only combine if utxos are not existing | |||||
/* | |||||
Given | |||||
NB a 'hydrated' utxo is a utxo where token information has been added | |||||
previousHydratedUtxoDetails in format: | |||||
{ | |||||
slpUtxos: [ | |||||
{ | |||||
utxos: [n existing hydrated utxos at address1], | |||||
address: 'address1', | |||||
} | |||||
{ | |||||
utxos: [k existing hydrated utxos at address2], | |||||
address: 'address2', | |||||
} | |||||
], | |||||
}, | |||||
newHydratedUtxoDetails in format: | |||||
{ | |||||
slpUtxos: [ | |||||
{ | |||||
utxos: [x new hydrated utxos at address1], | |||||
address: 'address1', | |||||
} | |||||
{ | |||||
utxos: [y new hydrated utxos at address2], | |||||
address: 'address2', | |||||
} | |||||
], | |||||
} | |||||
Return | |||||
mergedHydratedUtxoDetails in format: | |||||
{ | |||||
slpUtxos: [ | |||||
{ | |||||
utxos: [n existing hydrated utxos at address1], | |||||
address: 'address1', | |||||
} | |||||
{ | |||||
utxos: [k existing hydrated utxos at address2], | |||||
address: 'address2', | |||||
} | |||||
{ | |||||
utxos: [x new hydrated utxos at address1], | |||||
address: 'address1', | |||||
} | |||||
{ | |||||
utxos: [y new hydrated utxos at address2], | |||||
address: 'address2', | |||||
} | |||||
], | |||||
} | |||||
*/ | |||||
let mergedHydratedUtxoDetails = {}; | |||||
let mergedSlpUtxos = []; | |||||
mergedSlpUtxos = previousHydratedUtxoDetails.slpUtxos.concat( | |||||
newHydratedUtxoDetails.slpUtxos, | |||||
); | |||||
mergedHydratedUtxoDetails.slpUtxos = mergedSlpUtxos; | |||||
return mergedHydratedUtxoDetails; | |||||
/* Initial attempt | |||||
Return | |||||
mergedHydratedUtxoDetails | |||||
newHydratedUtxoDetails in format: | |||||
{ | |||||
slpUtxos: [ | |||||
{ | |||||
utxos: [n+x total hydrated utxos at address1], | |||||
address: 'address1', | |||||
}, | |||||
{ | |||||
utxos: [k+y total hydrated utxos at address2], | |||||
address: 'address2', | |||||
}, | |||||
{ | |||||
utxos: [any new utxos at a new address (for HD wallet support)], | |||||
address: 'address3', | |||||
} | |||||
], | |||||
} | |||||
// Initialize the merged utxo set with the previous set | |||||
const mergedHydratedUtxoDetails = previousHydratedUtxoDetails; | |||||
// Iterate over newHydratedUtxoDetails | |||||
// It's each one of these utxos that requires action | |||||
for (let i = 0; i < newHydratedUtxoDetails.slpUtxos.length; i += 1) { | |||||
const thisNewHydratedUtxoDetailsAddress = | |||||
newHydratedUtxoDetails.slpUtxos[i].address; | |||||
const thisNewHydratedUtxoDetailsUtxos = | |||||
newHydratedUtxoDetails.slpUtxos[i].utxos; | |||||
for ( | |||||
let j = 0; | |||||
j < previousHydratedUtxoDetails.slpUtxos.length; | |||||
j += 1 | |||||
) { | |||||
const thisPreviouslyHydratedUtxoDetailsAddress = | |||||
previousHydratedUtxoDetails.slpUtxos[j].address; | |||||
let addressExistsInPreviouslyHydratedUtxoDetails = false; | |||||
// look for the matching address | |||||
if ( | |||||
thisNewHydratedUtxoDetailsAddress === | |||||
thisPreviouslyHydratedUtxoDetailsAddress | |||||
) { | |||||
// If find matching address, add all utxos from newHydratedUtxoDetail to previous | |||||
mergedHydratedUtxoDetails.slpUtxos[j].utxos.concat( | |||||
thisNewHydratedUtxoDetailsUtxos, | |||||
); | |||||
addressExistsInPreviouslyHydratedUtxoDetails = true; | |||||
} | |||||
} | |||||
// if this is a new address, add them as their own object | |||||
} | |||||
*/ | |||||
}; | |||||
export const flattenBatchedHydratedUtxos = batchedHydratedUtxoDetails => { | export const flattenBatchedHydratedUtxos = batchedHydratedUtxoDetails => { | ||||
// Return same result as if only the bulk API call were made | // Return same result as if only the bulk API call were made | ||||
// to do this, just need to move all utxos under one slpUtxos | // to do this, just need to move all utxos under one slpUtxos | ||||
/* | /* | ||||
given | given | ||||
[ | [ | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | return ( | ||||
typeof walletStateFromStorage.state === 'object' && | typeof walletStateFromStorage.state === 'object' && | ||||
'balances' in walletStateFromStorage.state && | 'balances' in walletStateFromStorage.state && | ||||
'utxos' in walletStateFromStorage.state && | 'utxos' in walletStateFromStorage.state && | ||||
'hydratedUtxoDetails' in walletStateFromStorage.state && | 'hydratedUtxoDetails' in walletStateFromStorage.state && | ||||
'slpBalancesAndUtxos' in walletStateFromStorage.state && | 'slpBalancesAndUtxos' in walletStateFromStorage.state && | ||||
'tokens' in walletStateFromStorage.state | 'tokens' in walletStateFromStorage.state | ||||
); | ); | ||||
}; | }; | ||||
export const whichUtxosWereConsumed = ( | |||||
currentUtxos, | |||||
previousUtxos, | |||||
utxosConfirmed, | |||||
) => { | |||||
/* | |||||
Determine if the utxo set received from the API is missing utxos contained in wallet.state | |||||
If so, these utxos have been spent and should be removed from wallet.state | |||||
If currentUtxos.length < previousUtxos.length...then utxos have certainly been spent | |||||
But you want a generalized way of doing this. Most of the time, making a transaction involves | |||||
sending a utxo and getting one as change; so you cannot rely on length change to solve this problem | |||||
Function is called if haveUtxosChanged is true | |||||
*/ | |||||
// Iterate over previousUtxos | |||||
// For each {address: '', utxos: []} object, i.e. the utxo set at each address in the wallet | |||||
// Determine if you have previousUtxos that do not exist in currentUtxos | |||||
let consumedUtxos = []; | |||||
for (let i = 0; i < previousUtxos.length; i += 1) { | |||||
const thisAddress = previousUtxos[i].address; | |||||
const consumedUtxosAtThisAddress = {}; | |||||
consumedUtxosAtThisAddress.address = thisAddress; | |||||
consumedUtxosAtThisAddress.utxos = differenceWith( | |||||
previousUtxos[i].utxos, | |||||
currentUtxos[i].utxos, | |||||
isEqual, | |||||
); | |||||
// TODO | |||||
// if only the height changed, don't include it here | |||||
// we don't want to throw out a utxo because it confirmed | |||||
consumedUtxos.push(consumedUtxosAtThisAddress); | |||||
} | |||||
// Remove any consumedUtxos that are only tx confirmations | |||||
for (let i = 0; i < utxosConfirmed.length; i += 1) { | |||||
const addressOfTheseConfirmedUtxos = utxosConfirmed[i].address; | |||||
for (let j = 0; j < consumedUtxos.length; j += 1) { | |||||
const addressOfTheseConsumedUtxos = consumedUtxos[j].address; | |||||
if (addressOfTheseConfirmedUtxos === addressOfTheseConsumedUtxos) { | |||||
const theseConfirmedUtxos = utxosConfirmed[i].utxos; | |||||
const theseConsumedUtxos = consumedUtxos[j].utxos; | |||||
for (let k = 0; k < theseConfirmedUtxos.length; k += 1) { | |||||
const thisConfirmedUtxo = theseConfirmedUtxos[k]; | |||||
for (let z = 0; z < theseConsumedUtxos.length; z += 1) { | |||||
const thisConsumedUtxo = theseConsumedUtxos[z]; | |||||
// If a consumed utxo has the same txid as a confirmed utxo | |||||
if ( | |||||
thisConsumedUtxo.tx_hash === | |||||
thisConfirmedUtxo.tx_hash | |||||
) { | |||||
// Remove it from the set, it was already picked up by parsedChangedUtxos() | |||||
consumedUtxos[j].utxos.splice(z, 1); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
return consumedUtxos; | |||||
// Note that whichUtxosChanged will catch utxos with only a changed height | |||||
// So, you should run that first...then run this to see what's duplicated...then filter them out | |||||
}; | |||||
export const whichUtxosChanged = (currentUtxos, previousUtxos) => { | |||||
/* | |||||
Function only compares valid utxos arrays of type expected from | |||||
getUtxos function from useBCH.js | |||||
Note, this function is only called if haveUtxosChanged() from useBCH.js returns true | |||||
This can happen in two ways: | |||||
1) An existing utxo is confirmed in a block | |||||
2) The user has sent or received utxos | |||||
If we have case (1), then we should update the transaction history to show confirmed | |||||
If we have case (2) then we need to return that utxo for additional parsing | |||||
So, this function should return both the changed utxos and whether or not | |||||
*/ | |||||
// Function to only hydrate changed utxos, instead of entire set | |||||
// Helper function to identify which utxos have changed | |||||
// This allows faster updates of utxo set | |||||
/* DEV NOTE | |||||
currentUtxos and previousUtxos are arrays of objects (see below) | |||||
Hence, to find individual utxos, you need to examine the currentUtxos[i].utxos array | |||||
currentUtxos and previousUtxos will always be the same size, as they are derived from the | |||||
same wallet object | |||||
utxos = | |||||
[ | |||||
{ | |||||
utxos: [], | |||||
address: 'bitcoincash:cashAddress1', | |||||
}, | |||||
{ | |||||
utxos: [], | |||||
address: 'bitcoincash:cashAddress2', | |||||
}, | |||||
{ | |||||
utxos: | |||||
[ | |||||
{ | |||||
height: 681188, | |||||
tx_hash: | |||||
'5b74e05ced6b7d862fe9cab94071b2ccfa475c0cef94b90c7edb8a06f90e5ad6', | |||||
tx_pos: 1, | |||||
value: 546, | |||||
}, | |||||
{ | |||||
height: 681189, | |||||
tx_hash: | |||||
'0aacdb7d85c466a7d6d4edf127883da40b05617d9c4ff7493bde3c973f22231d', | |||||
tx_pos: 1, | |||||
value: 546, | |||||
}, | |||||
{ | |||||
height: 681189, | |||||
tx_hash: | |||||
'2cc8f480e9adfb74aff7351bdbbf12ed8972e35fb8bd0f43b9ea5e4aeaec5693', | |||||
tx_pos: 1, | |||||
value: 546, | |||||
} | |||||
], | |||||
address: 'bitcoincash:cashAddress3', | |||||
} | |||||
] | |||||
*/ | |||||
let changedUtxos = []; | |||||
for (let i = 0; i < currentUtxos.length; i += 1) { | |||||
// Push the it to your changedUtxos array | |||||
// You may have more than 1 utxo, so you need to track it this way | |||||
// TODO add array to array | |||||
const changedUtxosAtThisAddress = {}; | |||||
changedUtxosAtThisAddress.utxos = differenceWith( | |||||
currentUtxos[i].utxos, | |||||
previousUtxos[i].utxos, | |||||
isEqual, | |||||
); | |||||
changedUtxosAtThisAddress.address = currentUtxos[i].address; | |||||
changedUtxos.push(changedUtxosAtThisAddress); | |||||
// TODO -- you need to know the address param of each changed utxo | |||||
} | |||||
// Expected behavior: if currentUtxos === previousUtxos, then changedUtxos = [] | |||||
// UPDATE not anymore, changedUtxos would be an empty template with all addresses of currentUtxos | |||||
return changedUtxos; | |||||
}; | |||||
export const parseConsumedUtxos = (currentUtxos, consumedUtxos) => { | |||||
// only include utxos where tx_hash is no longer present | |||||
// throw out utxos where heigh changed | |||||
}; | |||||
export const parseChangedUtxos = (previousUtxos, changedUtxos) => { | |||||
// do all of your iteration based on individual changedUtxos | |||||
// Start with blank template that includes the addresses of this utxo set | |||||
// Create two distinct arrays on the same template (list of addresses and utxos in wallet based on most recent utxo set) | |||||
const utxosConfirmed = whichUtxosChanged(changedUtxos, changedUtxos); | |||||
const utxosToHydrate = whichUtxosChanged(changedUtxos, changedUtxos); | |||||
// Iterate over changedUtxo array of objects to find your first changedUtxo | |||||
// First, iterate over the {address: 'str', utxos: []} objects | |||||
for (let i = 0; i < changedUtxos.length; i += 1) { | |||||
// Next, see if there are any changedUtxos at this address | |||||
const thisChangedUtxosAddress = changedUtxos[i].address; | |||||
const changedUtxosAtThisAddress = changedUtxos[i].utxos; | |||||
for (let j = 0; j < changedUtxosAtThisAddress.length; j += 1) { | |||||
// If changedUtxosAtThisAddress has any length, there are | |||||
const thisChangedUtxo = changedUtxosAtThisAddress[j]; | |||||
// Assume it must be hydrated | |||||
let utxoToBeHydrated = true; | |||||
// Now, start iterating over previousUtxos array to see if there is any utxo at the same address with the same tx_hash | |||||
for (let k = 0; k < previousUtxos.length; k += 1) { | |||||
const thisPreviousUtxosAddress = previousUtxos[k].address; | |||||
const previousUtxosAtThisAddress = previousUtxos[k].utxos; | |||||
// If addresses match, iterate over the previousUtxos at this address to find a match | |||||
if (thisChangedUtxosAddress === thisPreviousUtxosAddress) { | |||||
for ( | |||||
let z = 0; | |||||
z < previousUtxosAtThisAddress.length; | |||||
z += 1 | |||||
) { | |||||
const thisPreviousUtxo = previousUtxosAtThisAddress[z]; | |||||
// If tx_hash matches thisChangedUtxo tx_hash, then this is a confirmed tx | |||||
if ( | |||||
thisChangedUtxo.tx_hash === thisPreviousUtxo.tx_hash | |||||
) { | |||||
// Add it to the array of confirmed tx utxos at the appropriate address | |||||
utxosConfirmed[i].utxos.push(thisChangedUtxo); | |||||
// set utxoToBeHydrated to false | |||||
utxoToBeHydrated = false; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
// hydrate it if you couldn't find a utxo with matching tx_hash | |||||
if (utxoToBeHydrated) { | |||||
utxosToHydrate[i].utxos.push(thisChangedUtxo); | |||||
} | |||||
} | |||||
} | |||||
// Return your arrays | |||||
return { utxosConfirmed, utxosToHydrate }; | |||||
}; | |||||
export const isUtxoArrayEmpty = utxoDeltaArray => { | |||||
// Determine if a utxosConfirmed or utxosToHydrate array is empty | |||||
// A utxosConfirmed or utxosToHydrate array is empty if every utxos array in its n {address: '', utxos: []} objects is empty | |||||
for (let i = 0; i < utxoDeltaArray.length; i += 1) { | |||||
const utxosAtThisAddress = utxoDeltaArray[i].utxos; | |||||
if (utxosAtThisAddress.length > 0) { | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
}; | |||||
export const removeConsumedUtxosFromHydratedUtxoDetails = ( | |||||
organizedHydratedUtxoDetails, | |||||
consumedUtxos, | |||||
) => { | |||||
// Iterate over organizedHydratedUtxoDetails | |||||
// If you find matching utxos, remove them | |||||
let organizedHydratedUtxoDetailsWithoutConsumedUtxos = organizedHydratedUtxoDetails; | |||||
for (let i = 0; i < consumedUtxos.length; i += 1) { | |||||
const addressOfTheseConsumedUtxos = consumedUtxos[i].address; | |||||
const theseConsumedUtxos = consumedUtxos[i].utxos; | |||||
for ( | |||||
let j = 0; | |||||
j < organizedHydratedUtxoDetails.slpUtxos.length; | |||||
j += 1 | |||||
) { | |||||
const addressOfTheseHydratedUtxos = | |||||
organizedHydratedUtxoDetails.slpUtxos[j].address; | |||||
if (addressOfTheseConsumedUtxos === addressOfTheseHydratedUtxos) { | |||||
const theseHydratedUtxos = | |||||
organizedHydratedUtxoDetails.slpUtxos[j].utxos; | |||||
for (let k = 0; k < theseConsumedUtxos.length; k += 1) { | |||||
const thisConsumedUtxo = theseConsumedUtxos[k]; | |||||
for (let z = 0; z < theseHydratedUtxos.length; z += 1) { | |||||
const thisHydratedUtxo = theseHydratedUtxos[z]; | |||||
// If this hydrated utxo exists in consumedUtxos | |||||
if ( | |||||
thisConsumedUtxo.tx_hash === | |||||
thisHydratedUtxo.tx_hash | |||||
) { | |||||
// remove it | |||||
organizedHydratedUtxoDetailsWithoutConsumedUtxos.slpUtxos[ | |||||
j | |||||
].utxos.splice(z, 1); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
return organizedHydratedUtxoDetailsWithoutConsumedUtxos; | |||||
}; |