2024-05-15 21:22:13 +00:00
|
|
|
import QtQml 2.15
|
|
|
|
import SortFilterProxyModel 0.2
|
|
|
|
|
|
|
|
import StatusQ 0.1
|
|
|
|
import StatusQ.Core.Utils 0.1
|
|
|
|
|
|
|
|
import utils 1.0
|
|
|
|
|
|
|
|
import shared.stores 1.0
|
2024-06-07 12:27:56 +00:00
|
|
|
import AppLayouts.Wallet 1.0
|
2024-05-15 21:22:13 +00:00
|
|
|
import AppLayouts.Wallet.stores 1.0 as WalletStore
|
|
|
|
|
|
|
|
QObject {
|
|
|
|
id: root
|
|
|
|
|
|
|
|
required property CurrenciesStore currencyStore
|
|
|
|
required property WalletStore.WalletAssetsStore walletAssetsStore
|
|
|
|
required property WalletStore.SwapStore swapStore
|
|
|
|
required property SwapInputParamsForm swapFormData
|
2024-06-06 14:05:31 +00:00
|
|
|
required property SwapOutputData swapOutputData
|
2024-05-15 21:22:13 +00:00
|
|
|
|
2024-06-06 14:05:31 +00:00
|
|
|
// the below 2 properties holds the state of finding a swap proposal
|
|
|
|
property bool validSwapProposalReceived: false
|
2024-06-04 11:58:37 +00:00
|
|
|
property bool swapProposalLoading: false
|
|
|
|
|
|
|
|
// To expose the selected from and to Token from the SwapModal
|
2024-06-07 12:27:56 +00:00
|
|
|
readonly property var fromToken: fromTokenEntry.item
|
|
|
|
readonly property var toToken: toTokenEntry.item
|
2024-06-04 11:58:37 +00:00
|
|
|
|
2024-05-15 21:22:13 +00:00
|
|
|
readonly property var nonWatchAccounts: SortFilterProxyModel {
|
|
|
|
sourceModel: root.swapStore.accounts
|
|
|
|
filters: ValueFilter {
|
|
|
|
roleName: "walletType"
|
|
|
|
value: Constants.watchWalletType
|
|
|
|
inverted: true
|
|
|
|
}
|
|
|
|
sorters: RoleSorter { roleName: "position"; sortOrder: Qt.AscendingOrder }
|
|
|
|
proxyRoles: [
|
|
|
|
FastExpressionRole {
|
|
|
|
name: "accountBalance"
|
2024-06-06 14:05:31 +00:00
|
|
|
expression: d.processAccountBalance(model.address)
|
2024-05-15 21:22:13 +00:00
|
|
|
expectedRoles: ["address"]
|
|
|
|
},
|
|
|
|
FastExpressionRole {
|
|
|
|
name: "fromToken"
|
2024-06-04 11:58:37 +00:00
|
|
|
expression: root.fromToken
|
2024-06-07 12:27:56 +00:00
|
|
|
},
|
|
|
|
FastExpressionRole {
|
|
|
|
name: "colorizedChainPrefixes"
|
|
|
|
function getChainShortNames(chainIds) {
|
|
|
|
const chainShortNames = root.getNetworkShortNames(chainIds)
|
|
|
|
return WalletUtils.colorizedChainPrefix(chainShortNames)
|
|
|
|
}
|
|
|
|
expression: getChainShortNames(model.preferredSharingChainIds)
|
|
|
|
expectedRoles: ["preferredSharingChainIds"]
|
2024-05-15 21:22:13 +00:00
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
2024-05-29 15:42:26 +00:00
|
|
|
readonly property SortFilterProxyModel filteredFlatNetworksModel: SortFilterProxyModel {
|
|
|
|
sourceModel: root.swapStore.flatNetworks
|
|
|
|
filters: ValueFilter { roleName: "isTest"; value: root.swapStore.areTestNetworksEnabled }
|
|
|
|
}
|
|
|
|
|
2024-06-07 12:27:56 +00:00
|
|
|
ModelEntry {
|
|
|
|
id: fromTokenEntry
|
|
|
|
sourceModel: root.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel
|
|
|
|
key: "key"
|
|
|
|
value: root.swapFormData.fromTokensKey
|
|
|
|
}
|
|
|
|
|
|
|
|
ModelEntry {
|
|
|
|
id: toTokenEntry
|
|
|
|
sourceModel: root.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel
|
|
|
|
key: "key"
|
|
|
|
value: root.swapFormData.toTokenKey
|
|
|
|
}
|
|
|
|
|
|
|
|
ModelEntry {
|
|
|
|
id: selectedAccountEntry
|
|
|
|
sourceModel: root.nonWatchAccounts
|
|
|
|
key: "address"
|
|
|
|
value: root.swapFormData.selectedAccountAddress
|
|
|
|
}
|
|
|
|
|
2024-06-06 14:05:31 +00:00
|
|
|
QtObject {
|
|
|
|
id: d
|
2024-05-15 21:22:13 +00:00
|
|
|
|
2024-06-06 14:05:31 +00:00
|
|
|
property string uuid
|
2024-05-28 17:39:41 +00:00
|
|
|
|
2024-06-06 14:05:31 +00:00
|
|
|
readonly property SubmodelProxyModel filteredBalancesModel: SubmodelProxyModel {
|
|
|
|
sourceModel: root.walletAssetsStore.baseGroupedAccountAssetModel
|
|
|
|
submodelRoleName: "balances"
|
|
|
|
delegateModel: SortFilterProxyModel {
|
|
|
|
sourceModel: joinModel
|
|
|
|
filters: ValueFilter {
|
2024-05-28 17:39:41 +00:00
|
|
|
roleName: "chainId"
|
|
|
|
value: root.swapFormData.selectedNetworkChainId
|
2024-06-06 14:05:31 +00:00
|
|
|
}
|
|
|
|
readonly property LeftJoinModel joinModel: LeftJoinModel {
|
|
|
|
leftModel: submodel
|
|
|
|
rightModel: root.swapStore.flatNetworks
|
|
|
|
|
|
|
|
joinRole: "chainId"
|
|
|
|
}
|
|
|
|
}
|
2024-05-28 17:39:41 +00:00
|
|
|
}
|
|
|
|
|
2024-06-06 14:05:31 +00:00
|
|
|
function processAccountBalance(address) {
|
2024-06-25 21:33:25 +00:00
|
|
|
if (!root.swapFormData.fromTokensKey || !root.fromToken) {
|
2024-06-07 12:27:56 +00:00
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
2024-06-06 14:05:31 +00:00
|
|
|
let network = ModelUtils.getByKey(root.filteredFlatNetworksModel, "chainId", root.swapFormData.selectedNetworkChainId)
|
2024-06-07 12:27:56 +00:00
|
|
|
|
|
|
|
if (!network) {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
|
|
|
let balancesModel = ModelUtils.getByKey(filteredBalancesModel, "tokensKey", root.swapFormData.fromTokensKey, "balances")
|
|
|
|
let accountBalance = ModelUtils.getByKey(balancesModel, "account", address)
|
|
|
|
if(accountBalance) {
|
|
|
|
let balance = AmountsArithmetic.toNumber(accountBalance.balance, root.fromToken.decimals)
|
|
|
|
let formattedBalance = root.formatCurrencyAmount(balance, root.fromToken.symbol)
|
|
|
|
accountBalance.formattedBalance = formattedBalance
|
2024-06-06 14:05:31 +00:00
|
|
|
return accountBalance
|
2024-05-28 13:19:46 +00:00
|
|
|
}
|
2024-06-07 12:27:56 +00:00
|
|
|
|
|
|
|
return {
|
|
|
|
balance: "0",
|
|
|
|
iconUrl: network.iconUrl,
|
|
|
|
chainColor: network.chainColor,
|
|
|
|
formattedBalance: root.formatCurrencyAmount(.0 , root.fromToken.symbol)
|
|
|
|
}
|
2024-06-06 14:05:31 +00:00
|
|
|
}
|
2024-05-15 21:22:13 +00:00
|
|
|
}
|
2024-05-28 13:19:46 +00:00
|
|
|
|
2024-06-06 14:05:31 +00:00
|
|
|
Connections {
|
|
|
|
target: root.swapStore
|
|
|
|
function onSuggestedRoutesReady(txRoutes) {
|
|
|
|
root.swapOutputData.reset()
|
|
|
|
root.validSwapProposalReceived = false
|
|
|
|
root.swapProposalLoading = false
|
|
|
|
root.swapOutputData.rawPaths = txRoutes.rawPaths
|
|
|
|
// if valid route was found
|
|
|
|
if(txRoutes.suggestedRoutes.count === 1) {
|
|
|
|
root.validSwapProposalReceived = true
|
|
|
|
root.swapOutputData.bestRoutes = txRoutes.suggestedRoutes
|
2024-06-18 22:51:49 +00:00
|
|
|
root.swapOutputData.toTokenAmount = AmountsArithmetic.div(AmountsArithmetic.fromString(txRoutes.amountToReceive), AmountsArithmetic.fromNumber(1, root.toToken.decimals)).toString()
|
|
|
|
|
2024-06-06 14:05:31 +00:00
|
|
|
let gasTimeEstimate = txRoutes.gasTimeEstimate
|
|
|
|
let totalTokenFeesInFiat = 0
|
2024-06-18 22:51:49 +00:00
|
|
|
if (!!root.fromToken && !!root.fromToken.marketDetails && !!root.fromToken.marketDetails.currencyPrice)
|
2024-06-06 14:05:31 +00:00
|
|
|
totalTokenFeesInFiat = gasTimeEstimate.totalTokenFees * root.fromToken.marketDetails.currencyPrice.amount
|
|
|
|
root.swapOutputData.totalFees = root.currencyStore.getFiatValue(gasTimeEstimate.totalFeesInEth, Constants.ethToken) + totalTokenFeesInFiat
|
|
|
|
root.swapOutputData.approvalNeeded = ModelUtils.get(root.swapOutputData.bestRoutes, 0, "route").approvalRequired
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
root.swapOutputData.hasError = true
|
2024-05-15 21:22:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-05-28 17:39:41 +00:00
|
|
|
|
2024-06-06 14:05:31 +00:00
|
|
|
function reset() {
|
|
|
|
root.swapFormData.resetFormData()
|
|
|
|
root.swapOutputData.reset()
|
|
|
|
root.validSwapProposalReceived = false
|
|
|
|
root.swapProposalLoading = false
|
|
|
|
}
|
|
|
|
|
2024-06-13 00:45:33 +00:00
|
|
|
// this function will not reset input params but only the output ones and loading states
|
|
|
|
function newFetchReset() {
|
|
|
|
root.swapOutputData.reset()
|
|
|
|
root.validSwapProposalReceived = false
|
|
|
|
root.swapProposalLoading = false
|
|
|
|
}
|
|
|
|
|
2024-06-06 14:05:31 +00:00
|
|
|
function getNetworkShortNames(chainIds) {
|
|
|
|
var networkString = ""
|
|
|
|
let chainIdsArray = chainIds.split(":")
|
|
|
|
for (let i = 0; i< chainIdsArray.length; i++) {
|
|
|
|
let nwShortName = ModelUtils.getByKey(root.filteredFlatNetworksModel, "chainId", Number(chainIdsArray[i]), "shortName")
|
|
|
|
if(!!nwShortName) {
|
|
|
|
networkString = networkString + nwShortName + ':'
|
|
|
|
}
|
2024-05-28 17:39:41 +00:00
|
|
|
}
|
2024-06-06 14:05:31 +00:00
|
|
|
return networkString
|
2024-05-28 17:39:41 +00:00
|
|
|
}
|
2024-06-10 12:51:33 +00:00
|
|
|
|
2024-06-06 14:05:31 +00:00
|
|
|
function formatCurrencyAmount(balance, symbol, options = null, locale = null) {
|
|
|
|
return root.currencyStore.formatCurrencyAmount(balance, symbol, options, locale)
|
|
|
|
}
|
2024-06-10 12:51:33 +00:00
|
|
|
|
2024-06-06 14:05:31 +00:00
|
|
|
function formatCurrencyAmountFromBigInt(balance, symbol, decimals, options = null) {
|
|
|
|
return root.currencyStore.formatCurrencyAmountFromBigInt(balance, symbol, decimals, options)
|
|
|
|
}
|
2024-06-10 12:51:33 +00:00
|
|
|
|
2024-06-06 14:05:31 +00:00
|
|
|
function getAllChainIds() {
|
|
|
|
return ModelUtils.joinModelEntries(root.filteredFlatNetworksModel, "chainId", ":")
|
|
|
|
}
|
|
|
|
|
|
|
|
function getDisabledChainIds(enabledChainId) {
|
|
|
|
let disabledChainIds = []
|
|
|
|
let chainIds = ModelUtils.modelToFlatArray(root.filteredFlatNetworksModel, "chainId")
|
|
|
|
for (let i = 0; i < chainIds.length; i++) {
|
|
|
|
if (chainIds[i] !== enabledChainId) {
|
|
|
|
disabledChainIds.push(chainIds[i])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return disabledChainIds.join(":")
|
|
|
|
}
|
|
|
|
|
2024-06-13 00:45:33 +00:00
|
|
|
function fetchSuggestedRoutes(cryptoValueRaw) {
|
|
|
|
if (root.swapFormData.isFormFilledCorrectly() && !!cryptoValueRaw) {
|
|
|
|
root.swapOutputData.reset()
|
2024-06-06 14:05:31 +00:00
|
|
|
root.validSwapProposalReceived = false
|
|
|
|
|
|
|
|
// Identify new swap with a different uuid
|
|
|
|
d.uuid = Utils.uuid()
|
|
|
|
|
2024-06-07 12:27:56 +00:00
|
|
|
let account = selectedAccountEntry.item
|
2024-06-06 14:05:31 +00:00
|
|
|
let accountAddress = account.address
|
|
|
|
let disabledChainIds = getDisabledChainIds(root.swapFormData.selectedNetworkChainId)
|
|
|
|
let preferedChainIds = getAllChainIds()
|
|
|
|
|
|
|
|
root.swapStore.fetchSuggestedRoutes(accountAddress, accountAddress,
|
2024-06-13 00:45:33 +00:00
|
|
|
cryptoValueRaw, root.swapFormData.fromTokensKey, root.swapFormData.toTokenKey,
|
2024-06-06 14:05:31 +00:00
|
|
|
disabledChainIds, disabledChainIds, preferedChainIds,
|
|
|
|
Constants.SendType.Swap, "")
|
|
|
|
} else {
|
|
|
|
root.validSwapProposalReceived = false
|
|
|
|
root.swapProposalLoading = false
|
|
|
|
}
|
2024-06-10 12:51:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function sendApproveTx() {
|
2024-06-07 12:27:56 +00:00
|
|
|
let account = selectedAccountEntry.item
|
2024-06-10 12:51:33 +00:00
|
|
|
let accountAddress = account.address
|
|
|
|
|
|
|
|
root.swapStore.authenticateAndTransfer(d.uuid, accountAddress, accountAddress,
|
|
|
|
root.swapFormData.fromTokensKey, root.swapFormData.toTokenKey,
|
2024-06-17 00:18:55 +00:00
|
|
|
Constants.SendType.Approve, "", false, root.swapOutputData.rawPaths, "")
|
2024-06-10 12:51:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function sendSwapTx() {
|
2024-06-07 12:27:56 +00:00
|
|
|
let account = selectedAccountEntry.item
|
2024-06-10 12:51:33 +00:00
|
|
|
let accountAddress = account.address
|
|
|
|
|
|
|
|
root.swapStore.authenticateAndTransfer(d.uuid, accountAddress, accountAddress,
|
|
|
|
root.swapFormData.fromTokensKey, root.swapFormData.toTokenKey,
|
2024-06-17 00:18:55 +00:00
|
|
|
Constants.SendType.Swap, "", false, root.swapOutputData.rawPaths, root.swapFormData.selectedSlippage)
|
2024-06-10 12:51:33 +00:00
|
|
|
}
|
2024-05-15 21:22:13 +00:00
|
|
|
}
|