status-desktop/ui/app/mainui/SendModalHandler.qml

732 lines
32 KiB
QML
Raw Normal View History

import QtQuick 2.15
import QtQuick.Controls 2.15
import SortFilterProxyModel 0.2
import StatusQ 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1 as SQUtils
import AppLayouts.Wallet.stores 1.0 as WalletStores
import AppLayouts.Wallet.popups.simpleSend 1.0
import AppLayouts.Wallet.adaptors 1.0
import AppLayouts.Wallet 1.0
import shared.popups.send 1.0
import shared.stores.send 1.0
import utils 1.0
QtObject {
id: root
required property var popupParent
required property int loginType
required property TransactionStore transactionStore
required property WalletStores.CollectiblesStore walletCollectiblesStore
required property WalletStores.TransactionStoreNew transactionStoreNew
/** for ens flows **/
required property string myPublicKey
required property string ensRegisteredAddress
/** TODO: This should probably be a property and not
a function. Needs changes on backend side **/
property var getStatusTokenKey: function() {}
/** for sticker flows **/
required property string stickersMarketAddress
required property string stickersNetworkId
/** Feature flag for single network send until its feature complete **/
required property bool simpleSendEnabled
/** For simple send modal flows, decoupling from transaction store **/
/** Expected model structure:
- name: name of account
- address: wallet address
- color: color of the account
- emoji: emoji selected for the account
- currencyBalance: total currency balance in CurrencyAmount
- accountBalance: balance of selected token + selected chain
**/
required property var walletAccountsModel
/** Expected model structure:
- tokensKey: unique string ID of the token (asset); e.g. "ETH" or contract address
- name: user visible token name (e.g. "Ethereum")
- symbol: user visible token symbol (e.g. "ETH")
- decimals: number of decimal places
- communityId: optional; ID of the community this token belongs to, if any
- marketDetails: object containing props like `currencyPrice` for the computed values below
- balances: submodel[ chainId:int, account:string, balance:BigIntString, iconUrl:string ]
**/
required property var groupedAccountAssetsModel
/** Expected token by symbol model structure:
- key: id for the token,
- name: name of the token,
- symbol: symbol of the token,
- decimals: decimals for the token
*/
required property var plainTokensBySymbolModel
/** Expected model structure:
- symbol [string] - unique identifier of a collectible
- collectionUid [string] - unique identifier of a collection
- contractAddress [string] - collectible's contract address
- name [string] - collectible's name e.g. "Magicat"
- collectionName [string] - collection name e.g. "Crypto Kitties"
- mediaUrl [url] - collectible's media url
- imageUrl [url] - collectible's image url
- communityId [string] - unique identifier of a community for community collectible or empty
- ownership [model] - submodel of balances per chain/account
- balance [int] - balance (always 1 for ERC-721)
- accountAddress [string] - unique identifier of an account
**/
required property var collectiblesBySymbolModel
/**
Expected model structure:
- chainId: network chain id
- chainName: name of network
- iconUrl: network icon url
networks on both mainnet & testnet
**/
required property var flatNetworksModel
/**
Expected model structure:
- chainId: network chain id
- chainName: name of network
- iconUrl: network icon url
networks on either mainnet OR testnet
**/
required property var filteredFlatNetworksModel
/** true if testnet mode is on **/
required property bool areTestNetworksEnabled
/** whether community tokens are shown in send modal
based on a global setting **/
required property bool showCommunityAssetsInSend
required property var savedAddressesModel
required property var recentRecipientsModel
/** required function to resolve an ens name
- ensName [string] - ensName to be resolved
- uuid [string] - unique identifier for the request
**/
required property var fnResolveENS
/** required signal to receive resolved ens name address **/
signal ensNameResolved(string resolvedPubKey, string resolvedAddress, string uuid)
/** curently selected fiat currency symbol **/
required property string currentCurrency
/** required function to format currency amount to locale string
- amount [real] - amount to be formatted as a number
- symbol [string] - fiat/crypto currency symbol
**/
required property var fnFormatCurrencyAmount
/** required function to format to currency amount from big int
- amount [real] - amount to be formatted as a number
- symbol [string] - fiat/crypto currency symbol
- decimals [int] - decimals of the crypto token
**/
required property var fnFormatCurrencyAmountFromBigInt
/** required property holds the detailed collectible **/
required property var detailedCollectible
/** required property holds if collectible details is loading **/
required property bool isDetailedCollectibleLoading
/** required function to fetch detailed collectible
chainId, contractAddress, tokenId
- chainId [int] - chainId of collectible
- contractAddress [string] - contract address of collectible
- tokenId [string] - token id of collectible
**/
required property var fnGetDetailedCollectible
/** required function to reset the detailed collectible **/
required property var fnResetDetailedCollectible
/** required function to get openSea explorer url
- networkShortName [string] - collectible networks short name
**/
required property var fnGetOpenSeaUrl
/** property to store the params to be updated in the send modal until it is launched **/
property var simpleSendParams
/** signal to request launch of buy crypto modal **/
signal launchBuyFlowRequested(string accountAddress, int chainId, string tokenKey)
function openSend(params = {}, forceLaunchOldSend = false) {
// TODO remove once simple send is feature complete
if(root.simpleSendEnabled && !forceLaunchOldSend) {
root.simpleSendParams = params
let sendModalInst = simpleSendModalComponent.createObject(popupParent)
sendModalInst.open()
} else {
let sendModalInst = sendModalComponent.createObject(popupParent, params)
sendModalInst.open()
}
}
function connectUsername(ensName) {
let params = {}
if (root.simpleSendEnabled) {
params = {
sendType: Constants.SendType.ENSSetPubKey,
selectedTokenKey: Constants.ethToken ,
selectedRawAmount: "0",
selectedRecipientAddress: root.ensRegisteredAddress,
interactive: false,
publicKey: root.myPublicKey,
ensName: ensName
}
} else {
params = {
preSelectedSendType: Constants.SendType.ENSSetPubKey,
preSelectedHoldingID: Constants.ethToken ,
preSelectedHoldingType: Constants.TokenType.Native,
preDefinedAmountToSend: LocaleUtils.numberToLocaleString(0),
preSelectedRecipient: root.ensRegisteredAddress,
interactive: false,
publicKey: root.myPublicKey,
ensName: ensName
}
}
openSend(params)
}
function registerUsername(ensName) {
let params = {}
if (root.simpleSendEnabled) {
params = {
sendType: Constants.SendType.ENSRegister,
selectedTokenKey: root.getStatusTokenKey(),
// TODO this should come from backend.To be fixed when ENS is reworked
selectedRawAmount: SQUtils.AmountsArithmetic.fromNumber(10, 18).toString(),
selectedRecipientAddress: root.ensRegisteredAddress,
interactive: false,
publicKey: root.myPublicKey,
ensName: ensName
}
} else {
params = {
preSelectedSendType: Constants.SendType.ENSRegister,
preSelectedHoldingID: root.getStatusTokenKey(),
preSelectedHoldingType: Constants.TokenType.ERC20,
preDefinedAmountToSend: LocaleUtils.numberToLocaleString(10),
preSelectedRecipient: root.ensRegisteredAddress,
interactive: false,
publicKey: root.myPublicKey,
ensName: ensName
}
}
openSend(params)
}
function releaseUsername(ensName, senderAddress, chainId) {
let params = {}
if (root.simpleSendEnabled) {
params = {
sendType: Constants.SendType.ENSRelease,
selectedAccountAddress: senderAddress,
selectedTokenKey: Constants.ethToken ,
selectedRawAmount: "0",
selectedChainId: chainId,
selectedRecipientAddress: root.ensRegisteredAddress,
interactive: false,
publicKey: root.myPublicKey,
ensName: ensName
}
} else {
params = {
preSelectedSendType: Constants.SendType.ENSRelease,
preSelectedAccountAddress: senderAddress,
preSelectedHoldingID: Constants.ethToken ,
preSelectedHoldingType: Constants.TokenType.Native,
preDefinedAmountToSend: LocaleUtils.numberToLocaleString(0),
preSelectedChainId: chainId,
preSelectedRecipient: root.ensRegisteredAddress,
interactive: false,
publicKey: root.myPublicKey,
ensName: ensName
}
}
openSend(params)
}
function buyStickerPack(packId, price) {
let params = {}
if (root.simpleSendEnabled) {
params = {
sendType: Constants.SendType.StickersBuy,
selectedTokenKey: root.getStatusTokenKey(),
selectedRawAmount: SQUtils.AmountsArithmetic.fromNumber(price, 18).toString(),
selectedChainId: root.stickersNetworkId,
selectedRecipientAddress: root.stickersMarketAddress,
interactive: false,
stickersPackId: packId
}
} else {
params = {
preSelectedSendType: Constants.SendType.StickersBuy,
preSelectedHoldingID: root.getStatusTokenKey(),
preSelectedHoldingType: Constants.TokenType.ERC20,
preDefinedAmountToSend: LocaleUtils.numberToLocaleString(price),
preSelectedChainId: root.stickersNetworkId,
preSelectedRecipient: root.stickersMarketAddress,
interactive: false,
stickersPackId: packId
}
}
openSend(params)
}
function transferOwnership(tokenId, senderAddress) {
let selectedChainId =
SQUtils.ModelUtils.getByKey(root.collectiblesBySymbolModel, "symbol", tokenId, "chainId")
let params = {}
if (root.simpleSendEnabled) {
params = {
sendType: Constants.SendType.ERC721Transfer,
selectedAccountAddress: senderAddress,
selectedTokenKey: tokenId,
selectedRawAmount: "1",
selectedChainId: selectedChainId,
transferOwnership: true
}
} else {
params = {
preSelectedSendType: Constants.SendType.ERC721Transfer,
preSelectedAccountAddress: senderAddress,
preSelectedHoldingID: tokenId,
preSelectedHoldingType: Constants.TokenType.ERC721,
}
}
openSend(params)
}
function sendToRecipient(recipientAddress) {
let params = {}
if (root.simpleSendEnabled) {
params = {
selectedRecipientAddress: recipientAddress
}
} else {
params = {
preSelectedRecipient: recipientAddress
}
}
openSend(params)
}
function bridgeToken(tokenId, tokenType) {
let params = {
preSelectedSendType: Constants.SendType.Bridge,
preSelectedHoldingID: tokenId ,
preSelectedHoldingType: tokenType,
onlyAssets: true
}
openSend(params, true)
}
function sendToken(senderAddress, tokenId, tokenType) {
let sendType = Constants.SendType.Transfer
let selectedChainId = 0
let selectedRawAmount = ""
if (tokenType === Constants.TokenType.ERC721) {
sendType = Constants.SendType.ERC721Transfer
selectedRawAmount = "1"
selectedChainId =
SQUtils.ModelUtils.getByKey(root.collectiblesBySymbolModel, "symbol", tokenId, "chainId")
}
else if(tokenType === Constants.TokenType.ERC1155) {
sendType = Constants.SendType.ERC1155Transfer
selectedRawAmount = "1"
selectedChainId =
SQUtils.ModelUtils.getByKey(root.collectiblesBySymbolModel, "symbol", tokenId, "chainId")
}
else {
let layer1chainId = SQUtils.ModelUtils.getByKey(root.filteredFlatNetworksModel, "layer", "1", "chainId")
let networksChainIdArray = SQUtils.ModelUtils.modelToFlatArray(root.filteredFlatNetworksModel, "chainId")
let selectedAssetAddressPerChain =
SQUtils.ModelUtils.getByKey(root.plainTokensBySymbolModel, "key", tokenId, "addressPerChain")
// check if layer address is found
selectedChainId = SQUtils.ModelUtils.getByKey(selectedAssetAddressPerChain, "chainId", layer1chainId, "chainId")
// if not layer 1 chain id found, select the first one is list
if (!selectedChainId) {
selectedChainId = SQUtils.ModelUtils.getFirstModelEntryIf(
selectedAssetAddressPerChain,
(addPerChain) => {
return networksChainIdArray.includes(addPerChain.chainId)
})
}
}
let params = {}
if (root.simpleSendEnabled) {
params = {
sendType: sendType,
selectedAccountAddress: senderAddress,
selectedTokenKey: tokenId,
selectedRawAmount: selectedRawAmount,
selectedChainId: selectedChainId
}
} else {
params = {
preSelectedSendType: sendType,
preSelectedAccountAddress: senderAddress,
preSelectedHoldingID: tokenId,
preSelectedHoldingType: tokenType,
}
}
openSend(params)
}
function openTokenPaymentRequest(recipientAddress, symbol, rawAmount, chainId) {
let params = {}
if (root.simpleSendEnabled) {
params = {
selectedTokenKey: symbol,
selectedRawAmount: rawAmount,
selectedChainId: chainId,
selectedRecipientAddress: recipientAddress,
interactive: false
}
} else {
params = {
preSelectedHoldingID: symbol,
preSelectedHoldingType: Constants.TokenType.ERC20,
preDefinedRawAmountToSend: rawAmount,
preSelectedChainId: chainId,
preSelectedRecipient: recipientAddress
}
}
openSend(params)
}
readonly property Component sendModalComponent: Component {
SendModal {
loginType: root.loginType
store: root.transactionStore
collectiblesStore: root.walletCollectiblesStore
showCustomRoutingMode: !production
onClosed: destroy()
}
}
readonly property Component simpleSendModalComponent: Component {
SimpleSendModal {
id: simpleSendModal
accountsModel: handler.accountsSelectorAdaptor.processedWalletAccounts
assetsModel: handler.assetsSelectorViewAdaptor.outputAssetsModel
flatCollectiblesModel: handler.collectiblesSelectionAdaptor.filteredFlatModel
collectiblesModel: handler.collectiblesSelectionAdaptor.model
networksModel: root.filteredFlatNetworksModel
savedAddressesModel: root.savedAddressesModel
recentRecipientsModel: root.recentRecipientsModel
currentCurrency: root.currentCurrency
fnFormatCurrencyAmount: root.fnFormatCurrencyAmount
fnResolveENS: root.fnResolveENS
onOpened: {
if(root.simpleSendParams.interactive !== undefined) {
interactive = root.simpleSendParams.interactive
}
if(root.simpleSendParams.displayOnlyAssets !== undefined) {
displayOnlyAssets = root.simpleSendParams.displayOnlyAssets
}
if(root.simpleSendParams.sendType !== undefined) {
sendType = root.simpleSendParams.sendType
}
if(root.simpleSendParams.selectedAccountAddress !== undefined &&
!!root.simpleSendParams.selectedAccountAddress) {
selectedAccountAddress = root.simpleSendParams.selectedAccountAddress
}
if(root.simpleSendParams.selectedTokenKey !== undefined) {
selectedTokenKey = root.simpleSendParams.selectedTokenKey
}
if(root.simpleSendParams.selectedChainId !== undefined) {
selectedChainId = root.simpleSendParams.selectedChainId
}
if(root.simpleSendParams.selectedRawAmount !== undefined) {
selectedRawAmount = root.simpleSendParams.selectedRawAmount
}
if(root.simpleSendParams.selectedRecipientAddress !== undefined) {
selectedRecipientAddress = root.simpleSendParams.selectedRecipientAddress
}
if(root.simpleSendParams.publicKey !== undefined) {
publicKey = root.simpleSendParams.publicKey
}
if(root.simpleSendParams.ensName !== undefined) {
ensName = root.simpleSendParams.ensName
}
if(root.simpleSendParams.stickersPackId !== undefined) {
stickersPackId = root.simpleSendParams.stickersPackId
}
if(root.simpleSendParams.transferOwnership !== undefined) {
transferOwnership = root.simpleSendParams.transferOwnership
}
}
onClosed: {
destroy()
root.transactionStoreNew.stopUpdatesForSuggestedRoute()
}
onFormChanged: {
handler.resetRouterValues()
if(allValuesFilledCorrectly) {
handler.uuid = Utils.uuid()
simpleSendModal.routesLoading = true
let tokenKey = selectedTokenKey
/** TODO: This special handling for collectibles should ideally not
be needed, howver is needed because of current implementation and
collectible token id is contractAddress:tokenId **/
if(sendType === Constants.SendType.ERC1155Transfer ||
sendType === Constants.SendType.ERC721Transfer) {
const selectedCollectible =
SQUtils.ModelUtils.getByKey(root.collectiblesBySymbolModel, "symbol", selectedTokenKey)
if(!!selectedCollectible &&
!!selectedCollectible.contractAddress &&
!!selectedCollectible.tokenId) {
tokenKey = "%1:%2".arg(
selectedCollectible.contractAddress).arg(
selectedCollectible.tokenId)
}
}
root.transactionStoreNew.fetchSuggestedRoutes(handler.uuid,
sendType,
selectedChainId,
selectedAccountAddress,
selectedRecipientAddress,
selectedRawAmount,
tokenKey,
/*amountOut = */ "0",
/*toToken =*/ "",
handler.extraParamsJson)
}
}
onReviewSendClicked: {
if(sendType === Constants.SendType.ERC1155Transfer ||
sendType === Constants.SendType.ERC721Transfer) {
const selectedCollectible =
SQUtils.ModelUtils.getByKey(root.collectiblesBySymbolModel, "symbol", selectedTokenKey)
if(!!selectedCollectible &&
!!selectedCollectible.contractAddress &&
!!selectedCollectible.tokenId) {
root.fnGetDetailedCollectible(simpleSendModal.selectedChainId ,
selectedCollectible.contractAddress,
selectedCollectible.tokenId)
}
}
Global.openPopup(sendSignModalCmp)
}
onLaunchBuyFlow: {
root.launchBuyFlowRequested(selectedAccountAddress, selectedChainId, selectedTokenKey)
}
QtObject {
id: handler
property string uuid
property var fetchedPathModel
readonly property string extraParamsJson: {
if (!!simpleSendModal.stickersPackId) {
return JSON.stringify({[Constants.suggestedRoutesExtraParamsProperties.packId]: simpleSendModal.stickersPackId})
}
if (!!simpleSendModal.ensName && !!simpleSendModal.publicKey) {
return JSON.stringify({[Constants.suggestedRoutesExtraParamsProperties.username]: simpleSendModal.ensName,
[Constants.suggestedRoutesExtraParamsProperties.publicKey]: simpleSendModal.publicKey})
}
return ""
}
function routesFetched(returnedUuid, pathModel, errCode, errDescription) {
simpleSendModal.routesLoading = false
if(returnedUuid !== handler.uuid) {
// Suggested routes for a different fetch, ignore
return
}
simpleSendModal.routerErrorCode = errCode
simpleSendModal.routerError = WalletUtils.getRouterErrorBasedOnCode(errCode)
simpleSendModal.routerErrorDetails = "%1 - %2".arg(errCode).arg(
WalletUtils.getRouterErrorDetailsOnCode(errCode, errDescription))
fetchedPathModel = pathModel
}
function transactionSent(returnedUuid, chainId, approvalTx, txHash, error) {
if(returnedUuid !== handler.uuid) {
// Suggested routes for a different fetch, ignore
return
}
if (!!error) {
if (error.includes(Constants.walletSection.authenticationCanceled)) {
return
}
simpleSendModal.routerError = error
return
}
close()
}
readonly property var accountsSelectorAdaptor: WalletAccountsSelectorAdaptor {
accounts: root.walletAccountsModel
assetsModel: root.groupedAccountAssetsModel
tokensBySymbolModel: root.plainTokensBySymbolModel
filteredFlatNetworksModel: root.filteredFlatNetworksModel
selectedTokenKey: simpleSendModal.selectedTokenKey
selectedNetworkChainId: simpleSendModal.selectedChainId
fnFormatCurrencyAmountFromBigInt: root.fnFormatCurrencyAmountFromBigInt
}
readonly property var assetsSelectorViewAdaptor: TokenSelectorViewAdaptor {
assetsModel: root.groupedAccountAssetsModel
flatNetworksModel: root.flatNetworksModel
currentCurrency: root.currentCurrency
showCommunityAssets: root.showCommunityAssetsInSend
accountAddress: simpleSendModal.selectedAccountAddress
enabledChainIds: [simpleSendModal.selectedChainId]
}
readonly property var collectiblesSelectionAdaptor: CollectiblesSelectionAdaptor {
accountKey: simpleSendModal.selectedAccountAddress
enabledChainIds: [simpleSendModal.selectedChainId]
networksModel: root.filteredFlatNetworksModel
collectiblesModel: SortFilterProxyModel {
sourceModel: root.collectiblesBySymbolModel
filters: ValueFilter {
roleName: "soulbound"
value: false
}
}
filterCommunityOwnerAndMasterTokens: !simpleSendModal.transferOwnership
}
readonly property var totalFeesAggregator: FunctionAggregator {
model: !!handler.fetchedPathModel ?
handler.fetchedPathModel: null
initialValue: "0"
roleName: "txTotalFee"
aggregateFunction: (aggr, value) => SQUtils.AmountsArithmetic.sum(
SQUtils.AmountsArithmetic.fromString(aggr),
SQUtils.AmountsArithmetic.fromString(value)).toString()
onValueChanged: {
const ethToken = SQUtils.ModelUtils.getByKey(root.plainTokensBySymbolModel, "key", Constants.ethToken)
let decimals = !!ethToken ? ethToken.decimals: 18
let ethFiatValue = !!ethToken ? ethToken.marketDetails.currencyPrice.amount: 1
let totalFees = SQUtils.AmountsArithmetic.div(SQUtils.AmountsArithmetic.fromString(value), SQUtils.AmountsArithmetic.fromNumber(1, decimals))
let totalFeesInFiat = root.fnFormatCurrencyAmount(ethFiatValue*totalFees, root.currentCurrency).toString()
simpleSendModal.estimatedCryptoFees = root.fnFormatCurrencyAmount(totalFees.toString(), Constants.ethToken)
simpleSendModal.estimatedFiatFees = totalFeesInFiat
}
}
readonly property var estimatedTimeAggregator: FunctionAggregator {
model: !!handler.fetchedPathModel ?
handler.fetchedPathModel: null
initialValue: Constants.TransactionEstimatedTime.Unknown
roleName: "estimatedTime"
aggregateFunction: (aggr, value) => aggr < value? value : aggr
onValueChanged: {
simpleSendModal.estimatedTime = WalletUtils.getLabelForEstimatedTxTime(value)
}
}
Component.onCompleted: {
root.ensNameResolved.connect(ensNameResolved)
root.transactionStoreNew.suggestedRoutesReady.connect(routesFetched)
root.transactionStoreNew.transactionSent.connect(transactionSent)
}
function resetRouterValues() {
uuid = ""
fetchedPathModel = null
simpleSendModal.estimatedCryptoFees = ""
simpleSendModal.estimatedFiatFees = ""
simpleSendModal.estimatedTime = ""
simpleSendModal.routerErrorCode = ""
simpleSendModal.routerError = ""
simpleSendModal.routerErrorDetails = ""
}
}
SignSendAdaptor {
id: signSendAdaptor
accountKey: simpleSendModal.selectedAccountAddress
accountsModel: root.walletAccountsModel
chainId: simpleSendModal.selectedChainId
networksModel: root.flatNetworksModel
tokenKey: simpleSendModal.selectedTokenKey
tokenBySymbolModel: root.plainTokensBySymbolModel
selectedAmountInBaseUnit: simpleSendModal.selectedRawAmount
}
Component {
id: sendSignModalCmp
SendSignModal {
closePolicy: Popup.CloseOnEscape
destroyOnClose: true
onClosed: root.fnResetDetailedCollectible()
// Unused
formatBigNumber: function(number, symbol, noSymbolOption) {}
tokenSymbol: !!signSendAdaptor.selectedAsset &&
!!signSendAdaptor.selectedAsset.symbol ?
signSendAdaptor.selectedAsset.symbol: ""
tokenAmount: signSendAdaptor.selectedAmount
tokenContractAddress: signSendAdaptor.selectedAssetContractAddress
accountName: signSendAdaptor.selectedAccount.name
accountAddress: signSendAdaptor.selectedAccount.address
accountEmoji: signSendAdaptor.selectedAccount.emoji
accountColor: Utils.getColorForId(signSendAdaptor.selectedAccount.colorId)
recipientAddress: simpleSendModal.selectedRecipientAddress
networkShortName: signSendAdaptor.selectedNetwork.shortName
networkName: signSendAdaptor.selectedNetwork.chainName
networkIconPath: Theme.svg(signSendAdaptor.selectedNetwork.iconUrl)
networkBlockExplorerUrl: signSendAdaptor.selectedNetwork.blockExplorerURL
fiatFees: simpleSendModal.estimatedFiatFees
cryptoFees: simpleSendModal.estimatedCryptoFees
estimatedTime: simpleSendModal.estimatedTime
loginType: root.loginType
isCollectible: simpleSendModal.sendType === Constants.SendType.ERC1155Transfer ||
simpleSendModal.sendType === Constants.SendType.ERC721Transfer
isCollectibleLoading: root.isDetailedCollectibleLoading
collectibleContractAddress: root.detailedCollectible.contractAddress
collectibleTokenId: root.detailedCollectible.tokenId
collectibleName: root.detailedCollectible.name
collectibleBackgroundColor: root.detailedCollectible.backgroundColor
collectibleIsMetadataValid: root.detailedCollectible.isMetadataValid
collectibleMediaUrl: root.detailedCollectible.mediaUrl
collectibleMediaType: root.detailedCollectible.mediaType
collectibleFallbackImageUrl: root.detailedCollectible.imageUrl
fnGetOpenSeaExplorerUrl: root.fnGetOpenSeaUrl
onAccepted: {
root.transactionStoreNew.authenticateAndTransfer(handler.uuid, simpleSendModal.selectedAccountAddress)
}
}
}
}
}
}