chore: align buying stickers flow with the new sending flow

Based on changes done in this PR https://github.com/status-im/status-go/pull/5807
we can simplify our client logic a lot.

This results in the removal of many lines of code that are no longer needed

Closes 1st part of #16336
This commit is contained in:
Sale Djenic 2024-09-25 14:48:04 +02:00 committed by saledjenic
parent ad7e2df78a
commit ee9091377f
14 changed files with 70 additions and 523 deletions

View File

@ -222,7 +222,7 @@ proc newModule*[T](
networkService, keycardService, keychainService, tokenService, nodeService
)
result.stickersModule = stickers_module.newModule(result, events, stickersService, settingsService, walletAccountService,
networkService, tokenService, keycardService)
networkService, tokenService)
result.gifsModule = gifs_module.newModule(result, events, gifService)
result.activityCenterModule = activity_center_module.newModule(result, events, activityCenterService, contactsService,
messageService, chatService, communityService)

View File

@ -1,4 +1,4 @@
import Tables, uuids, stint, json
import Tables, uuids, stint
import ./io_interface
@ -7,14 +7,8 @@ import app_service/service/stickers/service as stickers_service
import app_service/service/token/service
import app_service/service/settings/service as settings_service
import app_service/service/network/service as network_service
import app_service/service/eth/utils as eth_utils
import app_service/service/wallet_account/service as wallet_account_service
import app_service/service/token/service as token_service
import app_service/service/keycard/service as keycard_service
import app/modules/shared_modules/keycard_popup/io_interface as keycard_shared_module
import app_service/service/network/network_item
const UNIQUE_BUY_STICKER_TRANSACTION_MODULE_IDENTIFIER* = "StickersSection-TransactionModule"
type
Controller* = ref object of RootObj
@ -25,7 +19,6 @@ type
networkService: network_service.Service
walletAccountService: wallet_account_service.Service
tokenService: token_service.Service
keycardService: keycard_service.Service
connectionKeycardResponse: UUID
disconnected: bool
@ -37,7 +30,6 @@ proc newController*(
walletAccountService: wallet_account_service.Service,
networkService: network_service.Service,
tokenService: token_service.Service,
keycardService: keycard_service.Service
): Controller =
result = Controller()
result.delegate = delegate
@ -47,7 +39,6 @@ proc newController*(
result.networkService = networkService
result.walletAccountService = walletAccountService
result.tokenService = tokenService
result.keycardService = keycardService
result.disconnected = false
proc delete*(self: Controller) =
@ -81,9 +72,9 @@ proc init*(self: Controller) =
self.events.on(SIGNAL_ALL_STICKER_PACKS_LOAD_FAILED) do(e: Args):
self.delegate.allPacksLoadFailed()
self.events.on(SIGNAL_STICKER_GAS_ESTIMATED) do(e: Args):
let args = StickerGasEstimatedArgs(e)
self.delegate.gasEstimateReturned(args.estimate, args.uuid)
self.events.on(SIGNAL_STICKER_TRANSACTION_SENT) do(e:Args):
let args = StickerBuyResultArgs(e)
self.delegate.stickerTransactionSent(args.chainId, args.packId, args.txHash, args.error)
self.events.on(SIGNAL_STICKER_TRANSACTION_CONFIRMED) do(e:Args):
let args = StickerTransactionArgs(e)
@ -93,28 +84,10 @@ proc init*(self: Controller) =
let args = StickerTransactionArgs(e)
self.delegate.stickerTransactionReverted(args.transactionType, args.packID, args.transactionHash)
self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_USER_AUTHENTICATED) do(e: Args):
let args = SharedKeycarModuleArgs(e)
if args.uniqueIdentifier != UNIQUE_BUY_STICKER_TRANSACTION_MODULE_IDENTIFIER:
return
self.delegate.onKeypairAuthenticated(args.password, args.pin)
self.events.on(SIGNAL_STICKER_PACK_INSTALLED) do(e: Args):
let args = StickerPackInstalledArgs(e)
self.delegate.onStickerPackInstalled(args.packId)
proc prepareTxForBuyingStickers*(self: Controller, chainId: int, packId: string, address: string, gas: string, gasPrice: string,
maxPriorityFeePerGas: string, maxFeePerGas: string, eip1559Enabled: bool): JsonNode =
return self.stickerService.prepareTxForBuyingStickers(chainId, packId, address, gas, gasPrice, maxPriorityFeePerGas,
maxFeePerGas, eip1559Enabled)
proc signBuyingStickersTxLocally*(self: Controller, data, account, hashedPasssword: string): string =
return self.stickerService.signBuyingStickersTxLocally(data, account, hashedPasssword)
proc sendBuyingStickersTxWithSignatureAndWatch*(self: Controller, chainId: int, txData: JsonNode, packId: string,
signature: string): StickerBuyResultArgs =
return self.stickerService.sendBuyingStickersTxWithSignatureAndWatch(chainId, txData, packId, signature)
proc getRecentStickers*(self: Controller): seq[StickerDto] =
return self.stickerService.getRecentStickers()
@ -124,9 +97,6 @@ proc loadRecentStickers*(self: Controller) =
proc loadInstalledStickerPacks*(self: Controller) =
self.stickerService.asyncLoadInstalledStickerPacks()
proc estimate*(self: Controller, packId: string, address: string, price: string, uuid: string) =
self.stickerService.estimate(packId, address, price, uuid)
proc getInstalledStickerPacks*(self: Controller): Table[string, StickerPackDto] =
self.stickerService.getInstalledStickerPacks()
@ -153,9 +123,6 @@ proc sendSticker*(
preferredUsername: string) =
self.stickerService.asyncSendSticker(channelId, replyTo, sticker, preferredUsername)
proc wei2Eth*(self: Controller, price: Stuint[256]): string =
eth_utils.wei2Eth(price)
proc getSigningPhrase*(self: Controller): string =
return self.settingsService.getSigningPhrase()
@ -165,40 +132,8 @@ proc getStickerMarketAddress*(self: Controller): string =
proc getWalletDefaultAddress*(self: Controller): string =
return self.walletAccountService.getWalletAccount(0).address
proc getKeypairByAccountAddress*(self: Controller, address: string): KeypairDto =
return self.walletAccountService.getKeypairByAccountAddress(address)
proc getCurrentCurrency*(self: Controller): string =
return self.settingsService.getCurrency()
proc getAppNetwork*(self: Controller): NetworkItem =
return self.networkService.getAppNetwork()
proc getStatusTokenKey*(self: Controller): string =
return self.tokenService.getStatusTokenKey()
proc authenticate*(self: Controller, keyUid = "") =
let data = SharedKeycarModuleAuthenticationArgs(uniqueIdentifier: UNIQUE_BUY_STICKER_TRANSACTION_MODULE_IDENTIFIER,
keyUid: keyUid)
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_AUTHENTICATE_USER, data)
proc disconnectKeycardReponseSignal(self: Controller) =
self.events.disconnect(self.connectionKeycardResponse)
proc connectKeycardReponseSignal(self: Controller) =
self.connectionKeycardResponse = self.events.onWithUUID(SIGNAL_KEYCARD_RESPONSE) do(e: Args):
let args = KeycardLibArgs(e)
self.disconnectKeycardReponseSignal()
let currentFlow = self.keycardService.getCurrentFlow()
if currentFlow != KCSFlowType.Sign:
self.delegate.onTransactionSigned("", KeycardEvent())
return
self.delegate.onTransactionSigned(args.flowType, args.flowEvent)
proc cancelCurrentFlow*(self: Controller) =
self.keycardService.cancelCurrentFlow()
proc runSignFlow*(self: Controller, pin, bip44Path, txHash: string) =
self.cancelCurrentFlow()
self.connectKeycardReponseSignal()
self.keycardService.startSignFlow(bip44Path, txHash, pin)

View File

@ -1,8 +1,7 @@
import Tables, stint
import Tables
import ./item
import app_service/service/stickers/service as stickers_service
from app_service/service/keycard/service import KeycardEvent
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
@ -20,9 +19,6 @@ method isLoaded*(self: AccessInterface): bool {.base.} =
method viewDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method authenticateAndBuy*(self: AccessInterface, packId: string, address: string, gas: string, gasPrice: string, maxPriorityFeePerGas: string, maxFeePerGas: string, eip1559Enabled: bool){.base.} =
raise newException(ValueError, "No implementation available")
method getRecentStickers*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
@ -68,8 +64,6 @@ method onStickerPackInstalled*(self: AccessInterface, packId: string) {.base.} =
method uninstallStickerPack*(self: AccessInterface, packId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method wei2Eth*(self: AccessInterface, price: Stuint[256]): string {.base.} =
raise newException(ValueError, "No implementation available")
method removeRecentStickers*(self: AccessInterface, packId: string) {.base.} =
raise newException(ValueError, "No implementation available")
@ -80,9 +74,6 @@ method sendSticker*(self: AccessInterface, channelId: string, replyTo: string, s
method populateInstalledStickerPacks*(self: AccessInterface, stickers: Table[string, StickerPackDto]) {.base.} =
raise newException(ValueError, "No implementation available")
method gasEstimateReturned*(self: AccessInterface, estimate: int, uuid: string) {.base.} =
raise newException(ValueError, "No implementation available")
method addStickerPackToList*(self: AccessInterface, stickerPack: StickerPackDto, isInstalled: bool, isBought: bool, isPending: bool) {.base.} =
raise newException(ValueError, "No implementation available")
@ -92,20 +83,15 @@ method getWalletDefaultAddress*(self: AccessInterface): string {.base.} =
method getCurrentCurrency*(self: AccessInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method getGasEthValue*(self: AccessInterface, gweiValue: string, gasLimit: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method getStatusTokenKey*(self: AccessInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method stickerTransactionSent*(self: AccessInterface, chainId: int, packId: string, txHash: string, error: string) {.base.} =
raise newException(ValueError, "No implementation available")
method stickerTransactionConfirmed*(self: AccessInterface, trxType: string, packID: string, transactionHash: string) {.base.} =
raise newException(ValueError, "No implementation available")
method stickerTransactionReverted*(self: AccessInterface, trxType: string, packID: string, transactionHash: string) {.base.} =
raise newException(ValueError, "No implementation available")
method onKeypairAuthenticated*(self: AccessInterface, password: string, pin: string) {.base.} =
raise newException(ValueError, "No implementation available")
method onTransactionSigned*(self: AccessInterface, keycardFlowType: string, keycardEvent: KeycardEvent) {.base.} =
raise newException(ValueError, "No implementation available")
raise newException(ValueError, "No implementation available")

View File

@ -2,7 +2,9 @@ import NimQml, Tables, sequtils, sugar
import ./sticker_list
import ../io_interface, ../item
# TODO remove those uses of services stuff
import ../../../../../app_service/service/eth/utils as eth_utils
import app_service/service/eth/utils as eth_utils
import app_service/common/conversion as service_conversion
type
StickerPackRoles {.pure.} = enum
@ -57,7 +59,7 @@ QtObject:
of StickerPackRoles.Author: result = newQVariant(stickerPack.author)
of StickerPackRoles.Id: result = newQVariant(stickerPack.id)
of StickerPackRoles.Name: result = newQVariant(stickerPack.name)
of StickerPackRoles.Price: result = newQVariant(self.delegate.wei2Eth(stickerPack.price))
of StickerPackRoles.Price: result = newQVariant(service_conversion.wei2Eth(stickerPack.price))
of StickerPackRoles.Preview: result = newQVariant(stickerPack.preview)
of StickerPackRoles.Stickers: result = newQVariant(packInfo.stickers)
of StickerPackRoles.Thumbnail: result = newQVariant(stickerPack.thumbnail)

View File

@ -1,4 +1,4 @@
import NimQml, Tables, stint, sugar, sequtils, json, strutils, stew/shims/strformat, parseutils, chronicles
import NimQml, Tables, sugar, sequtils
import ./io_interface, ./view, ./controller, ./item, ./models/sticker_pack_list
import ../io_interface as delegate_interface
import app/global/global_singleton
@ -6,30 +6,13 @@ import app/core/eventemitter
import app_service/service/stickers/service as stickers_service
import app_service/service/settings/service as settings_service
import app_service/service/network/service as network_service
import app_service/common/conversion as service_conversion
import app_service/common/utils as common_utils
import app_service/common/wallet_constants as common_wallet_constants
import app_service/service/wallet_account/service as wallet_account_service
import app_service/service/token/service as token_service
import app_service/service/keycard/service as keycard_service
import app_service/service/keycard/constants as keycard_constants
export io_interface
const cancelledRequest* = "cancelled"
# Shouldn't be public ever, use only within this module.
type TmpBuyStickersTransactionDetails = object
packId: string
address: string
addressPath: string
gas: string
gasPrice: string
maxPriorityFeePerGas: string
maxFeePerGas: string
eip1559Enabled: bool
txData: JsonNode
type
Module* = ref object of io_interface.AccessInterface
delegate: delegate_interface.AccessInterface
@ -37,7 +20,6 @@ type
view: View
viewVariant: QVariant
moduleLoaded: bool
tmpBuyStickersTransactionDetails: TmpBuyStickersTransactionDetails
proc newModule*(
delegate: delegate_interface.AccessInterface,
@ -47,14 +29,13 @@ proc newModule*(
walletAccountService: wallet_account_service.Service,
networkService: network_service.Service,
tokenService: token_service.Service,
keycardService: keycard_service.Service
): Module =
result = Module()
result.delegate = delegate
result.view = newView(result)
result.viewVariant = newQVariant(result.view)
result.controller = controller.newController(result, events, stickersService, settingsService, walletAccountService,
networkService, tokenService, keycardService)
networkService, tokenService)
result.moduleLoaded = false
singletonInstance.engine.setRootContextProperty("stickersModule", result.viewVariant)
@ -62,13 +43,6 @@ proc newModule*(
method delete*(self: Module) =
self.view.delete
proc clear(self: Module) =
self.tmpBuyStickersTransactionDetails = TmpBuyStickersTransactionDetails()
proc finish(self: Module, chainId: int, txHash: string, error: string) =
self.clear()
self.view.transactionWasSent(chainId, txHash, error)
method load*(self: Module) =
self.controller.init()
let signingPhrase = self.controller.getSigningPhrase()
@ -82,108 +56,6 @@ method viewDidLoad*(self: Module) =
self.moduleLoaded = true
self.delegate.stickersDidLoad()
method authenticateAndBuy*(self: Module, packId: string, address: string, gas: string, gasPrice: string, maxPriorityFeePerGas: string, maxFeePerGas: string, eip1559Enabled: bool) =
self.tmpBuyStickersTransactionDetails.packId = packId
self.tmpBuyStickersTransactionDetails.address = address
self.tmpBuyStickersTransactionDetails.gas = gas
self.tmpBuyStickersTransactionDetails.gasPrice = gasPrice
self.tmpBuyStickersTransactionDetails.maxPriorityFeePerGas = maxPriorityFeePerGas
self.tmpBuyStickersTransactionDetails.maxFeePerGas = maxFeePerGas
self.tmpBuyStickersTransactionDetails.eip1559Enabled = eip1559Enabled
self.tmpBuyStickersTransactionDetails.txData = nil
let kp = self.controller.getKeypairByAccountAddress(address)
if kp.migratedToKeycard():
let accounts = kp.accounts.filter(acc => cmpIgnoreCase(acc.address, address) == 0)
if accounts.len != 1:
error "cannot resolve selected account to send from among known keypair accounts"
return
self.tmpBuyStickersTransactionDetails.addressPath = accounts[0].path
self.controller.authenticate(kp.keyUid)
else:
self.controller.authenticate()
proc sendBuyingStickersTxWithSignatureAndWatch(self: Module, signature: string) =
if self.tmpBuyStickersTransactionDetails.txData.isNil:
let errMsg = "unexpected error while sending buying stickers tx"
error "error", msg=errMsg, methodName="sendBuyingStickersTxWithSignatureAndWatch"
self.finish(chainId = 0, txHash = "", error = errMsg)
return
let response = self.controller.sendBuyingStickersTxWithSignatureAndWatch(
self.controller.getAppNetwork().chainId,
self.tmpBuyStickersTransactionDetails.txData,
self.tmpBuyStickersTransactionDetails.packId,
signature
)
if not response.error.isEmptyOrWhitespace():
error "sending buying stickers tx failed", errMsg=response.error, methodName="sendBuyingStickersTxWithSignatureAndWatch"
self.finish(chainId = 0, txHash = "", error = response.error)
return
self.view.stickerPacks.updateStickerPackInList(self.tmpBuyStickersTransactionDetails.packId, installed = false, pending = true)
self.finish(response.chainId, response.txHash, response.error)
method onKeypairAuthenticated*(self: Module, password: string, pin: string) =
if password.len == 0:
self.finish(chainId = 0, txHash = "", error = cancelledRequest)
return
let txDataJson = self.controller.prepareTxForBuyingStickers(
self.controller.getAppNetwork().chainId,
self.tmpBuyStickersTransactionDetails.packId,
self.tmpBuyStickersTransactionDetails.address,
self.tmpBuyStickersTransactionDetails.gas,
self.tmpBuyStickersTransactionDetails.gasPrice,
self.tmpBuyStickersTransactionDetails.maxPriorityFeePerGas,
self.tmpBuyStickersTransactionDetails.maxFeePerGas,
self.tmpBuyStickersTransactionDetails.eip1559Enabled
)
if txDataJson.isNil or
txDataJson.kind != JsonNodeKind.JObject or
not txDataJson.hasKey("txArgs") or
not txDataJson.hasKey("messageToSign"):
let errMsg = "unexpected response format preparing tx for buying stickers"
error "error", msg=errMsg, methodName="onKeypairAuthenticated"
self.finish(chainId = 0, txHash = "", error = errMsg)
return
var txToBeSigned = txDataJson["messageToSign"].getStr
if txToBeSigned.len != common_wallet_constants.TX_HASH_LEN_WITH_PREFIX:
let errMsg = "unexpected tx hash length"
error "error", msg=errMsg, methodName="onKeypairAuthenticated"
self.finish(chainId = 0, txHash = "", error = errMsg)
return
self.tmpBuyStickersTransactionDetails.txData = txDataJson["txArgs"]
if txDataJson.hasKey("signOnKeycard") and txDataJson["signOnKeycard"].getBool:
if pin.len != PINLengthForStatusApp:
let errMsg = "cannot proceed with keycard signing, unexpected pin"
error "error", msg=errMsg, methodName="onKeypairAuthenticated"
self.finish(chainId = 0, txHash = "", error = errMsg)
return
var txForKcFlow = txToBeSigned
if txForKcFlow.startsWith("0x"):
txForKcFlow = txForKcFlow[2..^1]
self.controller.runSignFlow(pin, self.tmpBuyStickersTransactionDetails.addressPath, txForKcFlow)
return
var finalPassword = password
if pin.len == 0:
finalPassword = common_utils.hashPassword(password)
let signature = self.controller.signBuyingStickersTxLocally(txToBeSigned, self.tmpBuyStickersTransactionDetails.address, finalPassword)
if signature.len == 0:
let errMsg = "couldn't sign tx locally"
error "error", msg=errMsg, methodName="onKeypairAuthenticated"
self.finish(chainId = 0, txHash = "", error = errMsg)
return
self.sendBuyingStickersTxWithSignatureAndWatch(signature)
method obtainMarketStickerPacks*(self: Module) =
self.controller.obtainMarketStickerPacks()
@ -205,9 +77,6 @@ method uninstallStickerPack*(self: Module, packId: string) =
method removeRecentStickers*(self: Module, packId: string) =
self.controller.removeRecentStickers(packId)
method wei2Eth*(self: Module, price: Stuint[256]): string =
self.controller.wei2Eth(price)
method sendSticker*(self: Module, channelId: string, replyTo: string, sticker: Item) =
let stickerDto = StickerDto(hash: sticker.getHash, packId: sticker.getPackId)
self.controller.sendSticker(
@ -216,9 +85,6 @@ method sendSticker*(self: Module, channelId: string, replyTo: string, sticker: I
stickerDto,
singletonInstance.userProfile.getPreferredName())
method estimate*(self: Module, packId: string, address: string, price: string, uuid: string) =
self.controller.estimate(packId, address, price, uuid)
method addRecentStickerToList*(self: Module, sticker: StickerDto) =
self.view.addRecentStickerToList(initItem(sticker.hash, sticker.packId, sticker.url))
@ -254,9 +120,6 @@ method populateInstalledStickerPacks*(self: Module, stickers: Table[string, Stic
))
self.view.populateInstalledStickerPacks(stickerPackItems)
method gasEstimateReturned*(self: Module, estimate: int, uuid: string) =
self.view.gasEstimateReturned(estimate, uuid)
method addStickerPackToList*(self: Module, stickerPack: StickerPackDto, isInstalled: bool, isBought: bool, isPending: bool) =
let stickerPackItem = initPackItem(
stickerPack.id,
@ -275,30 +138,18 @@ method getWalletDefaultAddress*(self: Module): string =
method getCurrentCurrency*(self: Module): string =
return self.controller.getCurrentCurrency()
method getGasEthValue*(self: Module, gweiValue: string, gasLimit: string): string {.slot.} =
var gasLimitInt:int
if(gasLimit.parseInt(gasLimitInt) == 0):
echo "an error occurred parsing gas limit, methodName=getGasEthValue"
return ""
# The following check prevents app crash, cause we're trying to promote
# gasLimitInt to unsigned 256 int, and this number must be a positive number,
# because of overflow.
var gwei = gweiValue.parseFloat()
if (gwei < 0):
gwei = 0
if (gasLimitInt < 0):
gasLimitInt = 0
let weiValue = service_conversion.gwei2Wei(gwei) * gasLimitInt.u256
let ethValue = service_conversion.wei2Eth(weiValue)
return fmt"{ethValue}"
method getStatusTokenKey*(self: Module): string =
return self.controller.getStatusTokenKey()
method stickerTransactionSent*(self: Module, chainId: int, packId: string, txHash: string, error: string) =
self.view.stickerPacks.updateStickerPackInList(packId, installed = false, pending = true)
self.view.transactionWasSent(chainId, txHash, error)
method stickerTransactionConfirmed*(self: Module, trxType: string, packID: string, transactionHash: string) =
self.view.stickerPacks.updateStickerPackInList(packID, installed = true, pending = false)
self.controller.installStickerPack(packID)
@ -306,13 +157,4 @@ method stickerTransactionConfirmed*(self: Module, trxType: string, packID: strin
method stickerTransactionReverted*(self: Module, trxType: string, packID: string, transactionHash: string) =
self.view.stickerPacks.updateStickerPackInList(packID, installed = false, pending = false)
self.view.emitTransactionCompletedSignal(false, transactionHash, packID, trxType)
method onTransactionSigned*(self: Module, keycardFlowType: string, keycardEvent: KeycardEvent) =
if keycardFlowType != keycard_constants.ResponseTypeValueKeycardFlowResult:
let errMsg = "unexpected error while keycard signing transaction"
error "error", msg=errMsg, methodName="onTransactionSigned"
self.finish(chainId = 0, txHash = "", error = errMsg)
return
let signature = "0x" & keycardEvent.txSignature.r & keycardEvent.txSignature.s & keycardEvent.txSignature.v
self.sendBuyingStickersTxWithSignatureAndWatch(signature)
self.view.emitTransactionCompletedSignal(false, transactionHash, packID, trxType)

View File

@ -58,14 +58,6 @@ QtObject:
proc transactionCompleted*(self: View, success: bool, txHash: string) {.signal.}
proc estimate*(self: View, packId: string, address: string, price: string, uuid: string) {.slot.} =
self.delegate.estimate(packId, address, price, uuid)
proc gasEstimateReturned*(self: View, estimate: int, uuid: string) {.signal.}
proc authenticateAndBuy*(self: View, packId: string, address: string, gas: string, gasPrice: string, maxPriorityFeePerGas: string, maxFeePerGas: string, eip1559Enabled: bool) {.slot.} =
self.delegate.authenticateAndBuy(packId, address, gas, gasPrice, maxPriorityFeePerGas, maxFeePerGas, eip1559Enabled)
proc stickerPacksLoaded*(self: View) {.signal.}
proc stickerPackInstalled*(self: View, packId: string) {.signal.}
@ -179,8 +171,6 @@ QtObject:
proc getCurrentCurrency*(self: View): string {.slot.} =
return self.delegate.getCurrentCurrency()
proc getGasEthValue*(self: View, gweiValue: string, gasLimit: string): string {.slot.} =
return self.delegate.getGasEthValue(gweiValue, gasLimit)
proc getStatusTokenKey*(self: View): string {.slot.} =
return self.delegate.getStatusTokenKey()

View File

@ -2,12 +2,6 @@ include ../../common/json_utils
include ../../../app/core/tasks/common
type
EstimateTaskArg = ref object of QObjectTaskArg
chainId*: int
packId*: string
fromAddress*: string
uuid*: string
ObtainMarketStickerPacksTaskArg = ref object of QObjectTaskArg
chainId*: int
InstallStickerPackTaskArg = ref object of QObjectTaskArg
@ -51,24 +45,6 @@ proc getMarketStickerPacks*(chainId: int):
error "Error in getMarketStickerPacks", message = getCurrentExceptionMsg()
result.error = getCurrentExceptionMsg()
# The pragmas `{.gcsafe, nimcall.}` in this context do not force the compiler
# to accept unsafe code, rather they work in conjunction with the proc
# signature for `type Task` in tasks/common.nim to ensure that the proc really
# is gcsafe and that a helpful error message is displayed
proc estimateTask(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[EstimateTaskArg](argEncoded)
var estimate = 325000
try:
let estimateResponse = status_stickers.buyEstimate(arg.chainId, parseAddress(arg.fromAddress), arg.packId)
estimate = estimateResponse.result.getInt + 1000
except ValueError:
# TODO: notify the UI that the trx is likely to fail
error "Error in buyPack estimate", message = getCurrentExceptionMsg()
except RpcException:
error "Error in buyPack estimate", message = getCurrentExceptionMsg()
let tpl: tuple[estimate: int, uuid: string] = (estimate, arg.uuid)
arg.finish(tpl)
proc obtainMarketStickerPacksTask(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[ObtainMarketStickerPacksTaskArg](argEncoded)
let (marketStickerPacks, error) = getMarketStickerPacks(arg.chainId)

View File

@ -26,7 +26,7 @@ type StickerPackDto* = object
stickers*: seq[StickerDto]
thumbnail*: string
status* : StickerPackStatus
txHash*: string
proc toStickerPackStatus*(value: int): StickerPackStatus =
result = StickerPackStatus.Unknown

View File

@ -10,7 +10,6 @@ import backend/chat as status_chat
import backend/response_type
import backend/eth as status_eth
import backend/backend as status_go_backend
import backend/wallet as status_wallet
import ./dto/stickers
import ../token/service as token_service
@ -20,7 +19,6 @@ import ../transaction/service as transaction_service
import ../network/service as network_service
import ../chat/service as chat_service
import app_service/common/types
import ../eth/utils as status_utils
export StickerDto
export StickerPackDto
@ -53,6 +51,7 @@ type
packs*: Table[string, StickerPackDto]
StickerBuyResultArgs* = ref object of Args
chainId*: int
packId*: string
txHash*: string
error*: string
@ -60,7 +59,7 @@ type
const SIGNAL_STICKER_PACK_LOADED* = "stickerPackLoaded"
const SIGNAL_ALL_STICKER_PACKS_LOADED* = "allStickerPacksLoaded"
const SIGNAL_ALL_STICKER_PACKS_LOAD_FAILED* = "allStickerPacksLoadFailed"
const SIGNAL_STICKER_GAS_ESTIMATED* = "stickerGasEstimated"
const SIGNAL_STICKER_TRANSACTION_SENT* = "stickerTransactionSent"
const SIGNAL_STICKER_TRANSACTION_CONFIRMED* = "stickerTransactionConfirmed"
const SIGNAL_STICKER_TRANSACTION_REVERTED* = "stickerTransactionReverted"
const SIGNAL_STICKER_PACK_INSTALLED* = "stickerPackInstalled"
@ -126,56 +125,46 @@ QtObject:
except RpcException:
error "Error obtaining sticker market address", message = getCurrentExceptionMsg()
proc confirmTransaction(self: Service, trxType: string, packID: string, transactionHash: string) =
try:
if not self.marketStickerPacks.contains(packID):
let pendingStickerPacksResponse = status_stickers.pending()
for (pID, stickerPackJson) in pendingStickerPacksResponse.result.pairs():
if packID != pID: continue
self.marketStickerPacks[packID] = stickerPackJson.toStickerPackDto()
self.marketStickerPacks[packID].status = StickerPackStatus.Purchased
self.events.emit(SIGNAL_STICKER_PACK_LOADED, StickerPackLoadedArgs(
stickerPack: self.marketStickerPacks[packID],
isInstalled: false,
isBought: true,
isPending: false
))
proc updateStickersPack(self: Service, transactionHash: string, status: string) =
if status == TxStatusPending:
return
discard status_stickers.removePending(packID)
self.marketStickerPacks[packID].status = StickerPackStatus.Purchased
let data = StickerTransactionArgs(transactionHash: transactionHash, packID: packID, transactionType: $trxType)
# find packID by transactionHash
var packId = ""
for pId, stickerPack in self.marketStickerPacks.pairs:
if stickerPack.txHash == transactionHash:
packId = pId
break
if packId.len == 0:
error "Error updating sticker pack status", message = "no packId found for transactionHash: " & transactionHash
return
if status == TxStatusSuccess:
self.marketStickerPacks[packId].status = StickerPackStatus.Purchased
let data = StickerTransactionArgs(transactionHash: transactionHash, packID: packId, transactionType: $PendingTransactionTypeDto.BuyStickerPack)
self.events.emit(SIGNAL_STICKER_TRANSACTION_CONFIRMED, data)
except:
error "Error confirming sticker transaction", message = getCurrentExceptionMsg()
proc revertTransaction(self: Service, trxType: string, packID: string, transactionHash: string) =
try:
if not self.marketStickerPacks.contains(packID):
let pendingStickerPacksResponse = status_stickers.pending()
for (pID, stickerPackJson) in pendingStickerPacksResponse.result.pairs():
if packID != pID: continue
self.marketStickerPacks[packID] = stickerPackJson.toStickerPackDto()
self.marketStickerPacks[packID].status = StickerPackStatus.Available
self.events.emit(SIGNAL_STICKER_PACK_LOADED, StickerPackLoadedArgs(
stickerPack: self.marketStickerPacks[packID],
isInstalled: false,
isBought: false,
isPending: false
))
discard status_stickers.removePending(packID)
self.marketStickerPacks[packID].status = StickerPackStatus.Available
let data = StickerTransactionArgs(transactionHash: transactionHash, packID: packID, transactionType: $trxType)
return
if status == TxStatusFailed:
self.marketStickerPacks[packId].status = StickerPackStatus.Available
let data = StickerTransactionArgs(transactionHash: transactionHash, packID: packId, transactionType: $PendingTransactionTypeDto.BuyStickerPack)
self.events.emit(SIGNAL_STICKER_TRANSACTION_REVERTED, data)
except:
error "Error reverting sticker transaction", message = getCurrentExceptionMsg()
return
error "Error updating sticker pack status", message = "unknown status: " & status
proc init*(self: Service) =
self.events.on(PendingTransactionTypeDto.BuyStickerPack.event) do(e: Args):
var receivedData = TransactionMinedArgs(e)
if receivedData.success:
self.confirmTransaction($PendingTransactionTypeDto.BuyStickerPack, receivedData.data, receivedData.transactionHash)
else:
self.revertTransaction($PendingTransactionTypeDto.BuyStickerPack, receivedData.data, receivedData.transactionHash)
self.events.on(SIGNAL_TRANSACTION_SENT) do(e:Args):
let args = TransactionSentArgs(e)
if args.txType != SendType.StickersBuy:
return
self.marketStickerPacks[$args.packId].status = StickerPackStatus.Pending
self.marketStickerPacks[$args.packId].txHash = args.txHash
let data = StickerBuyResultArgs(chainId: args.chainId, packId: args.packId, txHash: args.txHash, error: args.error)
self.events.emit(SIGNAL_STICKER_TRANSACTION_SENT, data)
self.events.on(SIGNAL_TRANSACTION_STATUS_CHANGED) do(e:Args):
let args = TransactionStatusArgs(e)
self.updateStickersPack(args.data.hash, args.data.status)
proc setMarketStickerPacks*(self: Service, strickersJSON: string) {.slot.} =
let stickersResult = Json.decode(strickersJSON, tuple[packs: seq[StickerPackDto], error: string])
@ -187,7 +176,8 @@ QtObject:
let availableStickers = stickersResult.packs
for stickerPack in availableStickers:
if self.marketStickerPacks.contains(stickerPack.id): continue
if self.marketStickerPacks.contains(stickerPack.id):
continue
self.marketStickerPacks[stickerPack.id] = stickerPack
self.events.emit(SIGNAL_STICKER_PACK_LOADED, StickerPackLoadedArgs(
@ -198,11 +188,12 @@ QtObject:
))
let pendingStickerPacksResponse = status_stickers.pending()
for (packID, stickerPackJson) in pendingStickerPacksResponse.result.pairs():
if self.marketStickerPacks.contains(packID): continue
self.marketStickerPacks[packID] = stickerPackJson.toStickerPackDto()
for (packId, stickerPackJson) in pendingStickerPacksResponse.result.pairs():
if self.marketStickerPacks.contains(packId):
continue
self.marketStickerPacks[packId] = stickerPackJson.toStickerPackDto()
self.events.emit(SIGNAL_STICKER_PACK_LOADED, StickerPackLoadedArgs(
stickerPack: self.marketStickerPacks[packID],
stickerPack: self.marketStickerPacks[packId],
isInstalled: false,
isBought: false,
isPending: true
@ -220,27 +211,6 @@ QtObject:
)
self.threadpool.start(arg)
proc setGasEstimate*(self: Service, estimateJson: string) {.slot.} =
let estimateResult = Json.decode(estimateJson, tuple[estimate: int, uuid: string])
self.events.emit(SIGNAL_STICKER_GAS_ESTIMATED, StickerGasEstimatedArgs(estimate: estimateResult.estimate, uuid: estimateResult.uuid))
# the [T] here is annoying but the QtObject template only allows for one type
# definition so we'll need to setup the type, task, and helper outside of body
# passed to `QtObject:`
proc estimate*(self: Service, packId: string, address: string, price: string, uuid: string) =
let chainId = self.networkService.getAppNetwork().chainId
let arg = EstimateTaskArg(
tptr: estimateTask,
vptr: cast[ByteAddress](self.vptr),
slot: "setGasEstimate",
packId: packId,
uuid: uuid,
chainId: chainId,
fromAddress: address
)
self.threadpool.start(arg)
proc addStickerToRecent*(self: Service, sticker: StickerDto, save: bool = false) =
try:
discard status_stickers.addRecent(sticker.packId, sticker.hash)
@ -385,98 +355,4 @@ QtObject:
try:
discard status_stickers.clearRecentStickers()
except RpcException:
error "Error removing recent stickers", message = getCurrentExceptionMsg()
# proc prepareTxForBuyingStickers*(self: Service, chainId: int, packId: string, address: string): JsonNode =
proc prepareTxForBuyingStickers*(self: Service, chainId: int, packId: string, address: string, gas: string, gasPrice: string, maxPriorityFeePerGas: string,
maxFeePerGas: string, eip1559Enabled: bool): JsonNode =
try:
var prepareTxResponse = status_stickers.prepareTxForBuyingStickers(chainId, address, packId)
if not prepareTxResponse.error.isNil:
error "error occurred", procName="prepareTxForBuyingStickers", msg = prepareTxResponse.error.message
return
prepareTxResponse.result["gas"] = %* (if gas.isEmptyOrWhitespace: Quantity.none else: Quantity(cast[uint64](parseFloat(gas).toUInt64)).some)
if eip1559Enabled:
let maxPriorityFeePerGasFinal = if maxPriorityFeePerGas.isEmptyOrWhitespace: Uint256.none else: gwei2Wei(parseFloat(maxPriorityFeePerGas)).some
let maxFeePerGasFinal = if maxFeePerGas.isEmptyOrWhitespace: Uint256.none else: gwei2Wei(parseFloat(maxFeePerGas)).some
prepareTxResponse.result["maxPriorityFeePerGas"] = %* ("0x" & maxPriorityFeePerGasFinal.unsafeGet.toHex)
prepareTxResponse.result["maxFeePerGas"] = %* ("0x" & maxFeePerGasFinal.unsafeGet.toHex)
else:
let gasPriceFinal = if gasPrice.isEmptyOrWhitespace: int.none else: gwei2Wei(parseFloat(gasPrice)).truncate(int).some
prepareTxResponse.result["gasPrice"] = %* ("0x" & gasPriceFinal.unsafeGet.toHex.stripLeadingZeros)
var buildTxResponse: JsonNode
let err = status_wallet.buildTransaction(buildTxResponse, chainId, $prepareTxResponse.result)
if err.len > 0:
error "error occurred", procName="prepareTxForBuyingStickers", msg = err
return
return buildTxResponse
except Exception as e:
error "error occurred", procName="prepareTxForBuyingStickers", msg = e.msg
proc signBuyingStickersTxLocally*(self: Service, data, account, hashedPasssword: string): string =
try:
var response: JsonNode
let err = status_wallet.signMessage(response, data, account, hashedPasssword)
if err.len > 0 or response.isNil:
error "error occurred", procName="signBuyingStickersTxLocally", msg = err
return
return response.getStr()
except Exception as e:
error "error occurred", procName="signBuyingStickersTxLocally", msg = e.msg
proc sendBuyingStickersTxWithSignatureAndWatch*(self: Service, chainId: int, txData: JsonNode, packId: string,
signature: string): StickerBuyResultArgs =
result = StickerBuyResultArgs(chainId: chainId)
try:
if txData.isNil:
result.error = "txData is nil"
error "error occurred", procName="sendBuyingStickersTxWithSignatureAndWatch", msg = result.error
return
if not txData.hasKey("from") or txData["from"].getStr().len == 0:
result.error = "from address is empty"
error "error occurred", procName="sendBuyingStickersTxWithSignatureAndWatch", msg = result.error
return
if not txData.hasKey("to") or txData["to"].getStr().len == 0:
result.error = "to address is empty"
error "error occurred", procName="sendBuyingStickersTxWithSignatureAndWatch", msg = result.error
return
var finalSignature = signature
if finalSignature.startsWith("0x"):
finalSignature = finalSignature[2..^1]
var txResponse: JsonNode
let err = status_wallet.sendTransactionWithSignature(txResponse, chainId, $PendingTransactionTypeDto.BuyStickerPack,
$txData, finalSignature)
if err.len > 0 or txResponse.isNil:
result.error = err
error "error occurred", procName="sendBuyingStickersTxWithSignatureAndWatch", msg = result.error
return
let
transactionHash = txResponse.getStr()
fromAddress = txData["from"].getStr()
toAddress = txData["to"].getStr()
let addPendingResponse = status_stickers.addPending(chainId, packId)
if not addPendingResponse.error.isNil:
result.error = addPendingResponse.error.message
error "error occurred", procName="sendBuyingStickersTxWithSignatureAndWatch", msg = result.error
return
self.transactionService.watchTransaction(
transactionHash,
fromAddress,
toAddress,
$PendingTransactionTypeDto.BuyStickerPack,
packId,
chainId,
)
result.txHash = transactionHash
except Exception as e:
result.error = e.msg
error "error occurred", procName="sendBuyingStickersTxWithSignatureAndWatch", msg = result.error
error "Error removing recent stickers", message = getCurrentExceptionMsg()

View File

@ -98,7 +98,6 @@ proc toSendDetailsDto*(jsonObj: JsonNode): SendDetailsDto =
let packId = stint.fromHex(UInt256, tmpObj.getStr)
result.packId = $packId
proc toSigningDetails*(jsonObj: JsonNode): SigningDetails =
result = SigningDetails()
discard jsonObj.getProp("address", result.address)

View File

@ -1,7 +1,6 @@
import json
import ./eth
import ./core, ./response_type
import web3/[ethtypes, conversions]
proc market*(chainId: int): RpcResponse[JsonNode] =
let payload = %* [chainId]
@ -11,9 +10,6 @@ proc pending*(): RpcResponse[JsonNode] =
let payload = %* []
return core.callPrivateRPC("stickers_pending", payload)
proc addPending*(chainId: int, packId: string): RpcResponse[JsonNode] =
let payload = %* [chainId, packId]
result = core.callPrivateRPC("stickers_addPending", payload)
proc installed*(): RpcResponse[JsonNode] =
let payload = %* []
@ -39,22 +35,10 @@ proc stickerMarketAddress*(chainId: int): RpcResponse[JsonNode] =
let payload = %* [chainId]
return core.callPrivateRPC("stickers_stickerMarketAddress", payload)
proc buyEstimate*(chainId: int, fromAccount: Address, packId: string): RpcResponse[JsonNode] =
let payload = %* [chainId, $fromAccount, packId]
return core.callPrivateRPC("stickers_buyEstimate", payload)
proc buy*(chainId: int, txData: JsonNode, packId: string, hashedPassword: string): RpcResponse[JsonNode] =
let payload = %* [chainId, txData, packID, hashedPassword]
return core.callPrivateRPC("stickers_buy", payload)
proc clearRecentStickers*(): RpcResponse[JsonNode] =
let payload = %* []
return core.callPrivateRPC("stickers_clearRecent", payload)
proc removePending*(packId: string): RpcResponse[JsonNode] =
let payload = %* [packId]
return core.callPrivateRPC("stickers_removePending", payload)
proc prepareTxForBuyingStickers*(chainId: int, address: string, packId: string): RpcResponse[JsonNode] =
let payload = %* [chainId, address, packId]
result = core.callPrivateRPC("stickers_buyPrepareTx", payload)
return core.callPrivateRPC("stickers_removePending", payload)

View File

@ -30,28 +30,11 @@ QtObject {
return stickersModule.getCurrentCurrency()
}
function getGasEthValue(gweiValue, gasLimit) {
if(!root.stickersModule)
return ""
return stickersModule.getGasEthValue(gweiValue, gasLimit)
}
function getStatusTokenKey() {
if(!root.stickersModule)
return ""
return stickersModule.getStatusTokenKey()
}
function estimate(packId, selectedAccount, price, uuid) {
if(!root.stickersModule)
return 0
return stickersModule.estimate(packId, selectedAccount, price, uuid)
}
function authenticateAndBuy(packId, address, price, gasLimit, gasPrice, tipLimit, overallLimit, eip1559Enabled) {
if(!root.stickersModule)
return ""
return stickersModule.authenticateAndBuy(packId, address, price, gasLimit, gasPrice, tipLimit, overallLimit, eip1559Enabled)
}
}

View File

@ -215,20 +215,7 @@ Item {
return !!token && !!token.symbol ? token.symbol : ""
}
preSelectedHoldingType: Constants.TokenType.ERC20
sendTransaction: function() {
if(bestRoutes.count === 1) {
let path = bestRoutes.firstItem()
let eip1559Enabled = path.gasFees.eip1559Enabled
let maxFeePerGas = path.gasFees.maxFeePerGasM
root.store.stickersStore.authenticateAndBuy(packId,
store.selectedSenderAccountAddress,
path.gasAmount,
eip1559Enabled ? "" : path.gasFees.gasPrice,
eip1559Enabled ? path.gasFees.maxPriorityFeePerGas : "",
eip1559Enabled ? maxFeePerGas : path.gasFees.gasPrice,
eip1559Enabled)
}
}
Connections {
target: root.store.stickersStore.stickersModule
function onTransactionWasSent(chainId: int, txHash: string, error: string) {

View File

@ -86,20 +86,7 @@ ModalPopup {
return !!token && !!token.symbol ? token.symbol : ""
}
preSelectedHoldingType: Constants.TokenType.ERC20
sendTransaction: function() {
if(bestRoutes.count === 1) {
let path = bestRoutes.firstItem()
let eip1559Enabled = path.gasFees.eip1559Enabled
let maxFeePerGas = path.gasFees.maxFeePerGasM
stickerPackDetailsPopup.store.stickersStore.authenticateAndBuy(packId,
store.selectedSenderAccountAddress,
path.gasAmount,
eip1559Enabled ? "" : path.gasFees.gasPrice,
eip1559Enabled ? path.gasFees.maxPriorityFeePerGas : "",
eip1559Enabled ? maxFeePerGas : path.gasFees.gasPrice,
eip1559Enabled)
}
}
Connections {
target: stickerPackDetailsPopup.store.stickersStore.stickersModule
function onTransactionWasSent(chainId: int, txHash: string, error: string) {