status-desktop/ui/app/AppLayouts/Wallet/WalletUtils.qml

380 lines
20 KiB
QML
Raw Normal View History

pragma Singleton
import QtQuick 2.14
import utils 1.0
import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1 as StatusQUtils
import AppLayouts.Wallet.stores 1.0 as WalletStores
QtObject {
function colorizedChainPrefixNew(chainColors, prefix) {
if (!prefix)
return ""
const prefixes = prefix.split(":").filter(Boolean)
let prefixStr = ""
const lastPrefixEndsWithColumn = prefix.endsWith(":")
const defaultColor = Theme.palette.baseColor1
for (let i in prefixes) {
const pref = prefixes[i]
let col = chainColors[pref]
if (!col)
col = defaultColor
prefixStr += Utils.richColorText(pref, col)
// Avoid adding ":" if it was not there for the last prefix,
// because when user manually edits the address, it breaks editing
if (!(i === (prefixes.length - 1) && !lastPrefixEndsWithColumn)) {
prefixStr += Utils.richColorText(":", Theme.palette.baseColor1)
}
}
return prefixStr
}
// TODO: Remove dependency to RootStore by requesting model or chainColors as a parameter. Indeed, this
// method should be just replaced by `colorizedChainPrefixNew`
// Issue #15494
function colorizedChainPrefix(prefix) {
if (!prefix)
return ""
const prefixes = prefix.split(":").filter(Boolean)
let prefixStr = ""
const lastPrefixEndsWithColumn = prefix.endsWith(":")
const defaultColor = Theme.palette.baseColor1
for (let i in prefixes) {
const pref = prefixes[i]
let col = WalletStores.RootStore.colorForChainShortName(pref)
if (!col)
col = defaultColor
prefixStr += Utils.richColorText(pref, col)
// Avoid adding ":" if it was not there for the last prefix,
// because when user manually edits the address, it breaks editing
if (!(i === (prefixes.length - 1) && !lastPrefixEndsWithColumn)) {
prefixStr += Utils.richColorText(":", Theme.palette.baseColor1)
}
}
return prefixStr
}
function calculateConfirmationTimestamp(chainLayer, timestamp) {
if (chainLayer === 1) {
return timestamp + 12 * 4 // A block on layer1 is every 12s
}
return timestamp
}
function calculateFinalisationTimestamp(chainLayer, timestamp) {
if (chainLayer === 1) {
return timestamp + 12 * 64 // A block on layer1 is every 12s
}
return timestamp + Constants.time.secondsIn7Days
}
function addressToDisplay(address, chainShortNames, shortForm, hovered) {
let finalAddress = address
if (shortForm) {
finalAddress = StatusQUtils.Utils.elideText(address,6,4)
}
return hovered? WalletUtils.colorizedChainPrefix(chainShortNames) + Utils.richColorText(finalAddress, Theme.palette.directColor1) : chainShortNames + finalAddress
}
/**
Calculate max safe amount to be used when making a transaction
This logic is here to make sure there is enough eth to pay for the gas.
Context, when making a transaction, whatever the type: swap/bridge/send, you need eth to pay for the gas.
rationale: https://github.com/status-im/status-desktop/pull/14959#discussion_r1627110880
*/
function calculateMaxSafeSendAmount(value, symbol) {
if (symbol !== Constants.ethToken || value === 0) {
return value
}
return value - Math.max(0.0001, Math.min(0.01, value * 0.1))
}
function getLabelForEstimatedTxTime(estimatedFlag) {
switch(estimatedFlag) {
case Constants.TransactionEstimatedTime.Unknown:
return qsTr("~ Unknown")
case Constants.TransactionEstimatedTime.LessThanOneMin :
return qsTr("< 1 minute")
case Constants.TransactionEstimatedTime.LessThanThreeMins :
return qsTr("< 3 minutes")
case Constants.TransactionEstimatedTime.LessThanFiveMins:
return qsTr("< 5 minutes")
default:
return qsTr("> 5 minutes")
}
}
// Where: chainIds [string] - separated by `:`, e.g "42161:10:1"
function getNetworkShortNames(chainIds: string, flatNetworksModel) {
let networkString = ""
const chainIdsArray = chainIds.split(":")
for (let i = 0; i < chainIdsArray.length; i++) {
const nwShortName = StatusQUtils.ModelUtils.getByKey(flatNetworksModel, "chainId", Number(chainIdsArray[i]), "shortName")
if (!!nwShortName)
networkString = networkString + nwShortName + ':'
}
return networkString
}
function getRouterErrorBasedOnCode(code) {
if (code === "") {
return ""
}
switch(code) {
case Constants.routerErrorCodes.errInternal:
return qsTr("an internal error occurred")
case Constants.routerErrorCodes.errGeneric:
return qsTr("unknown error occurred, try again later")
case Constants.routerErrorCodes.processor.errFailedToParseBaseFee:
case Constants.routerErrorCodes.processor.errFailedToParsePercentageFee:
case Constants.routerErrorCodes.processor.errContractNotFound:
case Constants.routerErrorCodes.processor.errNetworkNotFound:
case Constants.routerErrorCodes.processor.errTokenNotFound:
case Constants.routerErrorCodes.processor.errNoEstimationFound:
case Constants.routerErrorCodes.processor.errNotAvailableForContractType:
case Constants.routerErrorCodes.processor.errNoBonderFeeFound:
case Constants.routerErrorCodes.processor.errContractTypeNotSupported:
case Constants.routerErrorCodes.processor.errFromChainNotSupported:
case Constants.routerErrorCodes.processor.errToChainNotSupported:
case Constants.routerErrorCodes.processor.errTxForChainNotSupported:
case Constants.routerErrorCodes.processor.errENSResolverNotFound:
case Constants.routerErrorCodes.processor.errENSRegistrarNotFound:
case Constants.routerErrorCodes.processor.errToAndFromTokensMustBeSet:
case Constants.routerErrorCodes.processor.errCannotResolveTokens:
case Constants.routerErrorCodes.processor.errPriceRouteNotFound:
case Constants.routerErrorCodes.processor.errConvertingAmountToBigInt:
case Constants.routerErrorCodes.processor.errNoChainSet:
case Constants.routerErrorCodes.processor.errNoTokenSet:
case Constants.routerErrorCodes.processor.errToTokenShouldNotBeSet:
case Constants.routerErrorCodes.processor.errFromAndToChainsMustBeDifferent:
case Constants.routerErrorCodes.processor.errFromAndToChainsMustBeSame:
case Constants.routerErrorCodes.processor.errFromAndToTokensMustBeDifferent:
case Constants.routerErrorCodes.processor.errContextCancelled:
case Constants.routerErrorCodes.processor.errContextDeadlineExceeded:
case Constants.routerErrorCodes.processor.errPriceTimeout:
case Constants.routerErrorCodes.processor.errNotEnoughLiquidity:
case Constants.routerErrorCodes.processor.errPriceImpactTooHigh:
return qsTr("processor internal error")
case Constants.routerErrorCodes.processor.errTransferCustomError:
case Constants.routerErrorCodes.processor.errERC721TransferCustomError:
case Constants.routerErrorCodes.processor.errERC1155TransferCustomError:
case Constants.routerErrorCodes.processor.errBridgeHopCustomError:
case Constants.routerErrorCodes.processor.errBridgeCellerCustomError:
case Constants.routerErrorCodes.processor.errSwapParaswapCustomError:
case Constants.routerErrorCodes.processor.errENSRegisterCustomError:
case Constants.routerErrorCodes.processor.errENSReleaseCustomError:
case Constants.routerErrorCodes.processor.errENSPublicKeyCustomError:
case Constants.routerErrorCodes.processor.errStickersBuyCustomError:
return qsTr("processor network error")
case Constants.routerErrorCodes.router.errENSRegisterRequiresUsernameAndPubKey:
case Constants.routerErrorCodes.router.errENSRegisterTestnetSTTOnly:
case Constants.routerErrorCodes.router.errENSRegisterMainnetSNTOnly:
case Constants.routerErrorCodes.router.errENSReleaseRequiresUsername:
case Constants.routerErrorCodes.router.errENSSetPubKeyRequiresUsernameAndPubKey:
case Constants.routerErrorCodes.router.errStickersBuyRequiresPackID:
case Constants.routerErrorCodes.router.errSwapRequiresToTokenID:
case Constants.routerErrorCodes.router.errSwapTokenIDMustBeDifferent:
case Constants.routerErrorCodes.router.errSwapAmountInAmountOutMustBeExclusive:
case Constants.routerErrorCodes.router.errSwapAmountInMustBePositive:
case Constants.routerErrorCodes.router.errSwapAmountOutMustBePositive:
case Constants.routerErrorCodes.router.errLockedAmountNotSupportedForNetwork:
case Constants.routerErrorCodes.router.errLockedAmountNotNegative:
case Constants.routerErrorCodes.router.errLockedAmountExceedsTotalSendAmount:
case Constants.routerErrorCodes.router.errLockedAmountLessThanSendAmountAllNetworks:
case Constants.routerErrorCodes.router.errNativeTokenNotFound:
case Constants.routerErrorCodes.router.errDisabledChainFoundAmongLockedNetworks:
case Constants.routerErrorCodes.router.errENSSetPubKeyInvalidUsername:
case Constants.routerErrorCodes.router.errLockedAmountExcludesAllSupported:
case Constants.routerErrorCodes.router.errTokenNotFound:
case Constants.routerErrorCodes.router.errNoBestRouteFound:
case Constants.routerErrorCodes.router.errCannotCheckReceiverBalance:
case Constants.routerErrorCodes.router.errCannotCheckLockedAmounts:
return qsTr("router network error")
case Constants.routerErrorCodes.router.errNotEnoughTokenBalance:
return qsTr("not enough token balance")
case Constants.routerErrorCodes.router.errNotEnoughNativeBalance:
return qsTr("not enough ETH")
case Constants.routerErrorCodes.router.errLowAmountInForHopBridge:
return qsTr("amount in too low")
case Constants.routerErrorCodes.router.errNoPositiveBalance:
return qsTr("no positive balance")
default:
return qsTr("unknown processor error")
}
}
function getRouterErrorDetailsOnCode(code, details) {
if (code === "") {
return ""
}
switch(code) {
case Constants.routerErrorCodes.errInternal:
case Constants.routerErrorCodes.errGeneric:
return details
case Constants.routerErrorCodes.processor.errFailedToParseBaseFee:
return qsTr("failed to parse base fee")
case Constants.routerErrorCodes.processor.errFailedToParsePercentageFee:
return qsTr("failed to parse percentage fee")
case Constants.routerErrorCodes.processor.errContractNotFound:
return qsTr("contract not found")
case Constants.routerErrorCodes.processor.errNetworkNotFound:
return qsTr("network not found")
case Constants.routerErrorCodes.processor.errTokenNotFound:
return qsTr("token not found")
case Constants.routerErrorCodes.processor.errNoEstimationFound:
return qsTr("no estimation found")
case Constants.routerErrorCodes.processor.errNotAvailableForContractType:
return qsTr("not available for contract type")
case Constants.routerErrorCodes.processor.errNoBonderFeeFound:
return qsTr("no bonder fee found")
case Constants.routerErrorCodes.processor.errContractTypeNotSupported:
return qsTr("contract type not supported")
case Constants.routerErrorCodes.processor.errFromChainNotSupported:
return qsTr("from chain not supported")
case Constants.routerErrorCodes.processor.errToChainNotSupported:
return qsTr("to chain not supported")
case Constants.routerErrorCodes.processor.errTxForChainNotSupported:
return qsTr("tx for chain not supported")
case Constants.routerErrorCodes.processor.errENSResolverNotFound:
return qsTr("ens resolver not found")
case Constants.routerErrorCodes.processor.errENSRegistrarNotFound:
return qsTr("ens registrar not found")
case Constants.routerErrorCodes.processor.errToAndFromTokensMustBeSet:
return qsTr("to and from tokens must be set")
case Constants.routerErrorCodes.processor.errCannotResolveTokens:
return qsTr("cannot resolve tokens")
case Constants.routerErrorCodes.processor.errPriceRouteNotFound:
return qsTr("price route not found")
case Constants.routerErrorCodes.processor.errConvertingAmountToBigInt:
return qsTr("converting amount issue")
case Constants.routerErrorCodes.processor.errNoChainSet:
return qsTr("no chain set")
case Constants.routerErrorCodes.processor.errNoTokenSet:
return qsTr("no token set")
case Constants.routerErrorCodes.processor.errToTokenShouldNotBeSet:
return qsTr("to token should not be set")
case Constants.routerErrorCodes.processor.errFromAndToChainsMustBeDifferent:
return qsTr("from and to chains must be different")
case Constants.routerErrorCodes.processor.errFromAndToChainsMustBeSame:
return qsTr("from and to chains must be same")
case Constants.routerErrorCodes.processor.errFromAndToTokensMustBeDifferent:
return qsTr("from and to tokens must be different")
case Constants.routerErrorCodes.processor.errContextCancelled:
return qsTr("context cancelled")
case Constants.routerErrorCodes.processor.errContextDeadlineExceeded:
return qsTr("context deadline exceeded")
case Constants.routerErrorCodes.processor.errPriceTimeout:
return qsTr("fetching price timeout")
case Constants.routerErrorCodes.processor.errNotEnoughLiquidity:
return qsTr("not enough liquidity")
case Constants.routerErrorCodes.processor.errPriceImpactTooHigh:
return qsTr("price impact too high")
case Constants.routerErrorCodes.processor.errTransferCustomError:
case Constants.routerErrorCodes.processor.errERC721TransferCustomError:
case Constants.routerErrorCodes.processor.errERC1155TransferCustomError:
case Constants.routerErrorCodes.processor.errBridgeHopCustomError:
case Constants.routerErrorCodes.processor.errBridgeCellerCustomError:
case Constants.routerErrorCodes.processor.errSwapParaswapCustomError:
case Constants.routerErrorCodes.processor.errENSRegisterCustomError:
case Constants.routerErrorCodes.processor.errENSReleaseCustomError:
case Constants.routerErrorCodes.processor.errENSPublicKeyCustomError:
case Constants.routerErrorCodes.processor.errStickersBuyCustomError:
return details
case Constants.routerErrorCodes.router.errENSRegisterRequiresUsernameAndPubKey:
return qsTr("username and public key are required for registering ens name")
case Constants.routerErrorCodes.router.errENSRegisterTestnetSTTOnly:
return qsTr("only STT is supported for registering ens name on testnet")
case Constants.routerErrorCodes.router.errENSRegisterMainnetSNTOnly:
return qsTr("only SNT is supported for registering ens name on mainnet")
case Constants.routerErrorCodes.router.errENSReleaseRequiresUsername:
return qsTr("username is required for releasing ens name")
case Constants.routerErrorCodes.router.errENSSetPubKeyRequiresUsernameAndPubKey:
return qsTr("username and public key are required for setting public key")
case Constants.routerErrorCodes.router.errStickersBuyRequiresPackID:
return qsTr("stickers pack id is required for buying stickers")
case Constants.routerErrorCodes.router.errSwapRequiresToTokenID:
return qsTr("to token is required for Swap")
case Constants.routerErrorCodes.router.errSwapTokenIDMustBeDifferent:
return qsTr("from and to token must be different")
case Constants.routerErrorCodes.router.errSwapAmountInAmountOutMustBeExclusive:
return qsTr("only one of amount to send or receiving amount can be set")
case Constants.routerErrorCodes.router.errSwapAmountInMustBePositive:
return qsTr("amount to send must be positive")
case Constants.routerErrorCodes.router.errSwapAmountOutMustBePositive:
return qsTr("receiving amount must be positive")
case Constants.routerErrorCodes.router.errLockedAmountNotSupportedForNetwork:
return qsTr("locked amount is not supported for the selected network")
case Constants.routerErrorCodes.router.errLockedAmountNotNegative:
return qsTr("locked amount must not be negative")
case Constants.routerErrorCodes.router.errLockedAmountExceedsTotalSendAmount:
return qsTr("locked amount exceeds the total amount to send")
case Constants.routerErrorCodes.router.errLockedAmountLessThanSendAmountAllNetworks:
return qsTr("locked amount is less than the total amount to send, but all networks are locked")
case Constants.routerErrorCodes.router.errNativeTokenNotFound:
return qsTr("native token not found")
case Constants.routerErrorCodes.router.errDisabledChainFoundAmongLockedNetworks:
return qsTr("disabled chain found among locked networks")
case Constants.routerErrorCodes.router.errENSSetPubKeyInvalidUsername:
return qsTr("a valid username, ending in '.eth', is required for setting public key")
case Constants.routerErrorCodes.router.errLockedAmountExcludesAllSupported:
return qsTr("all supported chains are excluded, routing impossible")
case Constants.routerErrorCodes.router.errTokenNotFound:
return qsTr("token not found")
case Constants.routerErrorCodes.router.errNoBestRouteFound:
return qsTr("no best route found")
case Constants.routerErrorCodes.router.errCannotCheckReceiverBalance:
return qsTr("cannot check balance")
case Constants.routerErrorCodes.router.errCannotCheckLockedAmounts:
return qsTr("cannot check locked amounts")
case Constants.routerErrorCodes.router.errNotEnoughTokenBalance:
case Constants.routerErrorCodes.router.errNotEnoughNativeBalance:
try {
const jsonObj = JSON.parse(details)
let chain = Constants.openseaExplorerLinks.ethereum
switch(jsonObj.chainId) {
case Constants.chains.optimismChainId:
case Constants.chains.optimismSepoliaChainId:
chain = Constants.openseaExplorerLinks.optimism
break
case Constants.chains.arbitrumChainId:
case Constants.chains.arbitrumSepoliaChainId:
chain = Constants.openseaExplorerLinks.arbitrum
break
}
return qsTr("not enough balance for %1 on %2 chain").arg(jsonObj.token).arg(chain)
}
catch (e) {
return ""
}
case Constants.routerErrorCodes.router.errLowAmountInForHopBridge:
return qsTr("bonder fee greater than estimated received, a higher amount is needed to cover fees")
case Constants.routerErrorCodes.router.errNoPositiveBalance:
return qsTr("no positive balance for your account across chains")
default:
return ""
}
}
}