feat(@desktop/communities): Add self-destruct tokens functionality
Issue #10052
This commit is contained in:
parent
c40472c285
commit
4c29343a4a
|
@ -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)
|
||||
|
||||
|
|
|
@ -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")
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -18,6 +18,7 @@ type
|
|||
WalletTransfer = "WalletTransfer"
|
||||
CollectibleDeployment = "CollectibleDeployment"
|
||||
CollectibleAirdrop = "CollectibleAirdrop"
|
||||
CollectibleRemoteSelfDestruct = "CollectibleRemoteSelfDestruct"
|
||||
|
||||
proc event*(self:PendingTransactionTypeDto):string =
|
||||
result = "transaction:" & $self
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -893,7 +893,8 @@ QtObject {
|
|||
Everyone = 4
|
||||
}
|
||||
|
||||
enum BackendProcessState {
|
||||
// refers to ContractTransactionStatus and DeployState in Nim
|
||||
enum ContractTransactionStatus {
|
||||
Failed,
|
||||
InProgress,
|
||||
Completed,
|
||||
|
|
Loading…
Reference in New Issue