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.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: 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") default: return qsTr("unknown processor error") } } function getRouterErrorDetailsOnCode(code, details) { if (code === "") { return "" } switch(code) { 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.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") default: return "" } } }