Changeset View
Changeset View
Standalone View
Standalone View
apps/ecash-herald/src/utils.js
// Copyright (c) 2023 The Bitcoin developers | // Copyright (c) 2023 The Bitcoin developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
'use strict'; | 'use strict'; | ||||
const axios = require('axios'); | const axios = require('axios'); | ||||
const config = require('../config'); | const config = require('../config'); | ||||
const BigNumber = require('bignumber.js'); | |||||
module.exports = { | module.exports = { | ||||
returnAddressPreview: function (cashAddress, sliceSize = 3) { | returnAddressPreview: function (cashAddress, sliceSize = 3) { | ||||
const addressParts = cashAddress.split(':'); | const addressParts = cashAddress.split(':'); | ||||
const unprefixedAddress = addressParts[addressParts.length - 1]; | const unprefixedAddress = addressParts[addressParts.length - 1]; | ||||
return `${unprefixedAddress.slice( | return `${unprefixedAddress.slice( | ||||
0, | 0, | ||||
sliceSize, | sliceSize, | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | formatPrice: function (price, fiatCode) { | ||||
// All decimal places for lower prices | // All decimal places for lower prices | ||||
// For now, these will only be XEC prices | // For now, these will only be XEC prices | ||||
return `${fiatSymbol}${price.toLocaleString('en-us', { | return `${fiatSymbol}${price.toLocaleString('en-us', { | ||||
maximumFractionDigits: 8, | maximumFractionDigits: 8, | ||||
})}`; | })}`; | ||||
}, | }, | ||||
jsonReplacer: function (key, value) { | jsonReplacer: function (key, value) { | ||||
if (value instanceof Map) { | if (value instanceof Map) { | ||||
const keyValueArray = Array.from(value.entries()); | |||||
for (let i = 0; i < keyValueArray.length; i += 1) { | |||||
const thisKeyValue = keyValueArray[i]; // [key, value] | |||||
// If this is not an empty map | |||||
if (typeof thisKeyValue !== 'undefined') { | |||||
// Note: this value is an array of length 2 | |||||
// [key, value] | |||||
// Check if value is a big number | |||||
if (thisKeyValue[1] instanceof BigNumber) { | |||||
// Replace it | |||||
thisKeyValue[1] = { | |||||
// Note, if you use dataType: 'BigNumber', it will not work | |||||
// This must be reserved | |||||
// Use a term that is definitely not reserved but also recognizable as | |||||
// "the dev means BigNumber here" | |||||
dataType: 'BigNumberReplacer', | |||||
value: thisKeyValue[1].toString(), | |||||
}; | |||||
} | |||||
} | |||||
} | |||||
return { | return { | ||||
dataType: 'Map', | dataType: 'Map', | ||||
value: Array.from(value.entries()), | value: keyValueArray, | ||||
}; | }; | ||||
} else if (value instanceof Set) { | } else if (value instanceof Set) { | ||||
return { | return { | ||||
dataType: 'Set', | dataType: 'Set', | ||||
value: Array.from(value.keys()), | value: Array.from(value.keys()), | ||||
}; | }; | ||||
} else { | } else { | ||||
return value; | return value; | ||||
} | } | ||||
}, | }, | ||||
jsonReviver: function (key, value) { | jsonReviver: function (key, value) { | ||||
if (typeof value === 'object' && value !== null) { | if (typeof value === 'object' && value !== null) { | ||||
if (value.dataType === 'Map') { | if (value.dataType === 'Map') { | ||||
// If the map is not empty | |||||
if (typeof value.value[0] !== 'undefined') { | |||||
/* value.value is an array of keyValue arrays | |||||
* e.g. | |||||
* [ | |||||
* [key1, value1], | |||||
* [key2, value2], | |||||
* [key3, value3], | |||||
* ] | |||||
*/ | |||||
// Iterate over each keyValue of the map | |||||
for (let i = 0; i < value.value.length; i += 1) { | |||||
const thisKeyValuePair = value.value[i]; // [key, value] | |||||
let thisValue = thisKeyValuePair[1]; | |||||
if ( | |||||
thisValue && | |||||
thisValue.dataType === 'BigNumberReplacer' | |||||
) { | |||||
// If this is saved BigNumber, replace it with an actual BigNumber | |||||
// note, you can't use thisValue = new BigNumber(thisValue.value) | |||||
// Need to use this specific array entry | |||||
value.value[i][1] = new BigNumber( | |||||
value.value[i][1].value, | |||||
); | |||||
} | |||||
} | |||||
} | |||||
return new Map(value.value); | return new Map(value.value); | ||||
} | } | ||||
if (value.dataType === 'Set') { | if (value.dataType === 'Set') { | ||||
return new Set(value.value); | return new Set(value.value); | ||||
} | } | ||||
} | } | ||||
return value; | return value; | ||||
}, | }, | ||||
returnChronikTokenInfoPromise: function (chronik, tokenId, tokenInfoMap) { | |||||
/* returnChronikTokenInfoPromise | |||||
* | |||||
* For best performance, we want to use Promise.all() to make several | |||||
* chronik API calls at the same time | |||||
* | |||||
* This function returns a promise to ask chronik for token genesis info | |||||
* and add this info to a map | |||||
*/ | |||||
return new Promise((resolve, reject) => { | |||||
chronik.tx(tokenId).then( | |||||
txDetails => { | |||||
console.assert( | |||||
typeof txDetails.slpTxData.genesisInfo !== 'undefined', | |||||
`Error: no genesisInfo object for ${tokenId}`, | |||||
); | |||||
// Note: txDetails.slpTxData.genesisInfo only exists for token genesis txs | |||||
const genesisInfo = txDetails.slpTxData.genesisInfo; | |||||
tokenInfoMap.set(tokenId, genesisInfo); | |||||
resolve(true); | |||||
}, | |||||
err => { | |||||
reject(err); | |||||
}, | |||||
); | |||||
}); | |||||
}, | |||||
}; | }; |