feat(wallet): in app tx related notifications improvements

Closes #16338
This commit is contained in:
Sale Djenic 2024-11-20 08:34:05 +01:00
parent 300bf4ac34
commit 9ca7167f71
11 changed files with 563 additions and 325 deletions

View File

@ -2,14 +2,14 @@ import NimQml, tables, json, sequtils, stew/shims/strformat, marshal, times, chr
import io_interface, view, controller, chat_search_item, chat_search_model import io_interface, view, controller, chat_search_item, chat_search_model
import ephemeral_notification_item, ephemeral_notification_model import ephemeral_notification_item, ephemeral_notification_model
import ../shared_models/[user_item, member_item, member_model, section_item, section_model, section_details] import app/modules/shared_models/[user_item, member_item, member_model, section_item, section_model, section_details]
import ../shared_models/[color_hash_item, color_hash_model] import app/modules/shared_models/[color_hash_item, color_hash_model]
import ../shared_modules/keycard_popup/module as keycard_shared_module import app/modules/shared_modules/keycard_popup/module as keycard_shared_module
import ../../global/app_sections_config as conf import app/global/app_sections_config as conf
import ../../global/app_signals import app/global/app_signals
import ../../global/global_singleton import app/global/global_singleton
import ../../global/utils as utils import app/global/utils as utils
import ../../../constants import constants
import chat_section/model as chat_model import chat_section/model as chat_model
import chat_section/item as chat_item import chat_section/item as chat_item
@ -27,51 +27,51 @@ import communities/tokens/models/token_model
import network_connection/module as network_connection_module import network_connection/module as network_connection_module
import shared_urls/module as shared_urls_module import shared_urls/module as shared_urls_module
import ../../../app_service/service/contacts/dto/contacts import app_service/service/contacts/dto/contacts
import ../../../app_service/service/community_tokens/community_collectible_owner import app_service/service/community_tokens/community_collectible_owner
import ../../../app_service/service/keychain/service as keychain_service import app_service/service/keychain/service as keychain_service
import ../../../app_service/service/chat/service as chat_service import app_service/service/chat/service as chat_service
import ../../../app_service/service/community/service as community_service import app_service/service/community/service as community_service
import ../../../app_service/service/message/service as message_service import app_service/service/message/service as message_service
import ../../../app_service/service/token/service as token_service import app_service/service/token/service as token_service
import ../../../app_service/service/collectible/service as collectible_service import app_service/service/collectible/service as collectible_service
import ../../../app_service/service/currency/service as currency_service import app_service/service/currency/service as currency_service
import ../../../app_service/service/ramp/service as ramp_service import app_service/service/ramp/service as ramp_service
import ../../../app_service/service/transaction/service as transaction_service import app_service/service/transaction/service as transaction_service
import ../../../app_service/service/wallet_account/service as wallet_account_service import app_service/service/wallet_account/service as wallet_account_service
import ../../../app_service/service/provider/service as provider_service import app_service/service/provider/service as provider_service
import ../../../app_service/service/profile/service as profile_service import app_service/service/profile/service as profile_service
import ../../../app_service/service/accounts/service as accounts_service import app_service/service/accounts/service as accounts_service
import ../../../app_service/service/accounts/utils as accounts_utils import app_service/service/accounts/utils as accounts_utils
import ../../../app_service/service/settings/service as settings_service import app_service/service/settings/service as settings_service
import ../../../app_service/service/contacts/service as contacts_service import app_service/service/contacts/service as contacts_service
import ../../../app_service/service/about/service as about_service import app_service/service/about/service as about_service
import ../../../app_service/service/language/service as language_service import app_service/service/language/service as language_service
import ../../../app_service/service/privacy/service as privacy_service import app_service/service/privacy/service as privacy_service
import ../../../app_service/service/stickers/service as stickers_service import app_service/service/stickers/service as stickers_service
import ../../../app_service/service/activity_center/service as activity_center_service import app_service/service/activity_center/service as activity_center_service
import ../../../app_service/service/saved_address/service as saved_address_service import app_service/service/saved_address/service as saved_address_service
import ../../../app_service/service/node/service as node_service import app_service/service/node/service as node_service
import ../../../app_service/service/node_configuration/service as node_configuration_service import app_service/service/node_configuration/service as node_configuration_service
import ../../../app_service/service/devices/service as devices_service import app_service/service/devices/service as devices_service
import ../../../app_service/service/mailservers/service as mailservers_service import app_service/service/mailservers/service as mailservers_service
import ../../../app_service/service/gif/service as gif_service import app_service/service/gif/service as gif_service
import ../../../app_service/service/ens/service as ens_service import app_service/service/ens/service as ens_service
import ../../../app_service/service/community_tokens/service as community_tokens_service import app_service/service/community_tokens/service as community_tokens_service
import ../../../app_service/service/network/service as network_service import app_service/service/network/service as network_service
import ../../../app_service/service/general/service as general_service import app_service/service/general/service as general_service
import ../../../app_service/service/keycard/service as keycard_service import app_service/service/keycard/service as keycard_service
import ../../../app_service/service/shared_urls/service as urls_service import app_service/service/shared_urls/service as urls_service
import ../../../app_service/service/network_connection/service as network_connection_service import app_service/service/network_connection/service as network_connection_service
import ../../../app_service/service/visual_identity/service as procs_from_visual_identity_service import app_service/service/visual_identity/service as procs_from_visual_identity_service
import ../../../app_service/common/types import app_service/common/types
import ../../../app_service/common/utils as common_utils import app_service/common/utils as common_utils
import app_service/service/network/network_item import app_service/service/network/network_item
import ../../core/notifications/details import app/core/notifications/details
import ../../core/eventemitter import app/core/eventemitter
import ../../core/custom_urls/urls_manager import app/core/custom_urls/urls_manager
export io_interface export io_interface
@ -101,6 +101,7 @@ type
walletAccountService: wallet_account_service.Service walletAccountService: wallet_account_service.Service
keychainService: keychain_service.Service keychainService: keychain_service.Service
networkConnectionService: network_connection_service.Service networkConnectionService: network_connection_service.Service
stickersService: stickers_service.Service
walletSectionModule: wallet_section_module.AccessInterface walletSectionModule: wallet_section_module.AccessInterface
profileSectionModule: profile_section_module.AccessInterface profileSectionModule: profile_section_module.AccessInterface
stickersModule: stickers_module.AccessInterface stickersModule: stickers_module.AccessInterface
@ -207,6 +208,7 @@ proc newModule*[T](
result.accountsService = accountsService result.accountsService = accountsService
result.walletAccountService = walletAccountService result.walletAccountService = walletAccountService
result.keychainService = keychainService result.keychainService = keychainService
result.stickersService = stickersService
# Submodules # Submodules
result.chatSectionModules = initOrderedTable[string, chat_section_module.AccessInterface]() result.chatSectionModules = initOrderedTable[string, chat_section_module.AccessInterface]()
@ -436,6 +438,86 @@ proc createCommunitySectionItem[T](self: Module[T], communityDetails: CommunityD
activeMembersCount = int(communityDetails.activeMembersCount), activeMembersCount = int(communityDetails.activeMembersCount),
) )
proc sendNotification[T](self: Module[T], status: string, sendDetails: SendDetailsDto, sentTransaction: RouterSentTransaction) =
var
addressFrom = sendDetails.fromAddress
addressTo = sendDetails.toAddress
txTo = "" # txFrom is always the same as addressFrom, but txTo is different from addressTo when the app performs any sending flow via certain contract
fromChain = sendDetails.fromChain
toChain = sendDetails.toChain
fromAmount = sendDetails.fromAmount.toString(10)
toAmount = sendDetails.toAmount.toString(10)
fromAsset = sendDetails.fromToken
toAsset = sendDetails.toToken
error = ""
if not sendDetails.errorResponse.isNil:
error = sendDetails.errorResponse.details
if sentTransaction.hash.len > 0:
txTo = sentTransaction.toAddress
if sentTransaction.fromChain > 0:
fromChain = sentTransaction.fromChain
if sentTransaction.toChain > 0:
toChain = sentTransaction.toChain
let
txAmountIn = sentTransaction.amountIn.toString(10)
txAmountOut = sentTransaction.amountOut.toString(10)
if txAmountIn != "0":
fromAmount = txAmountIn
if txAmountOut != "0":
toAmount = txAmountOut
if sentTransaction.fromToken.len > 0:
fromAsset = sentTransaction.fromToken
if sentTransaction.toToken.len > 0:
toAsset = sentTransaction.toToken
var accFromName = ""
var accDto = self.walletAccountService.getAccountByAddress(addressFrom)
if not accDto.isNil:
accFromName = accDto.name
var accToName = ""
accDto = self.walletAccountService.getAccountByAddress(addressTo)
if not accDto.isNil:
accToName = accDto.name
var txToName = ""
let txType = SendType(sendDetails.sendType)
if txType == SendType.Bridge:
txToName = "Hop" # no translations, currently we hardcode providers here, when we add more, this info should come from the status-go side.
elif txType == SendType.Swap:
txToName = "ParaSwap" # no translations, currently we hardcode providers here, when we add more, this info should come from the status-go side.
else:
accDto = self.walletAccountService.getAccountByAddress(txTo)
if not accDto.isNil:
txToName = accDto.name
self.view.showTransactionToast(
sendDetails.uuid,
sendDetails.sendType,
fromChain,
toChain,
addressFrom,
accFromName,
addressTo,
accToName,
txTo,
txToName,
sentTransaction.hash,
sentTransaction.approvalTx,
fromAmount,
toAmount,
fromAsset,
toAsset,
sendDetails.username,
sendDetails.publicKey,
sendDetails.packId,
status,
error,
)
proc connectForNotificationsOnly[T](self: Module[T]) = proc connectForNotificationsOnly[T](self: Module[T]) =
self.events.on(SIGNAL_WALLET_ACCOUNT_SAVED) do(e:Args): self.events.on(SIGNAL_WALLET_ACCOUNT_SAVED) do(e:Args):
let args = AccountArgs(e) let args = AccountArgs(e)
@ -464,22 +546,26 @@ proc connectForNotificationsOnly[T](self: Module[T]) =
kpName = args.keypairs[0].name kpName = args.keypairs[0].name
self.view.showToastKeypairsImported(kpName, args.keypairs.len, args.error) self.view.showToastKeypairsImported(kpName, args.keypairs.len, args.error)
self.events.on(SIGNAL_SENDING_TRANSACTIONS_STARTED) do(e:Args):
let args = TransactionArgs(e)
# we allow this notification only if an error occurs, otherwise skip it and display notification after the tx gets submitted to the network
if args.sendDetails.errorResponse.isNil:
return
self.sendNotification(args.status, args.sendDetails, args.sentTransaction)
self.events.on(SIGNAL_TRANSACTION_SENT) do(e:Args): self.events.on(SIGNAL_TRANSACTION_SENT) do(e:Args):
let args = TransactionSentArgs(e) let args = TransactionArgs(e)
self.view.showToastTransactionSent(args.chainId, args.txHash, args.uuid, args.error, self.sendNotification(args.status, args.sendDetails, args.sentTransaction)
ord(args.txType), args.fromAddress, args.toAddress, args.fromTokenKey, args.fromAmount,
args.toTokenKey, args.toAmount) self.events.on(SIGNAL_TRANSACTION_STATUS_CHANGED) do(e:Args):
let args = TransactionArgs(e)
self.sendNotification(args.status, args.sendDetails, args.sentTransaction)
self.events.on(MARK_WALLET_ADDRESSES_AS_SHOWN) do(e:Args): self.events.on(MARK_WALLET_ADDRESSES_AS_SHOWN) do(e:Args):
let args = WalletAddressesArgs(e) let args = WalletAddressesArgs(e)
for address in args.addresses: for address in args.addresses:
self.addressWasShown(address) self.addressWasShown(address)
self.events.on(SIGNAL_TRANSACTION_SENDING_COMPLETE) do(e:Args):
let args = TransactionMinedArgs(e)
self.view.showToastTransactionSendingComplete(args.chainId, args.transactionHash, args.data, args.success,
ord(args.txType), args.fromAddress, args.toAddress, args.fromTokenKey, args.fromAmount, args.toTokenKey, args.toAmount)
self.events.on(SIGNAL_PAIRING_FALLBACK_COMPLETED) do(e:Args): self.events.on(SIGNAL_PAIRING_FALLBACK_COMPLETED) do(e:Args):
self.view.showToastPairingFallbackCompleted() self.view.showToastPairingFallbackCompleted()

View File

@ -339,12 +339,31 @@ QtObject:
proc showNetworkEndpointUpdated*(self: View, name: string, isTest: bool, revertedToDefault: bool) {.signal.} proc showNetworkEndpointUpdated*(self: View, name: string, isTest: bool, revertedToDefault: bool) {.signal.}
proc showToastKeypairRemoved*(self: View, keypairName: string) {.signal.} proc showToastKeypairRemoved*(self: View, keypairName: string) {.signal.}
proc showToastKeypairsImported*(self: View, keypairName: string, keypairsCount: int, error: string) {.signal.} proc showToastKeypairsImported*(self: View, keypairName: string, keypairsCount: int, error: string) {.signal.}
proc showToastTransactionSent*(self: View, chainId: int, txHash: string, uuid: string, error: string,
txType: int, fromAddr: string, toAddr: string, fromTokenKey: string, fromAmount: string, toTokenKey: string, toAmount: string) {.signal.}
proc showToastTransactionSendingComplete*(self: View, chainId: int, txHash: string, data: string, success: bool,
txType: int, fromAddr: string, toAddr: string, fromTokenKey: string, fromAmount: string, toTokenKey: string, toAmount: string) {.signal.}
proc showToastPairingFallbackCompleted*(self: View) {.signal.} proc showToastPairingFallbackCompleted*(self: View) {.signal.}
proc showTransactionToast*(self: View,
uuid: string,
txType: int,
fromChainId: int,
toChainId: int,
fromAddr: string,
fromName: string,
toAddr: string,
toName: string,
txToAddr: string,
txToName: string,
txHash: string,
approvalTx: bool,
fromAmount: string,
toAmount: string,
fromAsset: string,
toAsset: string,
username: string,
publicKey: string,
packId: string,
status: string,
error: string) {.signal.}
## Used in test env only, for testing keycard flows ## Used in test env only, for testing keycard flows
proc registerMockedKeycard*(self: View, cardIndex: int, readerState: int, keycardState: int, proc registerMockedKeycard*(self: View, cardIndex: int, readerState: int, keycardState: int,
mockedKeycard: string, mockedKeycardHelper: string) {.slot.} = mockedKeycard: string, mockedKeycardHelper: string) {.slot.} =

View File

@ -54,8 +54,14 @@ proc delete*(self: Controller) =
proc init*(self: Controller) = proc init*(self: Controller) =
self.events.on(SIGNAL_TRANSACTION_SENT) do(e:Args): self.events.on(SIGNAL_TRANSACTION_SENT) do(e:Args):
let args = TransactionSentArgs(e) let args = TransactionArgs(e)
self.delegate.transactionWasSent(args.uuid, args.chainId, args.approvalTx, args.txHash, args.error) self.delegate.transactionWasSent(
args.sendDetails.uuid,
args.sendDetails.fromChain,
args.sentTransaction.approvalTx,
args.sentTransaction.hash,
if not args.sendDetails.errorResponse.isNil: args.sendDetails.errorResponse.details else: ""
)
self.events.on(SIGNAL_OWNER_TOKEN_SENT) do(e:Args): self.events.on(SIGNAL_OWNER_TOKEN_SENT) do(e:Args):
let args = OwnerTokenSentArgs(e) let args = OwnerTokenSentArgs(e)
@ -76,8 +82,8 @@ proc init*(self: Controller) =
self.delegate.prepareSignaturesForTransactions(data.data) self.delegate.prepareSignaturesForTransactions(data.data)
self.events.on(SIGNAL_TRANSACTION_STATUS_CHANGED) do(e:Args): self.events.on(SIGNAL_TRANSACTION_STATUS_CHANGED) do(e:Args):
let args = TransactionStatusArgs(e) let args = TransactionArgs(e)
self.delegate.transactionSendingComplete(args.data.hash, args.data.status) self.delegate.transactionSendingComplete(args.sentTransaction.hash, args.status)
proc getWalletAccounts*(self: Controller): seq[wallet_account_service.WalletAccountDto] = proc getWalletAccounts*(self: Controller): seq[wallet_account_service.WalletAccountDto] =
return self.walletAccountService.getWalletAccounts() return self.walletAccountService.getWalletAccounts()

View File

@ -1,4 +1,6 @@
const const
ETH_SYMBOL* = "ETH"
ETH_TRANSACTION_TYPE* = "eth" ETH_TRANSACTION_TYPE* = "eth"
ERC20_TRANSACTION_TYPE* = "erc20" ERC20_TRANSACTION_TYPE* = "erc20"
ERC721_TRANSACTION_TYPE* = "erc721" ERC721_TRANSACTION_TYPE* = "erc721"

View File

@ -146,48 +146,55 @@ QtObject:
proc doConnect(self: Service) = proc doConnect(self: Service) =
self.events.on(SIGNAL_TRANSACTION_SENT) do(e:Args): self.events.on(SIGNAL_TRANSACTION_SENT) do(e:Args):
let args = TransactionSentArgs(e) let args = TransactionArgs(e)
if args.txType != SendType.ENSRegister and args.txType != SendType.ENSSetPubKey and args.txType != SendType.ENSRelease: let txType = SendType(args.sendDetails.sendType)
if txType != SendType.ENSRegister and txType != SendType.ENSSetPubKey and txType != SendType.ENSRelease:
return return
var err = args.error var err = if not args.sendDetails.errorResponse.isNil: args.sendDetails.errorResponse.details else: ""
var dto = EnsUsernameDto( var dto = EnsUsernameDto(
chainId: args.chainId, chainId: args.sendDetails.fromChain,
username: args.username, username: args.sendDetails.username,
txHash: args.txHash, txHash: args.sentTransaction.hash,
txStatus: TxStatusPending txStatus: args.status
) )
if args.txType == SendType.ENSRegister: if txType == SendType.ENSRegister:
dto.txType = RegisterENS dto.txType = RegisterENS
if err.len == 0: if err.len == 0:
let ensUsernameFinal = self.formatUsername(args.username, true) let ensUsernameFinal = self.formatUsername(args.sendDetails.username, true)
if not self.add(args.chainId, ensUsernameFinal): if not self.add(args.sendDetails.fromChain, ensUsernameFinal):
err = "failed to add ens username" err = "failed to add ens username"
error "error", err error "error", err
elif args.txType == SendType.ENSSetPubKey: elif txType == SendType.ENSSetPubKey:
dto.txType = SetPubKey dto.txType = SetPubKey
if err.len == 0: if err.len == 0:
let usernameWithDomain = args.username.addDomain() let usernameWithDomain = args.sendDetails.username.addDomain()
if not self.add(args.chainId, usernameWithDomain): if not self.add(args.sendDetails.fromChain, usernameWithDomain):
err = "failed to set ens username" err = "failed to set ens username"
error "error", err error "error", err
elif args.txType == SendType.ENSRelease: elif txType == SendType.ENSRelease:
dto.txType = ReleaseENS dto.txType = ReleaseENS
if err.len == 0: if err.len == 0:
let ensUsernameFinal = self.formatUsername(args.username, true) let ensUsernameFinal = self.formatUsername(args.sendDetails.username, true)
if not self.remove(args.chainId, ensUsernameFinal): if not self.remove(args.sendDetails.fromChain, ensUsernameFinal):
err = "failed to remove ens username" err = "failed to remove ens username"
error "error", err error "error", err
self.pendingEnsUsernames[makeKey(dto.username, args.chainId)] = dto self.pendingEnsUsernames[makeKey(dto.username, args.sendDetails.fromChain)] = dto
let data = EnsTxResultArgs(transactionType: $dto.txType, chainId: args.chainId, ensUsername: args.username, txHash: args.txHash, error: err) let data = EnsTxResultArgs(
transactionType: $dto.txType,
chainId: args.sendDetails.fromChain,
ensUsername: args.sendDetails.username,
txHash: args.sentTransaction.hash,
error: err
)
self.events.emit(SIGNAL_ENS_TRANSACTION_SENT, data) self.events.emit(SIGNAL_ENS_TRANSACTION_SENT, data)
self.events.on(SIGNAL_TRANSACTION_STATUS_CHANGED) do(e:Args): self.events.on(SIGNAL_TRANSACTION_STATUS_CHANGED) do(e:Args):
let args = TransactionStatusArgs(e) let args = TransactionArgs(e)
self.updateEnsUsernames(args.data.chainId, args.data.hash, args.data.status) self.updateEnsUsernames(args.sentTransaction.fromChain, args.sentTransaction.hash, args.status)
proc init*(self: Service) = proc init*(self: Service) =
self.doConnect() self.doConnect()

View File

@ -153,17 +153,23 @@ QtObject:
proc init*(self: Service) = proc init*(self: Service) =
self.events.on(SIGNAL_TRANSACTION_SENT) do(e:Args): self.events.on(SIGNAL_TRANSACTION_SENT) do(e:Args):
let args = TransactionSentArgs(e) let args = TransactionArgs(e)
if args.txType != SendType.StickersBuy: let txType = SendType(args.sendDetails.sendType)
if txType != SendType.StickersBuy:
return return
self.marketStickerPacks[$args.packId].status = StickerPackStatus.Pending self.marketStickerPacks[$args.sendDetails.packId].status = StickerPackStatus.Pending
self.marketStickerPacks[$args.packId].txHash = args.txHash self.marketStickerPacks[$args.sendDetails.packId].txHash = args.sentTransaction.hash
let data = StickerBuyResultArgs(chainId: args.chainId, packId: args.packId, txHash: args.txHash, error: args.error) let data = StickerBuyResultArgs(
chainId: args.sendDetails.fromChain,
packId: args.sendDetails.packId,
txHash: args.sentTransaction.hash,
error: if not args.sendDetails.errorResponse.isNil: args.sendDetails.errorResponse.details else: ""
)
self.events.emit(SIGNAL_STICKER_TRANSACTION_SENT, data) self.events.emit(SIGNAL_STICKER_TRANSACTION_SENT, data)
self.events.on(SIGNAL_TRANSACTION_STATUS_CHANGED) do(e:Args): self.events.on(SIGNAL_TRANSACTION_STATUS_CHANGED) do(e:Args):
let args = TransactionStatusArgs(e) let args = TransactionArgs(e)
self.updateStickersPack(args.data.hash, args.data.status) self.updateStickersPack(args.sentTransaction.hash, args.status)
proc setMarketStickerPacks*(self: Service, strickersJSON: string) {.slot.} = proc setMarketStickerPacks*(self: Service, strickersJSON: string) {.slot.} =
let stickersResult = Json.decode(strickersJSON, tuple[packs: seq[StickerPackDto], error: string]) let stickersResult = Json.decode(strickersJSON, tuple[packs: seq[StickerPackDto], error: string])
@ -222,6 +228,10 @@ QtObject:
return packId return packId
return "0" return "0"
proc getStickersByPackId*(self: Service, packId: string): StickerPackDto =
if self.marketStickerPacks.hasKey(packId):
return self.marketStickerPacks[packId]
proc getRecentStickers*(self: Service): seq[StickerDto] = proc getRecentStickers*(self: Service): seq[StickerDto] =
try: try:
let recentResponse = status_stickers.recent() let recentResponse = status_stickers.recent()

View File

@ -3,16 +3,11 @@ import json, stint
include ../../common/json_utils include ../../common/json_utils
const const
TxStatusSending* = "Sending"
TxStatusPending* = "Pending" TxStatusPending* = "Pending"
TxStatusSuccess* = "Success" TxStatusSuccess* = "Success"
TxStatusFailed* = "Failed" TxStatusFailed* = "Failed"
type
TransactionStatusChange* = ref object
status*: string
hash*: string
chainId*: int
type type
ErrorResponse* = ref object ErrorResponse* = ref object
details*: string details*: string
@ -21,6 +16,8 @@ type
SendDetailsDto* = ref object SendDetailsDto* = ref object
uuid*: string uuid*: string
sendType*: int sendType*: int
fromChain*: int
toChain*: int
fromAddress*: string fromAddress*: string
toAddress*: string toAddress*: string
fromToken*: string fromToken*: string
@ -54,7 +51,9 @@ type
toChain*: int toChain*: int
fromToken*: string fromToken*: string
toToken*: string toToken*: string
amount*: UInt256 # amount of the transaction amount*: UInt256 # amount sent
amountIn*: UInt256 # amount that is "data" of tx (important for erc20 tokens)
amountOut*: UInt256 # amount that will be received
hash*: string hash*: string
approvalTx*: bool approvalTx*: bool
@ -63,11 +62,13 @@ type
sendDetails*: SendDetailsDto sendDetails*: SendDetailsDto
sentTransactions*: seq[RouterSentTransaction] sentTransactions*: seq[RouterSentTransaction]
proc toTransactionStatusChange*(jsonObj: JsonNode): TransactionStatusChange = type
result = TransactionStatusChange() TransactionStatusChange* = ref object
discard jsonObj.getProp("status", result.status) status*: string
discard jsonObj.getProp("hash", result.hash) hash*: string
discard jsonObj.getProp("chainId", result.chainId) chainId*: int
sendDetails*: SendDetailsDto
sentTransactions*: seq[RouterSentTransaction]
proc toErrorResponse*(jsonObj: JsonNode): ErrorResponse = proc toErrorResponse*(jsonObj: JsonNode): ErrorResponse =
result = ErrorResponse() result = ErrorResponse()
@ -80,6 +81,8 @@ proc toSendDetailsDto*(jsonObj: JsonNode): SendDetailsDto =
result = SendDetailsDto() result = SendDetailsDto()
discard jsonObj.getProp("uuid", result.uuid) discard jsonObj.getProp("uuid", result.uuid)
discard jsonObj.getProp("sendType", result.sendType) discard jsonObj.getProp("sendType", result.sendType)
discard jsonObj.getProp("fromChain", result.fromChain)
discard jsonObj.getProp("toChain", result.toChain)
discard jsonObj.getProp("fromAddress", result.fromAddress) discard jsonObj.getProp("fromAddress", result.fromAddress)
discard jsonObj.getProp("toAddress", result.toAddress) discard jsonObj.getProp("toAddress", result.toAddress)
discard jsonObj.getProp("fromToken", result.fromToken) discard jsonObj.getProp("fromToken", result.fromToken)
@ -130,6 +133,10 @@ proc toRouterSentTransaction*(jsonObj: JsonNode): RouterSentTransaction =
var tmpObj: JsonNode var tmpObj: JsonNode
if jsonObj.getProp("amount", tmpObj): if jsonObj.getProp("amount", tmpObj):
result.amount = stint.fromHex(UInt256, tmpObj.getStr) result.amount = stint.fromHex(UInt256, tmpObj.getStr)
if jsonObj.getProp("amountIn", tmpObj):
result.amountIn = stint.fromHex(UInt256, tmpObj.getStr)
if jsonObj.getProp("amountOut", tmpObj):
result.amountOut = stint.fromHex(UInt256, tmpObj.getStr)
proc toRouterSentTransactionsDto*(jsonObj: JsonNode): RouterSentTransactionsDto = proc toRouterSentTransactionsDto*(jsonObj: JsonNode): RouterSentTransactionsDto =
result = RouterSentTransactionsDto() result = RouterSentTransactionsDto()
@ -139,3 +146,15 @@ proc toRouterSentTransactionsDto*(jsonObj: JsonNode): RouterSentTransactionsDto
if jsonObj.getProp("sentTransactions", tmpObj) and tmpObj.kind == JArray: if jsonObj.getProp("sentTransactions", tmpObj) and tmpObj.kind == JArray:
for tx in tmpObj: for tx in tmpObj:
result.sentTransactions.add(toRouterSentTransaction(tx)) result.sentTransactions.add(toRouterSentTransaction(tx))
proc toTransactionStatusChange*(jsonObj: JsonNode): TransactionStatusChange =
result = TransactionStatusChange()
discard jsonObj.getProp("status", result.status)
discard jsonObj.getProp("hash", result.hash)
discard jsonObj.getProp("chainId", result.chainId)
var tmpObj: JsonNode
if jsonObj.getProp("sendDetails", tmpObj) and tmpObj.kind == JObject:
result.sendDetails = toSendDetailsDto(tmpObj)
if jsonObj.getProp("sentTransactions", tmpObj) and tmpObj.kind == JArray:
for tx in tmpObj:
result.sentTransactions.add(toRouterSentTransaction(tx))

View File

@ -44,7 +44,6 @@ const SIGNAL_HISTORY_NON_ARCHIVAL_NODE* = "historyNonArchivalNode"
const SIGNAL_HISTORY_ERROR* = "historyError" const SIGNAL_HISTORY_ERROR* = "historyError"
const SIGNAL_TRANSACTION_DECODED* = "transactionDecoded" const SIGNAL_TRANSACTION_DECODED* = "transactionDecoded"
const SIGNAL_OWNER_TOKEN_SENT* = "ownerTokenSent" const SIGNAL_OWNER_TOKEN_SENT* = "ownerTokenSent"
const SIGNAL_TRANSACTION_SENDING_COMPLETE* = "transactionSendingComplete"
const SIGNAL_TRANSACTION_STATUS_CHANGED* = "transactionStatusChanged" const SIGNAL_TRANSACTION_STATUS_CHANGED* = "transactionStatusChanged"
const InternalErrorCode = -1 const InternalErrorCode = -1
@ -104,24 +103,6 @@ proc `$`*(self: TransactionMinedArgs): string =
except ValueError: except ValueError:
raiseAssert "static fmt" raiseAssert "static fmt"
type
TransactionSentArgs* = ref object of Args
chainId*: int
txHash*: string
uuid*: string
error*: string
txType*: SendType
fromAddress*: string
toAddress*: string
fromTokenKey*: string
fromAmount*: string
toTokenKey*: string
toAmount*: string
approvalTx*: bool
username*: string
publicKey*: string
packId*: string
type type
OwnerTokenSentArgs* = ref object of Args OwnerTokenSentArgs* = ref object of Args
chainId*: int chainId*: int
@ -147,12 +128,10 @@ type
data*: RouterTransactionsForSigningDto data*: RouterTransactionsForSigningDto
type type
RouterTransactionsSendingStartedArgs* = ref object of Args TransactionArgs* = ref object of Args
data*: SendDetailsDto status*: string
sendDetails*: SendDetailsDto
type sentTransaction*: RouterSentTransaction
TransactionStatusArgs* = ref object of Args
data*: TransactionStatusChange
QtObject: QtObject:
type Service* = ref object of QObject type Service* = ref object of QObject
@ -201,9 +180,10 @@ QtObject:
self.events.on(SignalType.WalletRouterSendingTransactionsStarted.event) do(e:Args): self.events.on(SignalType.WalletRouterSendingTransactionsStarted.event) do(e:Args):
var data = WalletSignal(e) var data = WalletSignal(e)
self.events.emit(SIGNAL_SENDING_TRANSACTIONS_STARTED, RouterTransactionsSendingStartedArgs(data: data.routerTransactionsSendingDetails)) self.events.emit(SIGNAL_SENDING_TRANSACTIONS_STARTED, TransactionArgs(
# TODO: the line below is to aling with the old implementation, remove it status: TxStatusSending,
self.sendTransactionsSignal(data.routerTransactionsSendingDetails) sendDetails: data.routerTransactionsSendingDetails
))
self.events.on(SignalType.WalletRouterSignTransactions.event) do(e:Args): self.events.on(SignalType.WalletRouterSignTransactions.event) do(e:Args):
var data = WalletSignal(e) var data = WalletSignal(e)
@ -219,18 +199,26 @@ QtObject:
self.events.on(SignalType.WalletTransactionStatusChanged.event) do(e:Args): self.events.on(SignalType.WalletTransactionStatusChanged.event) do(e:Args):
var data = WalletSignal(e) var data = WalletSignal(e)
self.events.emit(SIGNAL_TRANSACTION_STATUS_CHANGED, TransactionStatusArgs(data: data.transactionStatusChange)) if data.transactionStatusChange.isNil:
return
for tx in data.transactionStatusChange.sentTransactions:
self.events.emit(SIGNAL_TRANSACTION_STATUS_CHANGED, TransactionArgs(
status: data.transactionStatusChange.status,
sendDetails: data.transactionStatusChange.sendDetails,
sentTransaction: tx
))
self.events.on(PendingTransactionTypeDto.WalletTransfer.event) do(e: Args): # TODO: handle this for community related tx (minting, airdropping...)
try: # self.events.on(PendingTransactionTypeDto.WalletTransfer.event) do(e: Args):
var receivedData = TransactionMinedArgs(e) # try:
let tokenMetadata = receivedData.data.parseJson().toTokenTransferMetadata() # var receivedData = TransactionMinedArgs(e)
if tokenMetadata.isOwnerToken: # let tokenMetadata = receivedData.data.parseJson().toTokenTransferMetadata()
let status = if receivedData.success: ContractTransactionStatus.Completed else: ContractTransactionStatus.Failed # if tokenMetadata.isOwnerToken:
self.events.emit(SIGNAL_OWNER_TOKEN_SENT, OwnerTokenSentArgs(chainId: receivedData.chainId, txHash: receivedData.transactionHash, tokenName: tokenMetadata.tokenName, status: status)) # let status = if receivedData.success: ContractTransactionStatus.Completed else: ContractTransactionStatus.Failed
self.events.emit(SIGNAL_TRANSACTION_SENDING_COMPLETE, receivedData) # self.events.emit(SIGNAL_OWNER_TOKEN_SENT, OwnerTokenSentArgs(chainId: receivedData.chainId, txHash: receivedData.transactionHash, tokenName: tokenMetadata.tokenName, status: status))
except Exception as e: # self.events.emit(SIGNAL_TRANSACTION_SENDING_COMPLETE, receivedData)
debug "Not the owner token transfer", msg=e.msg # except Exception as e:
# debug "Not the owner token transfer", msg=e.msg
proc getPendingTransactions*(self: Service): seq[TransactionDto] = proc getPendingTransactions*(self: Service): seq[TransactionDto] =
try: try:
@ -330,21 +318,8 @@ QtObject:
# that's why we need to mark the addresses as shown here (safer). # that's why we need to mark the addresses as shown here (safer).
self.events.emit(MARK_WALLET_ADDRESSES_AS_SHOWN, WalletAddressesArgs(addresses: @[sendDetails.fromAddress, sendDetails.toAddress])) self.events.emit(MARK_WALLET_ADDRESSES_AS_SHOWN, WalletAddressesArgs(addresses: @[sendDetails.fromAddress, sendDetails.toAddress]))
if not sendDetails.errorResponse.isNil and sendDetails.errorResponse.details.len > 0: if sentTransactions.len == 0:
self.events.emit(SIGNAL_TRANSACTION_SENT, TransactionSentArgs( self.events.emit(SIGNAL_TRANSACTION_SENT, TransactionArgs(sendDetails: sendDetails))
uuid: sendDetails.uuid,
error: sendDetails.errorResponse.details,
txType: SendType(sendDetails.sendType),
fromAddress: sendDetails.fromAddress,
toAddress: sendDetails.toAddress,
fromTokenKey: sendDetails.fromToken,
fromAmount: sendDetails.fromAmount.toString(10),
toTokenKey: sendDetails.toToken,
toAmount: sendDetails.toAmount.toString(10),
username: sendDetails.username,
publicKey: sendDetails.publicKey,
packId: sendDetails.packId
))
return return
for tx in sentTransactions: for tx in sentTransactions:
@ -357,21 +332,10 @@ QtObject:
status: ContractTransactionStatus.InProgress status: ContractTransactionStatus.InProgress
)) ))
else: else:
self.events.emit(SIGNAL_TRANSACTION_SENT, TransactionSentArgs( self.events.emit(SIGNAL_TRANSACTION_SENT, TransactionArgs(
chainId: tx.fromChain, status: TxStatusSending, # here should be TxStatusPending state, but that's not what Figma wants
txHash: tx.hash, sendDetails: sendDetails,
uuid: sendDetails.uuid, sentTransaction: tx
txType: SendType(sendDetails.sendType),
fromAddress: tx.fromAddress,
toAddress: tx.toAddress,
fromTokenKey: tx.fromToken,
fromAmount: tx.amount.toString(10),
toTokenKey: tx.toToken,
toAmount: tx.amount.toString(10),
approvalTx: tx.approvalTx,
username: sendDetails.username,
publicKey: sendDetails.publicKey,
packId: sendDetails.packId
)) ))
proc suggestedFees*(self: Service, chainId: int): SuggestedFeesDto = proc suggestedFees*(self: Service, chainId: int): SuggestedFeesDto =

View File

@ -435,49 +435,5 @@ Item {
} }
} }
Connections {
target: ensView.ensUsernamesStore.ensUsernamesModule
function onTransactionCompleted(success: bool, txHash: string, username: string, trxType: string) {
let title = ""
switch(trxType){
case d.registerENS:
title = !success ?
qsTr("ENS Registration failed")
:
qsTr("ENS Registration completed");
break;
case d.setPubKey:
title = !success ?
qsTr("Updating ENS pubkey failed")
:
qsTr("Updating ENS pubkey completed");
break;
case d.releaseENS:
title = !success ?
qsTr("Releasing ENS name failed")
:
qsTr("ENS name released");
break
default:
console.error("unknown transaction type: ", trxType);
return
}
let icon = "block-icon";
let ephType = Constants.ephemeralNotificationType.normal;
if (success) {
icon = "check-circle";
ephType = Constants.ephemeralNotificationType.success;
}
let url = `${ensView.ensUsernamesStore.getEtherscanTxLink()}/${txHash}`;
Global.displayToastMessage(qsTr("Transaction pending..."),
qsTr("View on etherscan"),
icon,
false,
ephType,
url)
}
}
} }

View File

@ -237,121 +237,276 @@ Item {
) )
} }
function onShowToastTransactionSent(chainId: int, txHash: string, uuid: string, error: string, txType: int, function onShowTransactionToast(uuid: string,
fromAddr: string, toAddr: string, fromTokenKey: string, fromAmount: string, txType: int,
toTokenKey: string, toAmount: string) { fromChainId: int,
switch(txType) { toChainId: int,
case Constants.SendType.Approve: { fromAddr: string,
const fromToken = SQUtils.ModelUtils.getByKey(appMain.tokensStore.plainTokensBySymbolModel, "key", fromTokenKey) fromName: string,
const fromAccountName = SQUtils.ModelUtils.getByKey(appMain.transactionStore.accounts, "address", fromAddr, "name") toAddr: string,
const networkName = SQUtils.ModelUtils.getByKey(WalletStores.RootStore.filteredFlatModel, "chainId", chainId, "chainName") toName: string,
if(!!fromToken && !!fromAccountName && !!networkName) { txToAddr: string,
const approvalAmount = currencyStore.formatCurrencyAmountFromBigInt(fromAmount, fromToken.symbol, fromToken.decimals) txToName: string,
let toastTitle = qsTr("Setting spending cap: %1 in %2 for %3 on %4").arg(approvalAmount).arg(fromAccountName).arg(Constants.swap.paraswapHostname).arg(networkName) txHash: string,
let toastSubtitle = qsTr("View on %1").arg(networkName) approvalTx: bool,
let urlLink = "%1/%2".arg(appMain.rootStore.getEtherscanTxLink(chainId)).arg(txHash) fromAmount: string,
let toastType = Constants.ephemeralNotificationType.normal toAmount: string,
let icon = "" fromAsset: string,
if(error) { toAsset: string,
toastTitle = qsTr("Failed to set spending cap: %1 in %2 for %3 on %4").arg(approvalAmount).arg(fromAccountName).arg(Constants.swap.paraswapHostname).arg(networkName) username: string,
toastSubtitle = "" publicKey: string,
urlLink = "" packId: string,
toastType = Constants.ephemeralNotificationType.danger status: string,
icon = "warning" error: string) {
}
Global.displayToastMessage(toastTitle, toastSubtitle, icon, !error, toastType, urlLink)
}
break
}
case Constants.SendType.Swap: {
const fromToken = SQUtils.ModelUtils.getByKey(appMain.tokensStore.plainTokensBySymbolModel, "key", fromTokenKey)
const toToken = SQUtils.ModelUtils.getByKey(appMain.tokensStore.plainTokensBySymbolModel, "key", toTokenKey)
const fromAccountName = SQUtils.ModelUtils.getByKey(appMain.transactionStore.accounts, "address", fromAddr, "name")
const networkName = SQUtils.ModelUtils.getByKey(WalletStores.RootStore.filteredFlatModel, "chainId", chainId, "chainName")
if(!!fromToken && !!toToken && !!fromAccountName && !!networkName) {
const fromSwapAmount = currencyStore.formatCurrencyAmountFromBigInt(fromAmount, fromToken.symbol, fromToken.decimals)
const toSwapAmount = currencyStore.formatCurrencyAmountFromBigInt(toAmount, toToken.symbol, toToken.decimals)
let toastTitle = qsTr("Swapping %1 to %2 in %3 using %4 on %5").arg(fromSwapAmount).arg(toSwapAmount).arg(fromAccountName).arg(Constants.swap.paraswapHostname).arg(networkName)
let toastSubtitle = qsTr("View on %1").arg(networkName)
let urlLink = "%1/%2".arg(appMain.rootStore.getEtherscanTxLink(chainId)).arg(txHash)
let toastType = Constants.ephemeralNotificationType.normal
let icon = ""
if(error) {
toastTitle = qsTr("Failed to swap %1 to %2 in %3 using %4 on %5").arg(fromSwapAmount).arg(toSwapAmount).arg(fromAccountName).arg(Constants.swap.paraswapHostname).arg(networkName)
toastSubtitle = ""
urlLink = ""
toastType = Constants.ephemeralNotificationType.danger
icon = "warning"
}
Global.displayToastMessage(toastTitle, toastSubtitle, icon, !error, toastType, urlLink)
}
break
}
default: {
if (!error) {
let networkName = SQUtils.ModelUtils.getByKey(WalletStores.RootStore.filteredFlatModel, "chainId", chainId, "chainName")
if(!!networkName) {
Global.displayToastMessage(qsTr("Transaction pending..."),
qsTr("View on %1").arg(networkName),
"",
true,
Constants.ephemeralNotificationType.normal,
"%1/%2".arg(appMain.rootStore.getEtherscanTxLink(chainId)).arg(txHash))
}
}
break
}
}
}
function onShowToastTransactionSendingComplete(chainId: int, txHash: string, data: string, success: bool, let toastTitle = ""
txType: int, fromAddr: string, toAddr: string, fromTokenKey: string, let toastSubtitle = ""
fromAmount: string, toTokenKey: string, toAmount: string) { let toastIcon = ""
switch(txType) { let toastLoading = false
case Constants.SendType.Approve: { let toastType = Constants.ephemeralNotificationType.normal
const fromToken = SQUtils.ModelUtils.getByKey(appMain.tokensStore.plainTokensBySymbolModel, "key", fromTokenKey) let toastLink = ""
const fromAccountName = SQUtils.ModelUtils.getByKey(appMain.transactionStore.accounts, "address", fromAddr, "name")
const networkName = SQUtils.ModelUtils.getByKey(WalletStores.RootStore.filteredFlatModel, "chainId", chainId, "chainName") const sender = !!fromName? fromName : SQUtils.Utils.elideText(fromAddr, 6, 4)
if(!!fromToken && !!fromAccountName && !!networkName) { let senderChainName = qsTr("unknown")
const approvalAmount = currencyStore.formatCurrencyAmountFromBigInt(fromAmount, fromToken.symbol, fromToken.decimals) let sentAmount = ""
let toastTitle = qsTr("Spending cap set: %1 in %2 for %3 on %4").arg(approvalAmount).arg(fromAccountName).arg(Constants.swap.paraswapHostname).arg(networkName)
const toastSubtitle = qsTr("View on %1").arg(networkName) const recipient = !!toName? toName : SQUtils.Utils.elideText(toAddr, 6, 4)
const urlLink = "%1/%2".arg(appMain.rootStore.getEtherscanTxLink(chainId)).arg(txHash) const txRecipient = !!txToName? txToName : SQUtils.Utils.elideText(txToAddr, 6, 4)
let toastType = Constants.ephemeralNotificationType.success let recipientChainName = qsTr("unknown")
let icon = "checkmark-circle" let receivedAmount = ""
if(!success) {
toastTitle = qsTr("Failed to set spending cap: %1 in %2 for %3 on %4").arg(approvalAmount).arg(fromAccountName).arg(Constants.swap.paraswapHostname).arg(networkName) let assetName = qsTr("unknown")
toastType = Constants.ephemeralNotificationType.danger let ensName = d.ensName(username)
icon = "warning" let stickersPackName = qsTr("unknown")
if (!!txHash) {
toastLink = "%1/%2".arg(appMain.rootStore.getEtherscanTxLink(fromChainId)).arg(txHash)
}
const fromChainName = SQUtils.ModelUtils.getByKey(WalletStores.RootStore.filteredFlatModel, "chainId", fromChainId, "chainName")
if (!!fromChainName) {
senderChainName = fromChainName
toastSubtitle = qsTr("View on %1").arg(senderChainName)
}
const toChainName = SQUtils.ModelUtils.getByKey(WalletStores.RootStore.filteredFlatModel, "chainId", toChainId, "chainName")
if (!!toChainName) {
recipientChainName = toChainName
}
const fromToken = SQUtils.ModelUtils.getByKey(appMain.tokensStore.plainTokensBySymbolModel, "key", fromAsset)
if (!!fromToken) {
sentAmount = currencyStore.formatCurrencyAmountFromBigInt(fromAmount, fromToken.symbol, fromToken.decimals)
}
const toToken = SQUtils.ModelUtils.getByKey(appMain.tokensStore.plainTokensBySymbolModel, "key", toAsset)
if (!!toToken) {
receivedAmount = currencyStore.formatCurrencyAmountFromBigInt(toAmount, toToken.symbol, toToken.decimals)
}
if (txType === Constants.SendType.ERC721Transfer || txType === Constants.SendType.ERC1155Transfer) {
const key = "%1+%2+%3".arg(fromChainId).arg(txToAddr).arg(fromAsset)
const entry = SQUtils.ModelUtils.getByKey(appMain.walletCollectiblesStore.allCollectiblesModel, "symbol", key)
if (!!entry) {
assetName = entry.name
}
}
if (txType === Constants.SendType.StickersBuy) {
const idx = appMain.rootChatStore.stickersModuleInst.stickerPacks.findIndexById(packId, false)
if(idx >= 0) {
const entry = SQUtils.ModelUtils.get(appMain.rootChatStore.stickersModuleInst.stickerPacks, idx)
if (!!entry) {
stickersPackName = entry.name
} }
Global.displayToastMessage(toastTitle, toastSubtitle, icon, false, toastType, urlLink) }
}
switch(status) {
case Constants.txStatus.sending: {
toastTitle = qsTr("Sending %1 from %2 to %3")
toastLoading = true
switch(txType) {
case Constants.SendType.Transfer: {
toastTitle = toastTitle.arg(sentAmount).arg(sender).arg(recipient)
break
}
case Constants.SendType.ENSRegister: {
toastTitle = qsTr("Registering %1 ENS name using %2").arg(ensName).arg(sender)
break
}
case Constants.SendType.ENSRelease: {
toastTitle = qsTr("Releasing %1 ENS username using %2").arg(ensName).arg(sender)
break
}
case Constants.SendType.ENSSetPubKey: {
toastTitle = qsTr("Setting public key %1 using %2").arg(ensName).arg(sender)
break
}
case Constants.SendType.StickersBuy: {
toastTitle = qsTr("Purchasing %1 sticker pack using %2").arg(stickersPackName).arg(sender)
break
}
case Constants.SendType.Bridge: {
toastTitle = qsTr("Bridging %1 from %2 to %3 in %4").arg(sentAmount).arg(senderChainName).arg(recipientChainName).arg(sender)
if (approvalTx) {
toastTitle = qsTr("Setting spending cap: %1 in %2 for %3").arg(sentAmount).arg(sender).arg(txRecipient)
}
break
}
case Constants.SendType.ERC721Transfer: {
toastTitle = toastTitle.arg(assetName).arg(sender).arg(recipient)
break
}
case Constants.SendType.ERC1155Transfer: {
toastTitle = qsTr("Sending %1 %2 from %3 to %4").arg(fromAmount).arg(assetName).arg(sender).arg(recipient)
break
}
case Constants.SendType.Swap: {
toastTitle = qsTr("Swapping %1 to %2 in %3").arg(sentAmount).arg(receivedAmount).arg(sender)
if (approvalTx) {
toastTitle = qsTr("Setting spending cap: %1 in %2 for %3").arg(sentAmount).arg(sender).arg(txRecipient)
}
break
}
case Constants.SendType.Approve: {
console.warn("tx type approve not yet identified as a stand alone path")
break
}
default:
console.warn("status: sending - tx type not supproted")
return
} }
break break
} }
case Constants.SendType.Swap: { case Constants.txStatus.pending: {
const fromToken = SQUtils.ModelUtils.getByKey(appMain.tokensStore.plainTokensBySymbolModel, "key", fromTokenKey) // So far we don't display notification when it's accepted by the network and its status is pending
const toToken = SQUtils.ModelUtils.getByKey(appMain.tokensStore.plainTokensBySymbolModel, "key", toTokenKey) // discussed in wallet group chat, we considered that pending status will be displayed almost at the
const fromAccountName = SQUtils.ModelUtils.getByKey(appMain.transactionStore.accounts, "address", fromAddr, "name") // same time as sending and decided to skip it.
const networkName = SQUtils.ModelUtils.getByKey(WalletStores.RootStore.filteredFlatModel, "chainId", chainId, "chainName") return
if(!!fromToken && !!toToken && !!fromAccountName && !!networkName) { }
const fromSwapAmount = currencyStore.formatCurrencyAmountFromBigInt(fromAmount, fromToken.symbol, fromToken.decimals) case Constants.txStatus.success: {
const toSwapAmount = currencyStore.formatCurrencyAmountFromBigInt(toAmount, toToken.symbol, toToken.decimals) toastTitle = qsTr("Sent %1 from %2 to %3")
let toastTitle = qsTr("Swapped %1 to %2 in %3 using %4 on %5").arg(fromSwapAmount).arg(toSwapAmount).arg(fromAccountName).arg(Constants.swap.paraswapHostname).arg(networkName) toastIcon = "checkmark-circle"
const toastSubtitle = qsTr("View on %1").arg(networkName) toastType = Constants.ephemeralNotificationType.success
const urlLink = "%1/%2".arg(appMain.rootStore.getEtherscanTxLink(chainId)).arg(txHash)
let toastType = Constants.ephemeralNotificationType.success switch(txType) {
let icon = "checkmark-circle" case Constants.SendType.Transfer: {
if(!success) { toastTitle = toastTitle.arg(sentAmount).arg(sender).arg(recipient)
toastTitle = qsTr("Failed to swap %1 to %2 in %3 using %4 on %5").arg(fromSwapAmount).arg(toSwapAmount).arg(fromAccountName).arg(Constants.swap.paraswapHostname).arg(networkName) break
toastType = Constants.ephemeralNotificationType.danger }
icon = "warning" case Constants.SendType.ENSRegister: {
toastTitle = qsTr("Registered %1 ENS name using %2").arg(ensName).arg(sender)
break
}
case Constants.SendType.ENSRelease: {
toastTitle = qsTr("Released %1 ENS username using %2").arg(ensName).arg(sender)
break
}
case Constants.SendType.ENSSetPubKey: {
toastTitle = qsTr("Set public key %1 using %2").arg(ensName).arg(sender)
break
}
case Constants.SendType.StickersBuy: {
toastTitle = qsTr("Purchased %1 sticker pack using %2").arg(stickersPackName).arg(sender)
break
}
case Constants.SendType.Bridge: {
toastTitle = qsTr("Bridged %1 from %2 to %3 in %4").arg(sentAmount).arg(senderChainName).arg(recipientChainName).arg(sender)
if (approvalTx) {
toastTitle = qsTr("Spending spending cap: %1 in %2 for %3").arg(sentAmount).arg(sender).arg(txRecipient)
} }
Global.displayToastMessage(toastTitle, toastSubtitle, icon, false, toastType, urlLink) break
}
case Constants.SendType.ERC721Transfer: {
toastTitle = toastTitle.arg(assetName).arg(sender).arg(recipient)
break
}
case Constants.SendType.ERC1155Transfer: {
toastTitle = qsTr("Sent %1 %2 from %3 to %4").arg(fromAmount).arg(assetName).arg(sender).arg(recipient)
break
}
case Constants.SendType.Swap: {
toastTitle = qsTr("Swapped %1 to %2 in %3").arg(sentAmount).arg(receivedAmount).arg(sender)
if (approvalTx) {
toastTitle = qsTr("Spending cap set: %1 in %2 for %3").arg(sentAmount).arg(sender).arg(txRecipient)
}
break
}
case Constants.SendType.Approve: {
console.warn("tx type approve not yet identified as a stand alone path")
break
}
default:
console.warn("status: success - tx type not supproted")
return
} }
break break
} }
default: break case Constants.txStatus.failed: {
toastTitle = "Send failed: %1 from %2 to %3"
toastIcon = "warning"
toastType = Constants.ephemeralNotificationType.danger
switch(txType) {
case Constants.SendType.Transfer: {
toastTitle = toastTitle.arg(sentAmount).arg(sender).arg(recipient)
break
}
case Constants.SendType.ENSRegister: {
toastTitle = qsTr("ENS username registeration failed: %1 using %2").arg(ensName).arg(sender)
break
}
case Constants.SendType.ENSRelease: {
toastTitle = qsTr("ENS username release failed: %1 using %2").arg(ensName).arg(sender)
break
}
case Constants.SendType.ENSSetPubKey: {
toastTitle = qsTr("Set public key failed: %1 using %2").arg(ensName).arg(sender)
break
}
case Constants.SendType.StickersBuy: {
toastTitle = qsTr("Sticker pack purchase failed: %1 using %2").arg(stickersPackName).arg(sender)
break
}
case Constants.SendType.Bridge: {
toastTitle = qsTr("Bridge failed: %1 from %2 to %3 in %4").arg(sentAmount).arg(senderChainName).arg(recipientChainName).arg(sender)
if (approvalTx) {
toastTitle = qsTr("Spending spending failed: %1 in %2 for %3").arg(sentAmount).arg(sender).arg(txRecipient)
}
break
}
case Constants.SendType.ERC721Transfer: {
toastTitle = toastTitle.arg(assetName).arg(sender).arg(recipient)
break
}
case Constants.SendType.ERC1155Transfer: {
toastTitle = qsTr("Send failed: %1 %2 from %3 to %4").arg(fromAmount).arg(assetName).arg(sender).arg(recipient)
break
}
case Constants.SendType.Swap: {
toastTitle = qsTr("Swapp failed: %1 to %2 in %3").arg(sentAmount).arg(receivedAmount).arg(sender)
if (approvalTx) {
toastTitle = qsTr("Spending cap failed: %1 in %2 for %3").arg(sentAmount).arg(sender).arg(txRecipient)
}
break
}
case Constants.SendType.Approve: {
console.warn("tx type approve not yet identified as a stand alone path")
break
}
default:
console.warn("status: failed - tx type not supproted")
return
}
break
} }
default:
console.warn("not supported status")
return
}
Global.displayToastMessage(toastTitle, toastSubtitle, toastIcon, toastLoading, toastType, toastLink)
} }
function onCommunityMemberStatusEphemeralNotification(communityName: string, memberName: string, state: CommunityMembershipRequestState) { function onCommunityMemberStatusEphemeralNotification(communityName: string, memberName: string, state: CommunityMembershipRequestState) {
@ -408,6 +563,13 @@ Item {
activityCenterPopupObj.open() activityCenterPopupObj.open()
} }
} }
function ensName(username) {
if (!username.endsWith(".stateofus.eth") && !username.endsWith(".eth")) {
return "%1.%2".arg(username).arg("stateofus.eth")
}
return username
}
} }
Settings { Settings {

View File

@ -1104,6 +1104,13 @@ QtObject {
High High
} }
readonly property QtObject txStatus: QtObject {
readonly property string sending: "Sending"
readonly property string pending: "Pending"
readonly property string success: "Success"
readonly property string failed: "Failed"
}
enum LoginType { enum LoginType {
Password, Password,
Biometrics, Biometrics,