feat(@desktop/communities): Add self-destruct tokens functionality

Issue #10052
This commit is contained in:
Michal Iskierko 2023-05-05 13:03:59 +02:00 committed by Michał Iskierko
parent c40472c285
commit 4c29343a4a
19 changed files with 417 additions and 106 deletions

View File

@ -43,14 +43,20 @@ proc init*(self: Controller) =
return
self.communityTokensModule.onUserAuthenticated(args.password)
self.events.on(SIGNAL_COMPUTE_DEPLOY_FEE) do(e:Args):
let args = ComputeDeployFeeArgs(e)
let args = ComputeFeeArgs(e)
self.communityTokensModule.onDeployFeeComputed(args.ethCurrency, args.fiatCurrency, args.errorCode)
self.events.on(SIGNAL_COMPUTE_SELF_DESTRUCT_FEE) do(e:Args):
let args = ComputeFeeArgs(e)
self.communityTokensModule.onSelfDestructFeeComputed(args.ethCurrency, args.fiatCurrency, args.errorCode)
self.events.on(SIGNAL_COMMUNITY_TOKEN_DEPLOYED) do(e: Args):
let args = CommunityTokenDeployedArgs(e)
self.communityTokensModule.onCommunityTokenDeployStateChanged(args.communityToken.communityId, args.communityToken.chainId, args.transactionHash, args.communityToken.deployState)
self.events.on(SIGNAL_COMMUNITY_TOKEN_DEPLOY_STATUS) do(e: Args):
let args = CommunityTokenDeployedStatusArgs(e)
self.communityTokensModule.onCommunityTokenDeployStateChanged(args.communityId, args.chainId, args.transactionHash, args.deployState)
self.events.on(SIGNAL_REMOTE_DESTRUCT_STATUS) do(e: Args):
let args = RemoteDestructArgs(e)
self.communityTokensModule.onRemoteDestructStateChanged(args.communityToken.communityId, args.communityToken.name, args.communityToken.chainId, args.transactionHash, args.status)
proc deployCollectibles*(self: Controller, communityId: string, addressFrom: string, password: string, deploymentParams: DeploymentParameters, tokenMetadata: CommunityTokensMetadataDto, chainId: int) =
self.communityTokensService.deployCollectibles(communityId, addressFrom, password, deploymentParams, tokenMetadata, chainId)
@ -58,6 +64,9 @@ proc deployCollectibles*(self: Controller, communityId: string, addressFrom: str
proc airdropCollectibles*(self: Controller, communityId: string, password: string, collectiblesAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) =
self.communityTokensService.airdropCollectibles(communityId, password, collectiblesAndAmounts, walletAddresses)
proc selfDestructCollectibles*(self: Controller, communityId: string, password: string, walletAndAmounts: seq[WalletAndAmount], contractUniqueKey: string) =
self.communityTokensService.selfDestructCollectibles(communityId, password, walletAndAmounts, contractUniqueKey)
proc authenticateUser*(self: Controller, keyUid = "") =
let data = SharedKeycarModuleAuthenticationArgs(uniqueIdentifier: UNIQUE_DEPLOY_COLLECTIBLES_COMMUNITY_TOKENS_MODULE_IDENTIFIER, keyUid: keyUid)
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_AUTHENTICATE_USER, data)
@ -68,6 +77,9 @@ proc getCommunityTokens*(self: Controller, communityId: string): seq[CommunityTo
proc computeDeployFee*(self: Controller, chainId: int, accountAddress: string) =
self.communityTokensService.computeDeployFee(chainId, accountAddress)
proc computeSelfDestructFee*(self: Controller, walletAndAmountList: seq[WalletAndAmount], contractUniqueKey: string) =
self.communityTokensService.computeSelfDestructFee(walletAndAmountList, contractUniqueKey)
proc getCommunityTokenBySymbol*(self: Controller, communityId: string, symbol: string): CommunityTokenDto =
return self.communityTokensService.getCommunityTokenBySymbol(communityId, symbol)

View File

@ -13,6 +13,9 @@ method load*(self: AccessInterface) {.base.} =
method airdropCollectibles*(self: AccessInterface, communityId: string, collectiblesJsonString: string, walletsJsonString: string) {.base.} =
raise newException(ValueError, "No implementation available")
method selfDestructCollectibles*(self: AccessInterface, communityId: string, collectiblesToBurnJsonString: string, contractUniqueKey: string) {.base.} =
raise newException(ValueError, "No implementation available")
method deployCollectible*(self: AccessInterface, communityId: string, address: string, name: string, symbol: string, description: string, supply: int, infiniteSupply: bool, transferable: bool,
selfDestruct: bool, chainId: int, image: string) {.base.} =
raise newException(ValueError, "No implementation available")
@ -26,8 +29,17 @@ method resetTempValues*(self: AccessInterface) {.base.} =
method computeDeployFee*(self: AccessInterface, chainId: int, accountAddress: string) {.base.} =
raise newException(ValueError, "No implementation available")
method computeSelfDestructFee*(self: AccessInterface, collectiblesToBurnJsonString: string, contractUniqueKey: string) {.base.} =
raise newException(ValueError, "No implementation available")
method onDeployFeeComputed*(self: AccessInterface, ethCurrency: CurrencyAmount, fiatCurrency: CurrencyAmount, errorCode: ComputeFeeErrorCode) {.base.} =
raise newException(ValueError, "No implementation available")
method onSelfDestructFeeComputed*(self: AccessInterface, ethCurrency: CurrencyAmount, fiatCurrency: CurrencyAmount, errorCode: ComputeFeeErrorCode) {.base.} =
raise newException(ValueError, "No implementation available")
method onCommunityTokenDeployStateChanged*(self: AccessInterface, communityId: string, chainId: int, transactionHash: string, deployState: DeployState) {.base.} =
raise newException(ValueError, "No implementation available")
method onRemoteDestructStateChanged*(self: AccessInterface, communityId: string, tokenName: string, chainId: int, transactionHash: string, status: ContractTransactionStatus) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -13,17 +13,20 @@ type
tokenDto*: CommunityTokenDto
chainName*: string
chainIcon*: string
accountName*: string
tokenOwnersModel*: token_owners_model.TokenOwnersModel
proc initTokenItem*(
tokenDto: CommunityTokenDto,
network: NetworkDto,
tokenOwners: seq[CollectibleOwner]
tokenOwners: seq[CollectibleOwner],
accountName: string
): TokenItem =
result.tokenDto = tokenDto
if network != nil:
result.chainName = network.chainName
result.chainIcon = network.iconURL
result.accountName = accountName
result.tokenOwnersModel = newTokenOwnersModel()
result.tokenOwnersModel.setItems(tokenOwners.map(proc(owner: CollectibleOwner): TokenOwnersItem =
# TODO find member with the address - later when airdrop to member will be added

View File

@ -4,10 +4,12 @@ import token_owners_item
import token_owners_model
import ../../../../../../app_service/service/community_tokens/dto/community_token
import ../../../../../../app_service/service/collectible/dto
import ../../../../../../app_service/common/utils
type
ModelRole {.pure.} = enum
TokenType = UserRole + 1
ContractUniqueKey = UserRole + 1
TokenType
TokenAddress
Name
Symbol
@ -22,6 +24,7 @@ type
ChainName
ChainIcon
TokenOwnersModel
AccountName
QtObject:
type TokenModel* = ref object of QAbstractListModel
@ -43,6 +46,7 @@ QtObject:
if((self.items[i].tokenDto.address == contractAddress) and (self.items[i].tokenDto.chainId == chainId)):
self.items[i].tokenDto.deployState = deployState
let index = self.createIndex(i, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[ModelRole.DeployState.int])
return
@ -87,6 +91,7 @@ QtObject:
method roleNames(self: TokenModel): Table[int, string] =
{
ModelRole.ContractUniqueKey.int:"contractUniqueKey",
ModelRole.TokenType.int:"tokenType",
ModelRole.TokenAddress.int:"tokenAddress",
ModelRole.Name.int:"name",
@ -102,6 +107,7 @@ QtObject:
ModelRole.ChainName.int:"chainName",
ModelRole.ChainIcon.int:"chainIcon",
ModelRole.TokenOwnersModel.int:"tokenOwnersModel",
ModelRole.AccountName.int:"accountName",
}.toTable
method data(self: TokenModel, index: QModelIndex, role: int): QVariant =
@ -112,6 +118,8 @@ QtObject:
let item = self.items[index.row]
let enumRole = role.ModelRole
case enumRole:
of ModelRole.ContractUniqueKey:
result = newQVariant(contractUniqueKey(item.tokenDto.chainId, item.tokenDto.address))
of ModelRole.TokenType:
result = newQVariant(item.tokenDto.tokenType.int)
of ModelRole.TokenAddress:
@ -142,6 +150,8 @@ QtObject:
result = newQVariant(item.chainIcon)
of ModelRole.TokenOwnersModel:
result = newQVariant(item.tokenOwnersModel)
of ModelRole.AccountName:
result = newQVariant(item.accountName)
proc `$`*(self: TokenModel): string =
for i in 0 ..< self.items.len:

View File

@ -18,6 +18,7 @@ type
Unknown = 0
Deploy = 1
Airdrop = 2
SelfDestruct = 3
type
Module* = ref object of io_interface.AccessInterface
@ -26,6 +27,7 @@ type
view: View
viewVariant: QVariant
tempTokenAndAmountList: seq[CommunityTokenAndAmount]
tempWalletAndAmountList: seq[WalletAndAmount]
tempAddressFrom: string
tempCommunityId: string
tempChainId: int
@ -34,6 +36,7 @@ type
tempTokenMetadata: CommunityTokensMetadataDto
tempWalletAddresses: seq[string]
tempContractAction: ContractAction
tempContractUniqueKey: string
proc newCommunityTokensModule*(
parent: parent_interface.AccessInterface,
@ -62,6 +65,8 @@ method resetTempValues(self:Module) =
self.tempWalletAddresses = @[]
self.tempContractAction = ContractAction.Unknown
self.tempTokenAndAmountList = @[]
self.tempWalletAndAmountList = @[]
self.tempContractUniqueKey = ""
method load*(self: Module) =
singletonInstance.engine.setRootContextProperty("communityTokensModule", self.viewVariant)
@ -92,6 +97,20 @@ method airdropCollectibles*(self: Module, communityId: string, collectiblesJsonS
self.tempContractAction = ContractAction.Airdrop
self.authenticate()
proc getWalletAndAmountListFromJson(self: Module, collectiblesToBurnJsonString: string): seq[WalletAndAmount] =
let collectiblesToBurnJson = collectiblesToBurnJsonString.parseJson
for collectibleToBurn in collectiblesToBurnJson:
let walletAddress = collectibleToBurn["walletAddress"].getStr
let amount = collectibleToBurn["amount"].getInt
result.add(WalletAndAmount(walletAddress: walletAddress, amount: amount))
method selfDestructCollectibles*(self: Module, communityId: string, collectiblesToBurnJsonString: string, contractUniqueKey: string) =
self.tempWalletAndAmountList = self.getWalletAndAmountListFromJson(collectiblesToBurnJsonString)
self.tempCommunityId = communityId
self.tempContractUniqueKey = contractUniqueKey
self.tempContractAction = ContractAction.SelfDestruct
self.authenticate()
method deployCollectible*(self: Module, communityId: string, fromAddress: string, name: string, symbol: string, description: string,
supply: int, infiniteSupply: bool, transferable: bool, selfDestruct: bool, chainId: int, image: string) =
self.tempAddressFrom = fromAddress
@ -119,14 +138,28 @@ method onUserAuthenticated*(self: Module, password: string) =
self.controller.deployCollectibles(self.tempCommunityId, self.tempAddressFrom, password, self.tempDeploymentParams, self.tempTokenMetadata, self.tempChainId)
elif self.tempContractAction == ContractAction.Airdrop:
self.controller.airdropCollectibles(self.tempCommunityId, password, self.tempTokenAndAmountList, self.tempWalletAddresses)
elif self.tempContractAction == ContractAction.SelfDestruct:
self.controller.selfDestructCollectibles(self.tempCommunityId, password, self.tempWalletAndAmountList, self.tempContractUniqueKey)
method onDeployFeeComputed*(self: Module, ethCurrency: CurrencyAmount, fiatCurrency: CurrencyAmount, errorCode: ComputeFeeErrorCode) =
self.view.updateDeployFee(ethCurrency, fiatCurrency, errorCode.int)
method onSelfDestructFeeComputed*(self: Module, ethCurrency: CurrencyAmount, fiatCurrency: CurrencyAmount, errorCode: ComputeFeeErrorCode) =
self.view.updateSelfDestructFee(ethCurrency, fiatCurrency, errorCode.int)
method computeDeployFee*(self: Module, chainId: int, accountAddress: string) =
self.controller.computeDeployFee(chainId, accountAddress)
method computeSelfDestructFee*(self: Module, collectiblesToBurnJsonString: string, contractUniqueKey: string) =
let walletAndAmountList = self.getWalletAndAmountListFromJson(collectiblesToBurnJsonString)
self.controller.computeSelfDestructFee(walletAndAmountList, contractUniqueKey)
method onCommunityTokenDeployStateChanged*(self: Module, communityId: string, chainId: int, transactionHash: string, deployState: DeployState) =
let network = self.controller.getNetwork(chainId)
let url = if network != nil: network.blockExplorerURL & "/tx/" & transactionHash else: ""
self.view.emitDeploymentStateChanged(communityId, deployState.int, url)
self.view.emitDeploymentStateChanged(communityId, deployState.int, url)
method onRemoteDestructStateChanged*(self: Module, communityId: string, tokenName: string, chainId: int, transactionHash: string, status: ContractTransactionStatus) =
let network = self.controller.getNetwork(chainId)
let url = if network != nil: network.blockExplorerURL & "/tx/" & transactionHash else: ""
self.view.emitRemoteDestructStateChanged(communityId, tokenName, status.int, url)

View File

@ -25,14 +25,28 @@ QtObject:
proc airdropCollectibles*(self: View, communityId: string, collectiblesJsonString: string, walletsJsonString: string) {.slot.} =
self.communityTokensModule.airdropCollectibles(communityId, collectiblesJsonString, walletsJsonString)
proc selfDestructCollectibles*(self: View, communityId: string, collectiblesToBurnJsonString: string, contractUniqueKey: string) {.slot.} =
self.communityTokensModule.selfDestructCollectibles(communityId, collectiblesToBurnJsonString, contractUniqueKey)
proc deployFeeUpdated*(self: View, ethCurrency: QVariant, fiatCurrency: QVariant, errorCode: int) {.signal.}
proc selfDestructFeeUpdated*(self: View, ethCurrency: QVariant, fiatCurrency: QVariant, errorCode: int) {.signal.}
proc computeDeployFee*(self: View, chainId: int, accountAddress: string) {.slot.} =
self.communityTokensModule.computeDeployFee(chainId, accountAddress)
proc computeSelfDestructFee*(self: View, collectiblesToBurnJsonString: string, contractUniqueKey: string) {.slot.} =
self.communityTokensModule.computeSelfDestructFee(collectiblesToBurnJsonString, contractUniqueKey)
proc updateDeployFee*(self: View, ethCurrency: CurrencyAmount, fiatCurrency: CurrencyAmount, errorCode: int) =
self.deployFeeUpdated(newQVariant(ethCurrency), newQVariant(fiatCurrency), errorCode)
proc updateSelfDestructFee*(self: View, ethCurrency: CurrencyAmount, fiatCurrency: CurrencyAmount, errorCode: int) =
self.selfDestructFeeUpdated(newQVariant(ethCurrency), newQVariant(fiatCurrency), errorCode)
proc deploymentStateChanged*(self: View, communityId: string, status: int, url: string) {.signal.}
proc emitDeploymentStateChanged*(self: View, communityId: string, status: int, url: string) =
self.deploymentStateChanged(communityId, status, url)
self.deploymentStateChanged(communityId, status, url)
proc remoteDestructStateChanged*(self: View, communityId: string, tokenName: string, status: int, url: string) {.signal.}
proc emitRemoteDestructStateChanged*(self: View, communityId: string, tokenName: string, status: int, url: string) =
self.remoteDestructStateChanged(communityId, tokenName, status, url)

View File

@ -474,5 +474,8 @@ proc getCommunityTokens*(self: Controller, communityId: string): seq[CommunityTo
proc getCommunityTokenOwners*(self: Controller, communityId: string, chainId: int, contractAddress: string): seq[CollectibleOwner] =
return self.communityTokensService.getCommunityTokenOwners(communityId, chainId, contractAddress)
proc getCommunityTokenOwnerName*(self: Controller, chainId: int, contractAddress: string): string =
return self.communityTokensService.contractOwnerName(chainId, contractAddress)
proc getNetwork*(self:Controller, chainId: int): NetworkDto =
self.networksService.getNetwork(chainId)

View File

@ -236,7 +236,8 @@ method delete*[T](self: Module[T]) =
proc createTokenItem[T](self: Module[T], tokenDto: CommunityTokenDto) : TokenItem =
let network = self.controller.getNetwork(tokenDto.chainId)
let tokenOwners = self.controller.getCommunityTokenOwners(tokenDto.communityId, tokenDto.chainId, tokenDto.address)
result = initTokenItem(tokenDto, network, tokenOwners)
let ownerAddressName = self.controller.getCommunityTokenOwnerName(tokenDto.chainId, tokenDto.address)
result = initTokenItem(tokenDto, network, tokenOwners, ownerAddressName)
proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto): SectionItem =
let isCommunity = channelGroup.channelGroupType == ChannelGroupType.Community

View File

@ -80,4 +80,7 @@ proc isPathOutOfTheDefaultStatusDerivationTree*(path: string): bool =
path.count("'") != 3 or
path.count("/") != 5:
return true
return false
return false
proc contractUniqueKey*(chainId: int, contractAddress: string): string =
return $chainId & "_" & contractAddress

View File

@ -1,5 +1,7 @@
import stint
include ../../common/json_utils
import ../../../backend/eth
import ../../../backend/community_tokens
import ../../../backend/collectibles
import ../../../app/core/tasks/common
import ../../../app/core/tasks/qt
@ -22,6 +24,26 @@ const asyncGetSuggestedFeesTask: Task = proc(argEncoded: string) {.gcsafe, nimca
"error": e.msg,
})
type
AsyncGetBurnFees = ref object of QObjectTaskArg
chainId: int
contractAddress: string
tokenIds: seq[UInt256]
const asyncGetBurnFeesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[AsyncGetBurnFees](argEncoded)
try:
let feesResponse = eth.suggestedFees(arg.chainId).result
let burnGas = community_tokens.estimateRemoteBurn(arg.chainId, arg.contractAddress, arg.tokenIds).result.getInt
arg.finish(%* {
"fees": feesResponse.toSuggestedFeesDto(),
"burnGas": burnGas,
"error": "" })
except Exception as e:
arg.finish(%* {
"error": e.msg,
})
type
FetchCollectibleOwnersArg = ref object of QObjectTaskArg
chainId*: int

View File

@ -1,4 +1,4 @@
import NimQml, Tables, chronicles, json, stint, strutils
import NimQml, Tables, chronicles, json, stint, strutils, sugar, sequtils
import ../../../app/core/eventemitter
import ../../../app/core/tasks/[qt, threadpool]
import ../../../app/modules/shared_models/currency_amount
@ -15,6 +15,8 @@ import ../collectible/dto as collectibles_dto
import ../../../backend/response_type
import ../../common/conversion
import ../../common/account_constants
import ../../common/utils as common_utils
import ../community/dto/community
import ./dto/deployment_parameters
@ -37,6 +39,11 @@ type
communityToken*: CommunityTokenDto
amount*: int
type
WalletAndAmount* = object
walletAddress*: string
amount*: int
type
CommunityTokenDeployedStatusArgs* = ref object of Args
communityId*: string
@ -50,6 +57,18 @@ type
communityToken*: CommunityTokenDto
transactionHash*: string
type
ContractTransactionStatus* {.pure.} = enum
Failed,
InProgress,
Completed
type
RemoteDestructArgs* = ref object of Args
communityToken*: CommunityTokenDto
transactionHash*: string
status*: ContractTransactionStatus
type
ComputeFeeErrorCode* {.pure.} = enum
Success,
@ -58,7 +77,7 @@ type
Other
type
ComputeDeployFeeArgs* = ref object of Args
ComputeFeeArgs* = ref object of Args
ethCurrency*: CurrencyAmount
fiatCurrency*: CurrencyAmount
errorCode*: ComputeFeeErrorCode
@ -79,7 +98,9 @@ type
const SIGNAL_COMMUNITY_TOKEN_DEPLOY_STATUS* = "communityTokenDeployStatus"
const SIGNAL_COMMUNITY_TOKEN_DEPLOYED* = "communityTokenDeployed"
const SIGNAL_COMPUTE_DEPLOY_FEE* = "computeDeployFee"
const SIGNAL_COMPUTE_SELF_DESTRUCT_FEE* = "computeSelfDestructFee"
const SIGNAL_COMMUNITY_TOKEN_OWNERS_FETCHED* = "communityTokenOwnersFetched"
const SIGNAL_REMOTE_DESTRUCT_STATUS* = "communityTokenRemoteDestructStatus"
QtObject:
type
@ -92,15 +113,20 @@ QtObject:
walletAccountService: wallet_account_service.Service
tempAccountAddress: string
tempChainId: int
addressAndTxMap: Table[ContractTuple, string]
tokenOwnersTimer: QTimer
tokenOwners1SecTimer: QTimer # used to update 1 sec after changes in owners
tempTokenOwnersToFetch: CommunityTokenDto # used by 1sec timer
tokenOwnersCache: Table[ContractTuple, seq[CollectibleOwner]]
tempSuggestedFees: SuggestedFeesDto
tempGasUnits: int
# Forward declaration
proc fetchAllTokenOwners*(self: Service)
proc getCommunityTokenOwners*(self: Service, communityId: string, chainId: int, contractAddress: string): seq[CollectibleOwner]
proc delete*(self: Service) =
delete(self.tokenOwnersTimer)
delete(self.tokenOwners1SecTimer)
self.QObject.delete
proc newService*(
@ -119,10 +145,13 @@ QtObject:
result.tokenService = tokenService
result.settingsService = settingsService
result.walletAccountService = walletAccountService
result.addressAndTxMap = initTable[ContractTuple, string]()
result.tokenOwnersTimer = newQTimer()
result.tokenOwnersTimer.setInterval(10*60*1000)
signalConnect(result.tokenOwnersTimer, "timeout()", result, "onRefreshTransferableTokenOwners()", 2)
result.tokenOwners1SecTimer = newQTimer()
result.tokenOwners1SecTimer.setInterval(1000)
result.tokenOwners1SecTimer.setSingleShot(true)
signalConnect(result.tokenOwners1SecTimer, "timeout()", result, "onFetchTempTokenOwners()", 2)
proc init*(self: Service) =
self.fetchAllTokenOwners()
@ -139,21 +168,27 @@ QtObject:
error "Error updating collectibles contract state", message = getCurrentExceptionMsg()
let data = CommunityTokenDeployedStatusArgs(communityId: tokenDto.communityId, contractAddress: tokenDto.address,
deployState: deployState, chainId: tokenDto.chainId,
transactionHash: self.addressAndTxMap.getOrDefault((tokenDto.address,tokenDto.chainId)))
transactionHash: receivedData.transactionHash)
self.events.emit(SIGNAL_COMMUNITY_TOKEN_DEPLOY_STATUS, data)
self.events.on(PendingTransactionTypeDto.CollectibleAirdrop.event) do(e: Args):
var receivedData = TransactionMinedArgs(e)
let receivedData = TransactionMinedArgs(e)
let airdropDetails = toAirdropDetails(parseJson(receivedData.data))
if not receivedData.success:
error "Collectible airdrop failed", contractAddress=airdropDetails.contractAddress
return
try:
# add holders to db
discard addTokenOwners(airdropDetails.chainId, airdropDetails.contractAddress,
airdropDetails.walletAddresses, airdropDetails.amount)
except RpcException:
error "Error adding collectible token owners", message = getCurrentExceptionMsg()
#TODO signalize about airdrops - add when extending airdrops
self.events.on(PendingTransactionTypeDto.CollectibleRemoteSelfDestruct.event) do(e: Args):
let receivedData = TransactionMinedArgs(e)
let tokenDto = toCommunityTokenDto(parseJson(receivedData.data))
let transactionStatus = if receivedData.success: ContractTransactionStatus.Completed else: ContractTransactionStatus.Failed
let data = RemoteDestructArgs(communityToken: tokenDto, transactionHash: receivedData.transactionHash, status: transactionStatus)
self.events.emit(SIGNAL_REMOTE_DESTRUCT_STATUS, data)
# update owners list if burn was successfull
if receivedData.success:
self.tempTokenOwnersToFetch = tokenDto
self.tokenOwners1SecTimer.start()
proc deployCollectiblesEstimate*(self: Service): int =
try:
@ -181,8 +216,6 @@ QtObject:
debug "Deployed contract address ", contractAddress=contractAddress
debug "Deployment transaction hash ", transactionHash=transactionHash
self.addressAndTxMap[(contractAddress, chainId)] = transactionHash
var communityToken: CommunityTokenDto
communityToken.tokenType = TokenType.ERC721
communityToken.communityId = communityId
@ -245,6 +278,13 @@ QtObject:
except RpcException:
error "Error getting contract owner", message = getCurrentExceptionMsg()
proc contractOwnerName*(self: Service, chainId: int, contractAddress: string): string =
try:
let response = tokens_backend.contractOwner(chainId, contractAddress)
return self.walletAccountService.getAccountByAddress(response.result.getStr().toLower()).name
except RpcException:
error "Error getting contract owner name", message = getCurrentExceptionMsg()
proc airdropCollectibles*(self: Service, communityId: string, password: string, collectiblesAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) =
try:
for collectibleAndAmount in collectiblesAndAmounts:
@ -286,52 +326,147 @@ QtObject:
let arg = AsyncGetSuggestedFees(
tptr: cast[ByteAddress](asyncGetSuggestedFeesTask),
vptr: cast[ByteAddress](self.vptr),
slot: "onSuggestedFees",
slot: "onDeployFees",
chainId: chainId,
)
self.threadpool.start(arg)
except Exception as e:
error "Error loading fees", msg = e.msg
proc onSuggestedFees*(self:Service, response: string) {.slot.} =
let responseJson = response.parseJson()
const ethSymbol = "ETH"
proc findContractByUniqueId(self: Service, contractUniqueKey: string): CommunityTokenDto =
let allTokens = self.getAllCommunityTokens()
for token in allTokens:
if common_utils.contractUniqueKey(token.chainId, token.address) == contractUniqueKey:
return token
if responseJson{"error"}.kind != JNull and responseJson{"error"}.getStr != "":
let errorMessage = responseJson["error"].getStr
var errorCode = ComputeFeeErrorCode.Other
if errorMessage.contains("403 Forbidden") or errorMessage.contains("exceed"):
errorCode = ComputeFeeErrorCode.Infura
let ethCurrency = newCurrencyAmount(0.0, ethSymbol, 1, false)
let fiatCurrency = newCurrencyAmount(0.0, self.settingsService.getCurrency(), 1, false)
let data = ComputeDeployFeeArgs(ethCurrency: ethCurrency, fiatCurrency: fiatCurrency, errorCode: errorCode)
self.events.emit(SIGNAL_COMPUTE_DEPLOY_FEE, data)
proc getOwnerBalances(self: Service, contractOwners: seq[CollectibleOwner], ownerAddress: string): seq[CollectibleBalance] =
for owner in contractOwners:
if owner.address == ownerAddress:
return owner.balances
proc collectTokensToBurn(self: Service, walletAndAmountList: seq[WalletAndAmount], contractOwners: seq[CollectibleOwner]): seq[UInt256] =
if len(walletAndAmountList) == 0 or len(contractOwners) == 0:
return
for walletAndAmount in walletAndAmountList:
let ownerBalances = self.getOwnerBalances(contractOwners, walletAndAmount.walletAddress)
let amount = walletAndAmount.amount
if amount > len(ownerBalances):
error "amount to burn is higher than the number of tokens", amount=amount, balance=len(ownerBalances), owner=walletAndAmount.walletAddress
return
for i in 0..amount-1: # add the amount of tokens
result.add(ownerBalances[i].tokenId)
let suggestedFees = decodeSuggestedFeesDto(responseJson["fees"])
let contractGasUnits = self.deployCollectiblesEstimate()
proc getTokensToBurn(self: Service, walletAndAmountList: seq[WalletAndAmount], contract: CommunityTokenDto): seq[Uint256] =
if contract.address == "":
error "Can't find contract"
return
let tokenOwners = self.getCommunityTokenOwners(contract.communityId, contract.chainId, contract.address)
let tokenIds = self.collectTokensToBurn(walletAndAmountList, tokenOwners)
if len(tokenIds) == 0:
error "Can't find token ids to burn"
return tokenIds
# TODO use temp fees for deployment also
proc buildTransactionFromTempFees(self: Service, addressFrom: string): TransactionDataDto =
return ens_utils.buildTransaction(parseAddress(addressFrom), 0.u256, $self.tempGasUnits,
if self.tempSuggestedFees.eip1559Enabled: "" else: $self.tempSuggestedFees.gasPrice, self.tempSuggestedFees.eip1559Enabled,
if self.tempSuggestedFees.eip1559Enabled: $self.tempSuggestedFees.maxPriorityFeePerGas else: "",
if self.tempSuggestedFees.eip1559Enabled: $self.tempSuggestedFees.maxFeePerGasM else: "")
proc selfDestructCollectibles*(self: Service, communityId: string, password: string, walletAndAmounts: seq[WalletAndAmount], contractUniqueKey: string) =
try:
let contract = self.findContractByUniqueId(contractUniqueKey)
let tokenIds = self.getTokensToBurn(walletAndAmounts, contract)
if len(tokenIds) == 0:
return
let addressFrom = self.contractOwner(contract.chainId, contract.address)
let txData = self.buildTransactionFromTempFees(addressFrom)
debug "Remote destruct collectibles ", chainId=contract.chainId, address=contract.address, tokens=tokenIds
let response = tokens_backend.remoteBurn(contract.chainId, contract.address, %txData, password, tokenIds)
let transactionHash = response.result.getStr()
debug "Remote destruct transaction hash ", transactionHash=transactionHash
var data = RemoteDestructArgs(communityToken: contract, transactionHash: transactionHash, status: ContractTransactionStatus.InProgress)
self.events.emit(SIGNAL_REMOTE_DESTRUCT_STATUS, data)
# observe transaction state
self.transactionService.watchTransaction(
transactionHash,
addressFrom,
contract.address,
$PendingTransactionTypeDto.CollectibleRemoteSelfDestruct,
$contract.toJsonNode(),
contract.chainId,
)
except Exception as e:
error "Remote self destruct error", msg = e.msg
proc computeSelfDestructFee*(self: Service, walletAndAmountList: seq[WalletAndAmount], contractUniqueKey: string) =
try:
let contract = self.findContractByUniqueId(contractUniqueKey)
self.tempAccountAddress = self.contractOwner(contract.chainId, contract.address)
self.tempChainId = contract.chainId
let tokenIds = self.getTokensToBurn(walletAndAmountList, contract)
if len(tokenIds) == 0:
warn "token list is empty"
return
let arg = AsyncGetBurnFees(
tptr: cast[ByteAddress](asyncGetBurnFeesTask),
vptr: cast[ByteAddress](self.vptr),
slot: "onSelfDestructFees",
chainId: contract.chainId,
contractAddress: contract.address,
tokenIds: tokenIds
)
self.threadpool.start(arg)
except Exception as e:
error "Error loading fees", msg = e.msg
proc createComputeFeeArgs(self:Service, jsonNode: JsonNode, gasUnits: int, chainId: int, walletAddress: string): ComputeFeeArgs =
const ethSymbol = "ETH"
if jsonNode{"error"}.kind != JNull and jsonNode{"error"}.getStr != "":
let errorMessage = jsonNode["error"].getStr
var errorCode = ComputeFeeErrorCode.Other
if errorMessage.contains("403 Forbidden") or errorMessage.contains("exceed"):
errorCode = ComputeFeeErrorCode.Infura
let ethCurrency = newCurrencyAmount(0.0, ethSymbol, 1, false)
let fiatCurrency = newCurrencyAmount(0.0, self.settingsService.getCurrency(), 1, false)
return ComputeFeeArgs(ethCurrency: ethCurrency, fiatCurrency: fiatCurrency, errorCode: errorCode)
let suggestedFees = decodeSuggestedFeesDto(jsonNode["fees"])
# save suggested fees and use during operation, we always compute fees before operation
self.tempSuggestedFees = suggestedFees
self.tempGasUnits = gasUnits
let maxFees = suggestedFees.maxFeePerGasM
let gasPrice = if suggestedFees.eip1559Enabled: maxFees else: suggestedFees.gasPrice
let weiValue = gwei2Wei(gasPrice) * contractGasUnits.u256
let weiValue = gwei2Wei(gasPrice) * gasUnits.u256
let ethValueStr = wei2Eth(weiValue)
let ethValue = parseFloat(ethValueStr)
let fiatValue = self.getFiatValue(ethValue, ethSymbol)
let wallet = self.walletAccountService.getAccountByAddress(self.tempAccountAddress)
let wallet = self.walletAccountService.getAccountByAddress(walletAddress.toLower())
var balance = 0.0
let tokens = wallet.tokens
for token in tokens:
if token.symbol == ethSymbol:
balance = token.balancesPerChain[self.tempChainId].balance
balance = token.balancesPerChain[chainId].balance
break
let ethCurrency = newCurrencyAmount(ethValue, ethSymbol, 4, false)
let fiatCurrency = newCurrencyAmount(fiatValue, self.settingsService.getCurrency(), 2, false)
let data = ComputeDeployFeeArgs(ethCurrency: ethCurrency, fiatCurrency: fiatCurrency,
return ComputeFeeArgs(ethCurrency: ethCurrency, fiatCurrency: fiatCurrency,
errorCode: (if ethValue > balance: ComputeFeeErrorCode.Balance else: ComputeFeeErrorCode.Success))
proc onSelfDestructFees*(self:Service, response: string) {.slot.} =
let responseJson = response.parseJson()
let burnGas = if responseJson{"burnGas"}.kind != JNull: responseJson{"burnGas"}.getInt else: 0
let data = self.createComputeFeeArgs(responseJson, burnGas, self.tempChainId, self.tempAccountAddress)
self.events.emit(SIGNAL_COMPUTE_SELF_DESTRUCT_FEE, data)
proc onDeployFees*(self:Service, response: string) {.slot.} =
let responseJson = response.parseJson()
let data = self.createComputeFeeArgs(responseJson, self.deployCollectiblesEstimate(), self.tempChainId, self.tempAccountAddress)
self.events.emit(SIGNAL_COMPUTE_DEPLOY_FEE, data)
proc fetchCommunityOwners*(self: Service, communityId: string, chainId: int, contractAddress: string) =
@ -359,7 +494,9 @@ QtObject:
let contractAddress = responseJson["contractAddress"].getStr
let communityId = responseJson["communityId"].getStr
let resultJson = responseJson["result"]
let owners = collectibles_dto.toCollectibleOwnershipDto(resultJson).owners
var owners = collectibles_dto.toCollectibleOwnershipDto(resultJson).owners
owners = owners.filter(x => x.address != ZERO_ADDRESS)
self.tokenOwnersCache[(contractAddress, chainId)] = owners
let data = CommunityTokenOwnersArgs(chainId: chainId, contractAddress: contractAddress, communityId: communityId, owners: owners)
self.events.emit(SIGNAL_COMMUNITY_TOKEN_OWNERS_FETCHED, data)
@ -369,6 +506,9 @@ QtObject:
if token.transferable:
self.fetchCommunityOwners(token.communityId, token.chainId, token.address)
proc onFetchTempTokenOwners*(self: Service) {.slot.} =
self.fetchCommunityOwners(self.tempTokenOwnersToFetch.communityId, self.tempTokenOwnersToFetch.chainId, self.tempTokenOwnersToFetch.address)
proc fetchAllTokenOwners*(self: Service) =
let allTokens = self.getAllCommunityTokens()
for token in allTokens:

View File

@ -18,6 +18,7 @@ type
WalletTransfer = "WalletTransfer"
CollectibleDeployment = "CollectibleDeployment"
CollectibleAirdrop = "CollectibleAirdrop"
CollectibleRemoteSelfDestruct = "CollectibleRemoteSelfDestruct"
proc event*(self:PendingTransactionTypeDto):string =
result = "transaction:" & $self

View File

@ -1,4 +1,6 @@
import json
import json, stint
import std/sequtils
import std/sugar
import ./eth
import ../app_service/common/utils
import ./core, ./response_type
@ -28,6 +30,14 @@ proc mintTo*(chainId: int, contractAddress: string, txData: JsonNode, password:
let payload = %* [chainId, contractAddress, txData, utils.hashPassword(password), walletAddresses, amount]
return core.callPrivateRPC("collectibles_mintTo", payload)
proc remoteBurn*(chainId: int, contractAddress: string, txData: JsonNode, password: string, tokenIds: seq[UInt256]): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [chainId, contractAddress, txData, utils.hashPassword(password), tokenIds.map(x => x.toString(10))]
return core.callPrivateRPC("collectibles_remoteBurn", payload)
proc estimateRemoteBurn*(chainId: int, contractAddress: string, tokenIds: seq[UInt256]): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [chainId, contractAddress, tokenIds.map(x => x.toString(10))]
return core.callPrivateRPC("collectibles_estimateRemoteBurn", payload)
proc contractOwner*(chainId: int, contractAddress: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [chainId, contractAddress]
return core.callPrivateRPC("collectibles_contractOwner", payload)

View File

@ -67,12 +67,11 @@ SettingsPageLayout {
signal signMintTransactionOpened(int chainId, string accountAddress)
signal signSelfDestructTransactionOpened(int chainId)
signal signSelfDestructTransactionOpened(var selfDestructTokensList, // [key , amount]
string contractUniqueKey)
signal remoteSelfDestructCollectibles(var selfDestructTokensList, // [key , amount]
int chainId,
string accountName,
string accountAddress)
string contractUniqueKey)
signal signBurnTransactionOpened(int chainId)
@ -109,6 +108,7 @@ SettingsPageLayout {
property string accountName
property int chainId
property string chainName
property string contractUniqueKey
property var tokenOwnersModel
property var selfDestructTokensList
@ -436,13 +436,9 @@ SettingsPageLayout {
property bool isRemotelyDestructTransaction
function signTransaction() {
root.isFeeLoading = true
root.feeText = ""
root.setFeeLoading()
if(signTransactionPopup.isRemotelyDestructTransaction) {
root.remoteSelfDestructCollectibles(d.selfDestructTokensList,
d.chainId,
d.accountName,
d.accountAddress)
root.remoteSelfDestructCollectibles(d.selfDestructTokensList, d.contractUniqueKey)
} else {
root.burnCollectibles("TODO - KEY"/*d.tokenKey*/, d.burnAmount)
}
@ -457,9 +453,13 @@ SettingsPageLayout {
networkName: d.chainName
feeText: root.feeText
isFeeLoading: root.isFeeLoading
errorText: root.errorText
onOpened: signTransactionPopup.isRemotelyDestructTransaction ? root.signSelfDestructTransactionOpened(d.chainId) :
root.signBurnTransactionOpened(d.chainId)
onOpened: {
root.setFeeLoading()
signTransactionPopup.isRemotelyDestructTransaction ? root.signSelfDestructTransactionOpened(d.selfDestructTokensList, d.contractUniqueKey) :
root.signBurnTransactionOpened(d.chainId)
}
onCancelClicked: close()
onSignTransactionClicked: signTransaction()
}
@ -490,6 +490,7 @@ SettingsPageLayout {
onItemClicked: {
d.accountAddress = accountAddress
d.chainId = chainId
d.contractUniqueKey = contractUniqueKey
d.chainName = chainName
d.accountName = accountName
//d.tokenKey = key // TODO: Backend key role

View File

@ -275,6 +275,25 @@ StatusSectionLayout {
readonly property CommunityTokensStore communityTokensStore:
rootStore.communityTokensStore
function setFeesInfo(ethCurrency, fiatCurrency, errorCode) {
if (errorCode === Constants.ComputeFeeErrorCode.Success || errorCode === Constants.ComputeFeeErrorCode.Balance) {
let valueStr = LocaleUtils.currencyAmountToLocaleString(ethCurrency) + "(" + LocaleUtils.currencyAmountToLocaleString(fiatCurrency) + ")"
mintPanel.feeText = valueStr
if (errorCode === Constants.ComputeFeeErrorCode.Balance) {
mintPanel.errorText = qsTr("Not enough funds to make transaction")
}
mintPanel.isFeeLoading = false
return
} else if (errorCode === Constants.ComputeFeeErrorCode.Infura) {
mintPanel.errorText = qsTr("Infura error")
mintPanel.isFeeLoading = true
return
}
mintPanel.errorText = qsTr("Unknown error")
mintPanel.isFeeLoading = true
}
communityName: root.community.name
tokensModel: root.community.communityTokens
layer1Networks: communityTokensStore.layer1Networks
@ -315,12 +334,11 @@ StatusSectionLayout {
accountName,
artworkCropRect)
}
onSignSelfDestructTransactionOpened: communityTokensStore.computeSelfDestructFee(chainId)
onSignSelfDestructTransactionOpened: communityTokensStore.computeSelfDestructFee(selfDestructTokensList, contractUniqueKey)
onRemoteSelfDestructCollectibles: {
communityTokensStore.remoteSelfDestructCollectibles(selfDestructTokensList,
chainId,
accountName,
accountAddress)
communityTokensStore.remoteSelfDestructCollectibles(root.community.id,
selfDestructTokensList,
contractUniqueKey)
}
onSignBurnTransactionOpened: communityTokensStore.computeBurnFee(chainId)
onBurnCollectibles: communityTokensStore.burnCollectibles(tokenKey, amount)
@ -329,22 +347,43 @@ StatusSectionLayout {
Connections {
target: rootStore.communityTokensStore
function onDeployFeeUpdated(ethCurrency, fiatCurrency, errorCode) {
if (errorCode === Constants.ComputeFeeErrorCode.Success || errorCode === Constants.ComputeFeeErrorCode.Balance) {
let valueStr = LocaleUtils.currencyAmountToLocaleString(ethCurrency) + "(" + LocaleUtils.currencyAmountToLocaleString(fiatCurrency) + ")"
mintPanel.feeText = valueStr
if (errorCode === Constants.ComputeFeeErrorCode.Balance) {
mintPanel.errorText = qsTr("Not enough funds to make transaction")
}
mintPanel.isFeeLoading = false
return
} else if (errorCode === Constants.ComputeFeeErrorCode.Infura) {
mintPanel.errorText = qsTr("Infura error")
mintPanel.isFeeLoading = true
mintPanel.setFeesInfo(ethCurrency, fiatCurrency, errorCode)
}
function onSelfDestructFeeUpdated(ethCurrency, fiatCurrency, errorCode) {
mintPanel.setFeesInfo(ethCurrency, fiatCurrency, errorCode)
}
function onRemoteDestructStateChanged(communityId, tokenName, status, url) {
if (root.community.id !== communityId) {
return
}
mintPanel.errorText = qsTr("Unknown error")
mintPanel.isFeeLoading = true
let title = ""
let loading = false
let type = Constants.ephemeralNotificationType.normal
switch (status) {
case Constants.ContractTransactionStatus.InProgress:
title = qsTr("Remotely destroying tokens...")
loading = true
break
case Constants.ContractTransactionStatus.Completed:
title = qsTr("%1 tokens destroyed").arg(tokenName)
type = Constants.ephemeralNotificationType.success
break
case Constants.ContractTransactionStatus.Failed:
title = qsTr("%1 tokens destruction failed").arg(tokenName)
break
default:
console.warn("Unknown destruction state: "+status)
return
}
Global.displayToastMessage(title,
qsTr("View on etherscan"),
"",
loading,
type,
url)
}
function onDeploymentStateChanged(communityId, status, url) {
@ -356,15 +395,15 @@ StatusSectionLayout {
let loading = false
let type = Constants.ephemeralNotificationType.normal
switch (status) {
case Constants.BackendProcessState.InProgress:
case Constants.ContractTransactionStatus.InProgress:
title = qsTr("Token is being minted...")
loading = true
break
case Constants.BackendProcessState.Completed:
case Constants.ContractTransactionStatus.Completed:
title = qsTr("Token minting finished")
type = Constants.ephemeralNotificationType.success
break
case Constants.BackendProcessState.Failed:
case Constants.ContractTransactionStatus.Failed:
title = qsTr("Token minting failed")
break
default:

View File

@ -17,6 +17,7 @@ StatusScrollView {
signal itemClicked(int index,
int chainId,
string contractUniqueKey,
string chainName,
string accountName,
string accountAddress)
@ -25,11 +26,11 @@ StatusScrollView {
id: d
function getSubtitle(deployState, remainingTokens, supply) {
if(deployState === Constants.BackendProcessState.Failed) {
if(deployState === Constants.ContractTransactionStatus.Failed) {
return qsTr("Minting failed")
}
if(deployState === Constants.BackendProcessState.InProgress) {
if(deployState === Constants.ContractTransactionStatus.InProgress) {
return qsTr("Minting...")
}
@ -71,13 +72,13 @@ StatusScrollView {
width: gridView.cellWidth
title: model.name ? model.name : "..."
subTitle: d.getSubtitle(model.deployState, model.remainingTokens, model.supply)
subTitleColor: (model.deployState === Constants.BackendProcessState.Failed) ? Theme.palette.dangerColor1 : Theme.palette.baseColor1
subTitleColor: (model.deployState === Constants.ContractTransactionStatus.Failed) ? Theme.palette.dangerColor1 : Theme.palette.baseColor1
fallbackImageUrl: model.image ? model.image : ""
backgroundColor: model.backgroundColor ? model.backgroundColor : "transparent" // TODO BACKEND
isLoading: false
navigationIconVisible: true
onClicked: root.itemClicked(model.index, model.chainId, model.chainName, model.accountName, model.address) // TODO: Replace to model.key when role exists in backend
onClicked: root.itemClicked(model.index, model.chainId, model.contractUniqueKey, model.chainName, model.accountName, model.address)
}
}
}

View File

@ -37,13 +37,13 @@ StatusScrollView {
property var tokenOwnersModel
property int deployState: Constants.BackendProcessState.None
property int burnState: Constants.BackendProcessState.None
property int deployState: Constants.ContractTransactionStatus.None
property int burnState: Constants.ContractTransactionStatus.None
// Collectible object properties (ERC721)
property bool transferable
property bool selfDestruct
property int remotelyDestructState: Constants.BackendProcessState.None
property int remotelyDestructState: Constants.ContractTransactionStatus.None
// Asset properties (ERC20)
property alias assetDecimals: decimalsBox.value
@ -88,8 +88,8 @@ StatusScrollView {
contentHeight: mainLayout.height
padding: 0
onRemotelyDestructStateChanged: if(remotelyDestructState === Constants.BackendProcessState.Completed) d.startAnimation(false)
onBurnStateChanged: if(burnState === Constants.BackendProcessState.Completed) d.startAnimation(true)
onRemotelyDestructStateChanged: if(remotelyDestructState === Constants.ContractTransactionStatus.Completed) d.startAnimation(false)
onBurnStateChanged: if(burnState === Constants.ContractTransactionStatus.Completed) d.startAnimation(true)
ColumnLayout {
id: mainLayout
@ -98,16 +98,16 @@ StatusScrollView {
spacing: Style.current.padding
RowLayout {
visible: !root.preview && ((root.deployState === Constants.BackendProcessState.InProgress) ||
(root.deployState === Constants.BackendProcessState.Failed))
visible: !root.preview && ((root.deployState === Constants.ContractTransactionStatus.InProgress) ||
(root.deployState === Constants.ContractTransactionStatus.Failed))
spacing: Style.current.halfPadding
StatusDotsLoadingIndicator {
visible: (root.deployState === Constants.BackendProcessState.InProgress)
visible: (root.deployState === Constants.ContractTransactionStatus.InProgress)
}
StatusIcon {
visible: (root.deployState === Constants.BackendProcessState.Failed)
visible: (root.deployState === Constants.ContractTransactionStatus.Failed)
icon: "warning"
color: Theme.palette.dangerColor1
}
@ -115,12 +115,12 @@ StatusScrollView {
StatusBaseText {
elide: Text.ElideRight
font.pixelSize: Theme.primaryTextFontSize
text: (root.deployState === Constants.BackendProcessState.InProgress) ?
text: (root.deployState === Constants.ContractTransactionStatus.InProgress) ?
(root.isAssetView ?
qsTr("Asset is being minted") : qsTr("Collectible is being minted")) :
(root.deployState === Constants.BackendProcessState.Failed) ?
(root.deployState === Constants.ContractTransactionStatus.Failed) ?
(root.isAssetView ? qsTr("Asset minting failed") : qsTr("Collectible minting failed")) : ""
color: (root.deployState === Constants.BackendProcessState.Failed) ? Theme.palette.dangerColor1 : Theme.palette.directColor1
color: (root.deployState === Constants.ContractTransactionStatus.Failed) ? Theme.palette.dangerColor1 : Theme.palette.directColor1
}
}
@ -239,8 +239,8 @@ StatusScrollView {
label: qsTr("Total")
value: root.infiniteSupply ? d.infiniteSymbol : LocaleUtils.numberToLocaleString(root.supplyAmount)
isLoading: !root.infiniteSupply &&
((root.remotelyDestructState === Constants.BackendProcessState.InProgress) ||
(root.burnState === Constants.BackendProcessState.InProgress))
((root.remotelyDestructState === Constants.ContractTransactionStatus.InProgress) ||
(root.burnState === Constants.ContractTransactionStatus.InProgress))
}
CustomPreviewBox {
@ -248,7 +248,7 @@ StatusScrollView {
label: qsTr("Remaining")
value: root.infiniteSupply ? d.infiniteSymbol : LocaleUtils.numberToLocaleString(root.remainingTokens)
isLoading: !root.infiniteSupply && (root.burnState === Constants.BackendProcessState.InProgress)
isLoading: !root.infiniteSupply && (root.burnState === Constants.ContractTransactionStatus.InProgress)
}
CustomPreviewBox {

View File

@ -14,10 +14,14 @@ QtObject {
property var allNetworks: networksModule.all
signal deployFeeUpdated(var ethCurrency, var fiatCurrency, int error)
signal selfDestructFeeUpdated(var ethCurrency, var fiatCurrency, int error)
signal deploymentStateChanged(string communityId, int status, string url)
signal selfDestructFeeUpdated(string value) // TO BE REMOVED
signal burnFeeUpdated(string value) // TO BE REMOVED
signal remoteDestructStateChanged(string communityId, string tokenName, int status, string url)
// Minting tokens:
function deployCollectible(communityId, accountAddress, name, symbol, description, supply,
infiniteSupply, transferable, selfDestruct, chainId, artworkSource, accountName, artworkCropRect)
@ -43,26 +47,27 @@ QtObject {
function onDeployFeeUpdated(ethCurrency, fiatCurrency, errorCode) {
root.deployFeeUpdated(ethCurrency, fiatCurrency, errorCode)
}
function onSelfDestructFeeUpdated(ethCurrency, fiatCurrency, errorCode) {
root.selfDestructFeeUpdated(ethCurrency, fiatCurrency, errorCode)
}
function onDeploymentStateChanged(communityId, status, url) {
root.deploymentStateChanged(communityId, status, url)
}
function onRemoteDestructStateChanged(communityId, tokenName, status, url) {
root.remoteDestructStateChanged(communityId, tokenName, status, url)
}
}
function computeDeployFee(chainId, accountAddress) {
communityTokensModuleInst.computeDeployFee(chainId, accountAddress)
}
// Remotely destruct:
function computeSelfDestructFee(chainId) {
// TODO BACKEND
root.selfDestructFeeUpdated("0,0005 ETH")
console.warn("TODO: Compute self-destruct fee backend")
function computeSelfDestructFee(selfDestructTokensList, contractUniqueKey) {
communityTokensModuleInst.computeSelfDestructFee(JSON.stringify(selfDestructTokensList), contractUniqueKey)
}
function remoteSelfDestructCollectibles(selfDestructTokensList, chainId, accountName, accountAddress) {
// TODO BACKEND
// selfDestructTokensList is a js array with properties: `walletAddress` and `amount`
console.warn("TODO: Remote self-destruct collectible backend")
function remoteSelfDestructCollectibles(communityId, selfDestructTokensList, contractUniqueKey) {
communityTokensModuleInst.selfDestructCollectibles(communityId, JSON.stringify(selfDestructTokensList), contractUniqueKey)
}
// Burn:

View File

@ -893,7 +893,8 @@ QtObject {
Everyone = 4
}
enum BackendProcessState {
// refers to ContractTransactionStatus and DeployState in Nim
enum ContractTransactionStatus {
Failed,
InProgress,
Completed,