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
|
return
|
||||||
self.communityTokensModule.onUserAuthenticated(args.password)
|
self.communityTokensModule.onUserAuthenticated(args.password)
|
||||||
self.events.on(SIGNAL_COMPUTE_DEPLOY_FEE) do(e:Args):
|
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.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):
|
self.events.on(SIGNAL_COMMUNITY_TOKEN_DEPLOYED) do(e: Args):
|
||||||
let args = CommunityTokenDeployedArgs(e)
|
let args = CommunityTokenDeployedArgs(e)
|
||||||
self.communityTokensModule.onCommunityTokenDeployStateChanged(args.communityToken.communityId, args.communityToken.chainId, args.transactionHash, args.communityToken.deployState)
|
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):
|
self.events.on(SIGNAL_COMMUNITY_TOKEN_DEPLOY_STATUS) do(e: Args):
|
||||||
let args = CommunityTokenDeployedStatusArgs(e)
|
let args = CommunityTokenDeployedStatusArgs(e)
|
||||||
self.communityTokensModule.onCommunityTokenDeployStateChanged(args.communityId, args.chainId, args.transactionHash, args.deployState)
|
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) =
|
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)
|
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]) =
|
proc airdropCollectibles*(self: Controller, communityId: string, password: string, collectiblesAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) =
|
||||||
self.communityTokensService.airdropCollectibles(communityId, password, collectiblesAndAmounts, walletAddresses)
|
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 = "") =
|
proc authenticateUser*(self: Controller, keyUid = "") =
|
||||||
let data = SharedKeycarModuleAuthenticationArgs(uniqueIdentifier: UNIQUE_DEPLOY_COLLECTIBLES_COMMUNITY_TOKENS_MODULE_IDENTIFIER, keyUid: keyUid)
|
let data = SharedKeycarModuleAuthenticationArgs(uniqueIdentifier: UNIQUE_DEPLOY_COLLECTIBLES_COMMUNITY_TOKENS_MODULE_IDENTIFIER, keyUid: keyUid)
|
||||||
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_AUTHENTICATE_USER, data)
|
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) =
|
proc computeDeployFee*(self: Controller, chainId: int, accountAddress: string) =
|
||||||
self.communityTokensService.computeDeployFee(chainId, accountAddress)
|
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 =
|
proc getCommunityTokenBySymbol*(self: Controller, communityId: string, symbol: string): CommunityTokenDto =
|
||||||
return self.communityTokensService.getCommunityTokenBySymbol(communityId, symbol)
|
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.} =
|
method airdropCollectibles*(self: AccessInterface, communityId: string, collectiblesJsonString: string, walletsJsonString: string) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
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,
|
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.} =
|
selfDestruct: bool, chainId: int, image: string) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
@ -26,8 +29,17 @@ method resetTempValues*(self: AccessInterface) {.base.} =
|
||||||
method computeDeployFee*(self: AccessInterface, chainId: int, accountAddress: string) {.base.} =
|
method computeDeployFee*(self: AccessInterface, chainId: int, accountAddress: string) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
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.} =
|
method onDeployFeeComputed*(self: AccessInterface, ethCurrency: CurrencyAmount, fiatCurrency: CurrencyAmount, errorCode: ComputeFeeErrorCode) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
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.} =
|
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")
|
raise newException(ValueError, "No implementation available")
|
|
@ -13,17 +13,20 @@ type
|
||||||
tokenDto*: CommunityTokenDto
|
tokenDto*: CommunityTokenDto
|
||||||
chainName*: string
|
chainName*: string
|
||||||
chainIcon*: string
|
chainIcon*: string
|
||||||
|
accountName*: string
|
||||||
tokenOwnersModel*: token_owners_model.TokenOwnersModel
|
tokenOwnersModel*: token_owners_model.TokenOwnersModel
|
||||||
|
|
||||||
proc initTokenItem*(
|
proc initTokenItem*(
|
||||||
tokenDto: CommunityTokenDto,
|
tokenDto: CommunityTokenDto,
|
||||||
network: NetworkDto,
|
network: NetworkDto,
|
||||||
tokenOwners: seq[CollectibleOwner]
|
tokenOwners: seq[CollectibleOwner],
|
||||||
|
accountName: string
|
||||||
): TokenItem =
|
): TokenItem =
|
||||||
result.tokenDto = tokenDto
|
result.tokenDto = tokenDto
|
||||||
if network != nil:
|
if network != nil:
|
||||||
result.chainName = network.chainName
|
result.chainName = network.chainName
|
||||||
result.chainIcon = network.iconURL
|
result.chainIcon = network.iconURL
|
||||||
|
result.accountName = accountName
|
||||||
result.tokenOwnersModel = newTokenOwnersModel()
|
result.tokenOwnersModel = newTokenOwnersModel()
|
||||||
result.tokenOwnersModel.setItems(tokenOwners.map(proc(owner: CollectibleOwner): TokenOwnersItem =
|
result.tokenOwnersModel.setItems(tokenOwners.map(proc(owner: CollectibleOwner): TokenOwnersItem =
|
||||||
# TODO find member with the address - later when airdrop to member will be added
|
# 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 token_owners_model
|
||||||
import ../../../../../../app_service/service/community_tokens/dto/community_token
|
import ../../../../../../app_service/service/community_tokens/dto/community_token
|
||||||
import ../../../../../../app_service/service/collectible/dto
|
import ../../../../../../app_service/service/collectible/dto
|
||||||
|
import ../../../../../../app_service/common/utils
|
||||||
|
|
||||||
type
|
type
|
||||||
ModelRole {.pure.} = enum
|
ModelRole {.pure.} = enum
|
||||||
TokenType = UserRole + 1
|
ContractUniqueKey = UserRole + 1
|
||||||
|
TokenType
|
||||||
TokenAddress
|
TokenAddress
|
||||||
Name
|
Name
|
||||||
Symbol
|
Symbol
|
||||||
|
@ -22,6 +24,7 @@ type
|
||||||
ChainName
|
ChainName
|
||||||
ChainIcon
|
ChainIcon
|
||||||
TokenOwnersModel
|
TokenOwnersModel
|
||||||
|
AccountName
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
type TokenModel* = ref object of QAbstractListModel
|
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)):
|
if((self.items[i].tokenDto.address == contractAddress) and (self.items[i].tokenDto.chainId == chainId)):
|
||||||
self.items[i].tokenDto.deployState = deployState
|
self.items[i].tokenDto.deployState = deployState
|
||||||
let index = self.createIndex(i, 0, nil)
|
let index = self.createIndex(i, 0, nil)
|
||||||
|
defer: index.delete
|
||||||
self.dataChanged(index, index, @[ModelRole.DeployState.int])
|
self.dataChanged(index, index, @[ModelRole.DeployState.int])
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -87,6 +91,7 @@ QtObject:
|
||||||
|
|
||||||
method roleNames(self: TokenModel): Table[int, string] =
|
method roleNames(self: TokenModel): Table[int, string] =
|
||||||
{
|
{
|
||||||
|
ModelRole.ContractUniqueKey.int:"contractUniqueKey",
|
||||||
ModelRole.TokenType.int:"tokenType",
|
ModelRole.TokenType.int:"tokenType",
|
||||||
ModelRole.TokenAddress.int:"tokenAddress",
|
ModelRole.TokenAddress.int:"tokenAddress",
|
||||||
ModelRole.Name.int:"name",
|
ModelRole.Name.int:"name",
|
||||||
|
@ -102,6 +107,7 @@ QtObject:
|
||||||
ModelRole.ChainName.int:"chainName",
|
ModelRole.ChainName.int:"chainName",
|
||||||
ModelRole.ChainIcon.int:"chainIcon",
|
ModelRole.ChainIcon.int:"chainIcon",
|
||||||
ModelRole.TokenOwnersModel.int:"tokenOwnersModel",
|
ModelRole.TokenOwnersModel.int:"tokenOwnersModel",
|
||||||
|
ModelRole.AccountName.int:"accountName",
|
||||||
}.toTable
|
}.toTable
|
||||||
|
|
||||||
method data(self: TokenModel, index: QModelIndex, role: int): QVariant =
|
method data(self: TokenModel, index: QModelIndex, role: int): QVariant =
|
||||||
|
@ -112,6 +118,8 @@ QtObject:
|
||||||
let item = self.items[index.row]
|
let item = self.items[index.row]
|
||||||
let enumRole = role.ModelRole
|
let enumRole = role.ModelRole
|
||||||
case enumRole:
|
case enumRole:
|
||||||
|
of ModelRole.ContractUniqueKey:
|
||||||
|
result = newQVariant(contractUniqueKey(item.tokenDto.chainId, item.tokenDto.address))
|
||||||
of ModelRole.TokenType:
|
of ModelRole.TokenType:
|
||||||
result = newQVariant(item.tokenDto.tokenType.int)
|
result = newQVariant(item.tokenDto.tokenType.int)
|
||||||
of ModelRole.TokenAddress:
|
of ModelRole.TokenAddress:
|
||||||
|
@ -142,6 +150,8 @@ QtObject:
|
||||||
result = newQVariant(item.chainIcon)
|
result = newQVariant(item.chainIcon)
|
||||||
of ModelRole.TokenOwnersModel:
|
of ModelRole.TokenOwnersModel:
|
||||||
result = newQVariant(item.tokenOwnersModel)
|
result = newQVariant(item.tokenOwnersModel)
|
||||||
|
of ModelRole.AccountName:
|
||||||
|
result = newQVariant(item.accountName)
|
||||||
|
|
||||||
proc `$`*(self: TokenModel): string =
|
proc `$`*(self: TokenModel): string =
|
||||||
for i in 0 ..< self.items.len:
|
for i in 0 ..< self.items.len:
|
||||||
|
|
|
@ -18,6 +18,7 @@ type
|
||||||
Unknown = 0
|
Unknown = 0
|
||||||
Deploy = 1
|
Deploy = 1
|
||||||
Airdrop = 2
|
Airdrop = 2
|
||||||
|
SelfDestruct = 3
|
||||||
|
|
||||||
type
|
type
|
||||||
Module* = ref object of io_interface.AccessInterface
|
Module* = ref object of io_interface.AccessInterface
|
||||||
|
@ -26,6 +27,7 @@ type
|
||||||
view: View
|
view: View
|
||||||
viewVariant: QVariant
|
viewVariant: QVariant
|
||||||
tempTokenAndAmountList: seq[CommunityTokenAndAmount]
|
tempTokenAndAmountList: seq[CommunityTokenAndAmount]
|
||||||
|
tempWalletAndAmountList: seq[WalletAndAmount]
|
||||||
tempAddressFrom: string
|
tempAddressFrom: string
|
||||||
tempCommunityId: string
|
tempCommunityId: string
|
||||||
tempChainId: int
|
tempChainId: int
|
||||||
|
@ -34,6 +36,7 @@ type
|
||||||
tempTokenMetadata: CommunityTokensMetadataDto
|
tempTokenMetadata: CommunityTokensMetadataDto
|
||||||
tempWalletAddresses: seq[string]
|
tempWalletAddresses: seq[string]
|
||||||
tempContractAction: ContractAction
|
tempContractAction: ContractAction
|
||||||
|
tempContractUniqueKey: string
|
||||||
|
|
||||||
proc newCommunityTokensModule*(
|
proc newCommunityTokensModule*(
|
||||||
parent: parent_interface.AccessInterface,
|
parent: parent_interface.AccessInterface,
|
||||||
|
@ -62,6 +65,8 @@ method resetTempValues(self:Module) =
|
||||||
self.tempWalletAddresses = @[]
|
self.tempWalletAddresses = @[]
|
||||||
self.tempContractAction = ContractAction.Unknown
|
self.tempContractAction = ContractAction.Unknown
|
||||||
self.tempTokenAndAmountList = @[]
|
self.tempTokenAndAmountList = @[]
|
||||||
|
self.tempWalletAndAmountList = @[]
|
||||||
|
self.tempContractUniqueKey = ""
|
||||||
|
|
||||||
method load*(self: Module) =
|
method load*(self: Module) =
|
||||||
singletonInstance.engine.setRootContextProperty("communityTokensModule", self.viewVariant)
|
singletonInstance.engine.setRootContextProperty("communityTokensModule", self.viewVariant)
|
||||||
|
@ -92,6 +97,20 @@ method airdropCollectibles*(self: Module, communityId: string, collectiblesJsonS
|
||||||
self.tempContractAction = ContractAction.Airdrop
|
self.tempContractAction = ContractAction.Airdrop
|
||||||
self.authenticate()
|
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,
|
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) =
|
supply: int, infiniteSupply: bool, transferable: bool, selfDestruct: bool, chainId: int, image: string) =
|
||||||
self.tempAddressFrom = fromAddress
|
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)
|
self.controller.deployCollectibles(self.tempCommunityId, self.tempAddressFrom, password, self.tempDeploymentParams, self.tempTokenMetadata, self.tempChainId)
|
||||||
elif self.tempContractAction == ContractAction.Airdrop:
|
elif self.tempContractAction == ContractAction.Airdrop:
|
||||||
self.controller.airdropCollectibles(self.tempCommunityId, password, self.tempTokenAndAmountList, self.tempWalletAddresses)
|
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) =
|
method onDeployFeeComputed*(self: Module, ethCurrency: CurrencyAmount, fiatCurrency: CurrencyAmount, errorCode: ComputeFeeErrorCode) =
|
||||||
self.view.updateDeployFee(ethCurrency, fiatCurrency, errorCode.int)
|
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) =
|
method computeDeployFee*(self: Module, chainId: int, accountAddress: string) =
|
||||||
self.controller.computeDeployFee(chainId, accountAddress)
|
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) =
|
method onCommunityTokenDeployStateChanged*(self: Module, communityId: string, chainId: int, transactionHash: string, deployState: DeployState) =
|
||||||
let network = self.controller.getNetwork(chainId)
|
let network = self.controller.getNetwork(chainId)
|
||||||
let url = if network != nil: network.blockExplorerURL & "/tx/" & transactionHash else: ""
|
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.} =
|
proc airdropCollectibles*(self: View, communityId: string, collectiblesJsonString: string, walletsJsonString: string) {.slot.} =
|
||||||
self.communityTokensModule.airdropCollectibles(communityId, collectiblesJsonString, walletsJsonString)
|
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 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.} =
|
proc computeDeployFee*(self: View, chainId: int, accountAddress: string) {.slot.} =
|
||||||
self.communityTokensModule.computeDeployFee(chainId, accountAddress)
|
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) =
|
proc updateDeployFee*(self: View, ethCurrency: CurrencyAmount, fiatCurrency: CurrencyAmount, errorCode: int) =
|
||||||
self.deployFeeUpdated(newQVariant(ethCurrency), newQVariant(fiatCurrency), errorCode)
|
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 deploymentStateChanged*(self: View, communityId: string, status: int, url: string) {.signal.}
|
||||||
proc emitDeploymentStateChanged*(self: View, communityId: string, status: int, url: string) =
|
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] =
|
proc getCommunityTokenOwners*(self: Controller, communityId: string, chainId: int, contractAddress: string): seq[CollectibleOwner] =
|
||||||
return self.communityTokensService.getCommunityTokenOwners(communityId, chainId, contractAddress)
|
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 =
|
proc getNetwork*(self:Controller, chainId: int): NetworkDto =
|
||||||
self.networksService.getNetwork(chainId)
|
self.networksService.getNetwork(chainId)
|
|
@ -236,7 +236,8 @@ method delete*[T](self: Module[T]) =
|
||||||
proc createTokenItem[T](self: Module[T], tokenDto: CommunityTokenDto) : TokenItem =
|
proc createTokenItem[T](self: Module[T], tokenDto: CommunityTokenDto) : TokenItem =
|
||||||
let network = self.controller.getNetwork(tokenDto.chainId)
|
let network = self.controller.getNetwork(tokenDto.chainId)
|
||||||
let tokenOwners = self.controller.getCommunityTokenOwners(tokenDto.communityId, tokenDto.chainId, tokenDto.address)
|
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 =
|
proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto): SectionItem =
|
||||||
let isCommunity = channelGroup.channelGroupType == ChannelGroupType.Community
|
let isCommunity = channelGroup.channelGroupType == ChannelGroupType.Community
|
||||||
|
|
|
@ -80,4 +80,7 @@ proc isPathOutOfTheDefaultStatusDerivationTree*(path: string): bool =
|
||||||
path.count("'") != 3 or
|
path.count("'") != 3 or
|
||||||
path.count("/") != 5:
|
path.count("/") != 5:
|
||||||
return true
|
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
|
include ../../common/json_utils
|
||||||
import ../../../backend/eth
|
import ../../../backend/eth
|
||||||
|
import ../../../backend/community_tokens
|
||||||
import ../../../backend/collectibles
|
import ../../../backend/collectibles
|
||||||
import ../../../app/core/tasks/common
|
import ../../../app/core/tasks/common
|
||||||
import ../../../app/core/tasks/qt
|
import ../../../app/core/tasks/qt
|
||||||
|
@ -22,6 +24,26 @@ const asyncGetSuggestedFeesTask: Task = proc(argEncoded: string) {.gcsafe, nimca
|
||||||
"error": e.msg,
|
"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
|
type
|
||||||
FetchCollectibleOwnersArg = ref object of QObjectTaskArg
|
FetchCollectibleOwnersArg = ref object of QObjectTaskArg
|
||||||
chainId*: int
|
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/eventemitter
|
||||||
import ../../../app/core/tasks/[qt, threadpool]
|
import ../../../app/core/tasks/[qt, threadpool]
|
||||||
import ../../../app/modules/shared_models/currency_amount
|
import ../../../app/modules/shared_models/currency_amount
|
||||||
|
@ -15,6 +15,8 @@ import ../collectible/dto as collectibles_dto
|
||||||
import ../../../backend/response_type
|
import ../../../backend/response_type
|
||||||
|
|
||||||
import ../../common/conversion
|
import ../../common/conversion
|
||||||
|
import ../../common/account_constants
|
||||||
|
import ../../common/utils as common_utils
|
||||||
import ../community/dto/community
|
import ../community/dto/community
|
||||||
|
|
||||||
import ./dto/deployment_parameters
|
import ./dto/deployment_parameters
|
||||||
|
@ -37,6 +39,11 @@ type
|
||||||
communityToken*: CommunityTokenDto
|
communityToken*: CommunityTokenDto
|
||||||
amount*: int
|
amount*: int
|
||||||
|
|
||||||
|
type
|
||||||
|
WalletAndAmount* = object
|
||||||
|
walletAddress*: string
|
||||||
|
amount*: int
|
||||||
|
|
||||||
type
|
type
|
||||||
CommunityTokenDeployedStatusArgs* = ref object of Args
|
CommunityTokenDeployedStatusArgs* = ref object of Args
|
||||||
communityId*: string
|
communityId*: string
|
||||||
|
@ -50,6 +57,18 @@ type
|
||||||
communityToken*: CommunityTokenDto
|
communityToken*: CommunityTokenDto
|
||||||
transactionHash*: string
|
transactionHash*: string
|
||||||
|
|
||||||
|
type
|
||||||
|
ContractTransactionStatus* {.pure.} = enum
|
||||||
|
Failed,
|
||||||
|
InProgress,
|
||||||
|
Completed
|
||||||
|
|
||||||
|
type
|
||||||
|
RemoteDestructArgs* = ref object of Args
|
||||||
|
communityToken*: CommunityTokenDto
|
||||||
|
transactionHash*: string
|
||||||
|
status*: ContractTransactionStatus
|
||||||
|
|
||||||
type
|
type
|
||||||
ComputeFeeErrorCode* {.pure.} = enum
|
ComputeFeeErrorCode* {.pure.} = enum
|
||||||
Success,
|
Success,
|
||||||
|
@ -58,7 +77,7 @@ type
|
||||||
Other
|
Other
|
||||||
|
|
||||||
type
|
type
|
||||||
ComputeDeployFeeArgs* = ref object of Args
|
ComputeFeeArgs* = ref object of Args
|
||||||
ethCurrency*: CurrencyAmount
|
ethCurrency*: CurrencyAmount
|
||||||
fiatCurrency*: CurrencyAmount
|
fiatCurrency*: CurrencyAmount
|
||||||
errorCode*: ComputeFeeErrorCode
|
errorCode*: ComputeFeeErrorCode
|
||||||
|
@ -79,7 +98,9 @@ type
|
||||||
const SIGNAL_COMMUNITY_TOKEN_DEPLOY_STATUS* = "communityTokenDeployStatus"
|
const SIGNAL_COMMUNITY_TOKEN_DEPLOY_STATUS* = "communityTokenDeployStatus"
|
||||||
const SIGNAL_COMMUNITY_TOKEN_DEPLOYED* = "communityTokenDeployed"
|
const SIGNAL_COMMUNITY_TOKEN_DEPLOYED* = "communityTokenDeployed"
|
||||||
const SIGNAL_COMPUTE_DEPLOY_FEE* = "computeDeployFee"
|
const SIGNAL_COMPUTE_DEPLOY_FEE* = "computeDeployFee"
|
||||||
|
const SIGNAL_COMPUTE_SELF_DESTRUCT_FEE* = "computeSelfDestructFee"
|
||||||
const SIGNAL_COMMUNITY_TOKEN_OWNERS_FETCHED* = "communityTokenOwnersFetched"
|
const SIGNAL_COMMUNITY_TOKEN_OWNERS_FETCHED* = "communityTokenOwnersFetched"
|
||||||
|
const SIGNAL_REMOTE_DESTRUCT_STATUS* = "communityTokenRemoteDestructStatus"
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
type
|
type
|
||||||
|
@ -92,15 +113,20 @@ QtObject:
|
||||||
walletAccountService: wallet_account_service.Service
|
walletAccountService: wallet_account_service.Service
|
||||||
tempAccountAddress: string
|
tempAccountAddress: string
|
||||||
tempChainId: int
|
tempChainId: int
|
||||||
addressAndTxMap: Table[ContractTuple, string]
|
|
||||||
tokenOwnersTimer: QTimer
|
tokenOwnersTimer: QTimer
|
||||||
|
tokenOwners1SecTimer: QTimer # used to update 1 sec after changes in owners
|
||||||
|
tempTokenOwnersToFetch: CommunityTokenDto # used by 1sec timer
|
||||||
tokenOwnersCache: Table[ContractTuple, seq[CollectibleOwner]]
|
tokenOwnersCache: Table[ContractTuple, seq[CollectibleOwner]]
|
||||||
|
tempSuggestedFees: SuggestedFeesDto
|
||||||
|
tempGasUnits: int
|
||||||
|
|
||||||
# Forward declaration
|
# Forward declaration
|
||||||
proc fetchAllTokenOwners*(self: Service)
|
proc fetchAllTokenOwners*(self: Service)
|
||||||
|
proc getCommunityTokenOwners*(self: Service, communityId: string, chainId: int, contractAddress: string): seq[CollectibleOwner]
|
||||||
|
|
||||||
proc delete*(self: Service) =
|
proc delete*(self: Service) =
|
||||||
delete(self.tokenOwnersTimer)
|
delete(self.tokenOwnersTimer)
|
||||||
|
delete(self.tokenOwners1SecTimer)
|
||||||
self.QObject.delete
|
self.QObject.delete
|
||||||
|
|
||||||
proc newService*(
|
proc newService*(
|
||||||
|
@ -119,10 +145,13 @@ QtObject:
|
||||||
result.tokenService = tokenService
|
result.tokenService = tokenService
|
||||||
result.settingsService = settingsService
|
result.settingsService = settingsService
|
||||||
result.walletAccountService = walletAccountService
|
result.walletAccountService = walletAccountService
|
||||||
result.addressAndTxMap = initTable[ContractTuple, string]()
|
|
||||||
result.tokenOwnersTimer = newQTimer()
|
result.tokenOwnersTimer = newQTimer()
|
||||||
result.tokenOwnersTimer.setInterval(10*60*1000)
|
result.tokenOwnersTimer.setInterval(10*60*1000)
|
||||||
signalConnect(result.tokenOwnersTimer, "timeout()", result, "onRefreshTransferableTokenOwners()", 2)
|
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) =
|
proc init*(self: Service) =
|
||||||
self.fetchAllTokenOwners()
|
self.fetchAllTokenOwners()
|
||||||
|
@ -139,21 +168,27 @@ QtObject:
|
||||||
error "Error updating collectibles contract state", message = getCurrentExceptionMsg()
|
error "Error updating collectibles contract state", message = getCurrentExceptionMsg()
|
||||||
let data = CommunityTokenDeployedStatusArgs(communityId: tokenDto.communityId, contractAddress: tokenDto.address,
|
let data = CommunityTokenDeployedStatusArgs(communityId: tokenDto.communityId, contractAddress: tokenDto.address,
|
||||||
deployState: deployState, chainId: tokenDto.chainId,
|
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.emit(SIGNAL_COMMUNITY_TOKEN_DEPLOY_STATUS, data)
|
||||||
|
|
||||||
self.events.on(PendingTransactionTypeDto.CollectibleAirdrop.event) do(e: Args):
|
self.events.on(PendingTransactionTypeDto.CollectibleAirdrop.event) do(e: Args):
|
||||||
var receivedData = TransactionMinedArgs(e)
|
let receivedData = TransactionMinedArgs(e)
|
||||||
let airdropDetails = toAirdropDetails(parseJson(receivedData.data))
|
let airdropDetails = toAirdropDetails(parseJson(receivedData.data))
|
||||||
if not receivedData.success:
|
if not receivedData.success:
|
||||||
error "Collectible airdrop failed", contractAddress=airdropDetails.contractAddress
|
error "Collectible airdrop failed", contractAddress=airdropDetails.contractAddress
|
||||||
return
|
return
|
||||||
try:
|
#TODO signalize about airdrops - add when extending airdrops
|
||||||
# add holders to db
|
self.events.on(PendingTransactionTypeDto.CollectibleRemoteSelfDestruct.event) do(e: Args):
|
||||||
discard addTokenOwners(airdropDetails.chainId, airdropDetails.contractAddress,
|
let receivedData = TransactionMinedArgs(e)
|
||||||
airdropDetails.walletAddresses, airdropDetails.amount)
|
let tokenDto = toCommunityTokenDto(parseJson(receivedData.data))
|
||||||
except RpcException:
|
let transactionStatus = if receivedData.success: ContractTransactionStatus.Completed else: ContractTransactionStatus.Failed
|
||||||
error "Error adding collectible token owners", message = getCurrentExceptionMsg()
|
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 =
|
proc deployCollectiblesEstimate*(self: Service): int =
|
||||||
try:
|
try:
|
||||||
|
@ -181,8 +216,6 @@ QtObject:
|
||||||
debug "Deployed contract address ", contractAddress=contractAddress
|
debug "Deployed contract address ", contractAddress=contractAddress
|
||||||
debug "Deployment transaction hash ", transactionHash=transactionHash
|
debug "Deployment transaction hash ", transactionHash=transactionHash
|
||||||
|
|
||||||
self.addressAndTxMap[(contractAddress, chainId)] = transactionHash
|
|
||||||
|
|
||||||
var communityToken: CommunityTokenDto
|
var communityToken: CommunityTokenDto
|
||||||
communityToken.tokenType = TokenType.ERC721
|
communityToken.tokenType = TokenType.ERC721
|
||||||
communityToken.communityId = communityId
|
communityToken.communityId = communityId
|
||||||
|
@ -245,6 +278,13 @@ QtObject:
|
||||||
except RpcException:
|
except RpcException:
|
||||||
error "Error getting contract owner", message = getCurrentExceptionMsg()
|
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]) =
|
proc airdropCollectibles*(self: Service, communityId: string, password: string, collectiblesAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) =
|
||||||
try:
|
try:
|
||||||
for collectibleAndAmount in collectiblesAndAmounts:
|
for collectibleAndAmount in collectiblesAndAmounts:
|
||||||
|
@ -286,52 +326,147 @@ QtObject:
|
||||||
let arg = AsyncGetSuggestedFees(
|
let arg = AsyncGetSuggestedFees(
|
||||||
tptr: cast[ByteAddress](asyncGetSuggestedFeesTask),
|
tptr: cast[ByteAddress](asyncGetSuggestedFeesTask),
|
||||||
vptr: cast[ByteAddress](self.vptr),
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
slot: "onSuggestedFees",
|
slot: "onDeployFees",
|
||||||
chainId: chainId,
|
chainId: chainId,
|
||||||
)
|
)
|
||||||
self.threadpool.start(arg)
|
self.threadpool.start(arg)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error "Error loading fees", msg = e.msg
|
error "Error loading fees", msg = e.msg
|
||||||
|
|
||||||
proc onSuggestedFees*(self:Service, response: string) {.slot.} =
|
proc findContractByUniqueId(self: Service, contractUniqueKey: string): CommunityTokenDto =
|
||||||
let responseJson = response.parseJson()
|
let allTokens = self.getAllCommunityTokens()
|
||||||
const ethSymbol = "ETH"
|
for token in allTokens:
|
||||||
|
if common_utils.contractUniqueKey(token.chainId, token.address) == contractUniqueKey:
|
||||||
|
return token
|
||||||
|
|
||||||
if responseJson{"error"}.kind != JNull and responseJson{"error"}.getStr != "":
|
proc getOwnerBalances(self: Service, contractOwners: seq[CollectibleOwner], ownerAddress: string): seq[CollectibleBalance] =
|
||||||
let errorMessage = responseJson["error"].getStr
|
for owner in contractOwners:
|
||||||
var errorCode = ComputeFeeErrorCode.Other
|
if owner.address == ownerAddress:
|
||||||
if errorMessage.contains("403 Forbidden") or errorMessage.contains("exceed"):
|
return owner.balances
|
||||||
errorCode = ComputeFeeErrorCode.Infura
|
|
||||||
let ethCurrency = newCurrencyAmount(0.0, ethSymbol, 1, false)
|
proc collectTokensToBurn(self: Service, walletAndAmountList: seq[WalletAndAmount], contractOwners: seq[CollectibleOwner]): seq[UInt256] =
|
||||||
let fiatCurrency = newCurrencyAmount(0.0, self.settingsService.getCurrency(), 1, false)
|
if len(walletAndAmountList) == 0 or len(contractOwners) == 0:
|
||||||
let data = ComputeDeployFeeArgs(ethCurrency: ethCurrency, fiatCurrency: fiatCurrency, errorCode: errorCode)
|
return
|
||||||
self.events.emit(SIGNAL_COMPUTE_DEPLOY_FEE, data)
|
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
|
return
|
||||||
|
for i in 0..amount-1: # add the amount of tokens
|
||||||
|
result.add(ownerBalances[i].tokenId)
|
||||||
|
|
||||||
let suggestedFees = decodeSuggestedFeesDto(responseJson["fees"])
|
proc getTokensToBurn(self: Service, walletAndAmountList: seq[WalletAndAmount], contract: CommunityTokenDto): seq[Uint256] =
|
||||||
let contractGasUnits = self.deployCollectiblesEstimate()
|
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 maxFees = suggestedFees.maxFeePerGasM
|
||||||
let gasPrice = if suggestedFees.eip1559Enabled: maxFees else: suggestedFees.gasPrice
|
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 ethValueStr = wei2Eth(weiValue)
|
||||||
let ethValue = parseFloat(ethValueStr)
|
let ethValue = parseFloat(ethValueStr)
|
||||||
let fiatValue = self.getFiatValue(ethValue, ethSymbol)
|
let fiatValue = self.getFiatValue(ethValue, ethSymbol)
|
||||||
|
|
||||||
let wallet = self.walletAccountService.getAccountByAddress(self.tempAccountAddress)
|
let wallet = self.walletAccountService.getAccountByAddress(walletAddress.toLower())
|
||||||
|
|
||||||
var balance = 0.0
|
var balance = 0.0
|
||||||
let tokens = wallet.tokens
|
let tokens = wallet.tokens
|
||||||
for token in tokens:
|
for token in tokens:
|
||||||
if token.symbol == ethSymbol:
|
if token.symbol == ethSymbol:
|
||||||
balance = token.balancesPerChain[self.tempChainId].balance
|
balance = token.balancesPerChain[chainId].balance
|
||||||
break
|
break
|
||||||
|
|
||||||
let ethCurrency = newCurrencyAmount(ethValue, ethSymbol, 4, false)
|
let ethCurrency = newCurrencyAmount(ethValue, ethSymbol, 4, false)
|
||||||
let fiatCurrency = newCurrencyAmount(fiatValue, self.settingsService.getCurrency(), 2, 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))
|
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)
|
self.events.emit(SIGNAL_COMPUTE_DEPLOY_FEE, data)
|
||||||
|
|
||||||
proc fetchCommunityOwners*(self: Service, communityId: string, chainId: int, contractAddress: string) =
|
proc fetchCommunityOwners*(self: Service, communityId: string, chainId: int, contractAddress: string) =
|
||||||
|
@ -359,7 +494,9 @@ QtObject:
|
||||||
let contractAddress = responseJson["contractAddress"].getStr
|
let contractAddress = responseJson["contractAddress"].getStr
|
||||||
let communityId = responseJson["communityId"].getStr
|
let communityId = responseJson["communityId"].getStr
|
||||||
let resultJson = responseJson["result"]
|
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)
|
let data = CommunityTokenOwnersArgs(chainId: chainId, contractAddress: contractAddress, communityId: communityId, owners: owners)
|
||||||
self.events.emit(SIGNAL_COMMUNITY_TOKEN_OWNERS_FETCHED, data)
|
self.events.emit(SIGNAL_COMMUNITY_TOKEN_OWNERS_FETCHED, data)
|
||||||
|
|
||||||
|
@ -369,6 +506,9 @@ QtObject:
|
||||||
if token.transferable:
|
if token.transferable:
|
||||||
self.fetchCommunityOwners(token.communityId, token.chainId, token.address)
|
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) =
|
proc fetchAllTokenOwners*(self: Service) =
|
||||||
let allTokens = self.getAllCommunityTokens()
|
let allTokens = self.getAllCommunityTokens()
|
||||||
for token in allTokens:
|
for token in allTokens:
|
||||||
|
|
|
@ -18,6 +18,7 @@ type
|
||||||
WalletTransfer = "WalletTransfer"
|
WalletTransfer = "WalletTransfer"
|
||||||
CollectibleDeployment = "CollectibleDeployment"
|
CollectibleDeployment = "CollectibleDeployment"
|
||||||
CollectibleAirdrop = "CollectibleAirdrop"
|
CollectibleAirdrop = "CollectibleAirdrop"
|
||||||
|
CollectibleRemoteSelfDestruct = "CollectibleRemoteSelfDestruct"
|
||||||
|
|
||||||
proc event*(self:PendingTransactionTypeDto):string =
|
proc event*(self:PendingTransactionTypeDto):string =
|
||||||
result = "transaction:" & $self
|
result = "transaction:" & $self
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import json
|
import json, stint
|
||||||
|
import std/sequtils
|
||||||
|
import std/sugar
|
||||||
import ./eth
|
import ./eth
|
||||||
import ../app_service/common/utils
|
import ../app_service/common/utils
|
||||||
import ./core, ./response_type
|
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]
|
let payload = %* [chainId, contractAddress, txData, utils.hashPassword(password), walletAddresses, amount]
|
||||||
return core.callPrivateRPC("collectibles_mintTo", payload)
|
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].} =
|
proc contractOwner*(chainId: int, contractAddress: string): RpcResponse[JsonNode] {.raises: [Exception].} =
|
||||||
let payload = %* [chainId, contractAddress]
|
let payload = %* [chainId, contractAddress]
|
||||||
return core.callPrivateRPC("collectibles_contractOwner", payload)
|
return core.callPrivateRPC("collectibles_contractOwner", payload)
|
||||||
|
|
|
@ -67,12 +67,11 @@ SettingsPageLayout {
|
||||||
|
|
||||||
signal signMintTransactionOpened(int chainId, string accountAddress)
|
signal signMintTransactionOpened(int chainId, string accountAddress)
|
||||||
|
|
||||||
signal signSelfDestructTransactionOpened(int chainId)
|
signal signSelfDestructTransactionOpened(var selfDestructTokensList, // [key , amount]
|
||||||
|
string contractUniqueKey)
|
||||||
|
|
||||||
signal remoteSelfDestructCollectibles(var selfDestructTokensList, // [key , amount]
|
signal remoteSelfDestructCollectibles(var selfDestructTokensList, // [key , amount]
|
||||||
int chainId,
|
string contractUniqueKey)
|
||||||
string accountName,
|
|
||||||
string accountAddress)
|
|
||||||
|
|
||||||
signal signBurnTransactionOpened(int chainId)
|
signal signBurnTransactionOpened(int chainId)
|
||||||
|
|
||||||
|
@ -109,6 +108,7 @@ SettingsPageLayout {
|
||||||
property string accountName
|
property string accountName
|
||||||
property int chainId
|
property int chainId
|
||||||
property string chainName
|
property string chainName
|
||||||
|
property string contractUniqueKey
|
||||||
|
|
||||||
property var tokenOwnersModel
|
property var tokenOwnersModel
|
||||||
property var selfDestructTokensList
|
property var selfDestructTokensList
|
||||||
|
@ -436,13 +436,9 @@ SettingsPageLayout {
|
||||||
property bool isRemotelyDestructTransaction
|
property bool isRemotelyDestructTransaction
|
||||||
|
|
||||||
function signTransaction() {
|
function signTransaction() {
|
||||||
root.isFeeLoading = true
|
root.setFeeLoading()
|
||||||
root.feeText = ""
|
|
||||||
if(signTransactionPopup.isRemotelyDestructTransaction) {
|
if(signTransactionPopup.isRemotelyDestructTransaction) {
|
||||||
root.remoteSelfDestructCollectibles(d.selfDestructTokensList,
|
root.remoteSelfDestructCollectibles(d.selfDestructTokensList, d.contractUniqueKey)
|
||||||
d.chainId,
|
|
||||||
d.accountName,
|
|
||||||
d.accountAddress)
|
|
||||||
} else {
|
} else {
|
||||||
root.burnCollectibles("TODO - KEY"/*d.tokenKey*/, d.burnAmount)
|
root.burnCollectibles("TODO - KEY"/*d.tokenKey*/, d.burnAmount)
|
||||||
}
|
}
|
||||||
|
@ -457,9 +453,13 @@ SettingsPageLayout {
|
||||||
networkName: d.chainName
|
networkName: d.chainName
|
||||||
feeText: root.feeText
|
feeText: root.feeText
|
||||||
isFeeLoading: root.isFeeLoading
|
isFeeLoading: root.isFeeLoading
|
||||||
|
errorText: root.errorText
|
||||||
|
|
||||||
onOpened: signTransactionPopup.isRemotelyDestructTransaction ? root.signSelfDestructTransactionOpened(d.chainId) :
|
onOpened: {
|
||||||
root.signBurnTransactionOpened(d.chainId)
|
root.setFeeLoading()
|
||||||
|
signTransactionPopup.isRemotelyDestructTransaction ? root.signSelfDestructTransactionOpened(d.selfDestructTokensList, d.contractUniqueKey) :
|
||||||
|
root.signBurnTransactionOpened(d.chainId)
|
||||||
|
}
|
||||||
onCancelClicked: close()
|
onCancelClicked: close()
|
||||||
onSignTransactionClicked: signTransaction()
|
onSignTransactionClicked: signTransaction()
|
||||||
}
|
}
|
||||||
|
@ -490,6 +490,7 @@ SettingsPageLayout {
|
||||||
onItemClicked: {
|
onItemClicked: {
|
||||||
d.accountAddress = accountAddress
|
d.accountAddress = accountAddress
|
||||||
d.chainId = chainId
|
d.chainId = chainId
|
||||||
|
d.contractUniqueKey = contractUniqueKey
|
||||||
d.chainName = chainName
|
d.chainName = chainName
|
||||||
d.accountName = accountName
|
d.accountName = accountName
|
||||||
//d.tokenKey = key // TODO: Backend key role
|
//d.tokenKey = key // TODO: Backend key role
|
||||||
|
|
|
@ -275,6 +275,25 @@ StatusSectionLayout {
|
||||||
readonly property CommunityTokensStore communityTokensStore:
|
readonly property CommunityTokensStore communityTokensStore:
|
||||||
rootStore.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
|
communityName: root.community.name
|
||||||
tokensModel: root.community.communityTokens
|
tokensModel: root.community.communityTokens
|
||||||
layer1Networks: communityTokensStore.layer1Networks
|
layer1Networks: communityTokensStore.layer1Networks
|
||||||
|
@ -315,12 +334,11 @@ StatusSectionLayout {
|
||||||
accountName,
|
accountName,
|
||||||
artworkCropRect)
|
artworkCropRect)
|
||||||
}
|
}
|
||||||
onSignSelfDestructTransactionOpened: communityTokensStore.computeSelfDestructFee(chainId)
|
onSignSelfDestructTransactionOpened: communityTokensStore.computeSelfDestructFee(selfDestructTokensList, contractUniqueKey)
|
||||||
onRemoteSelfDestructCollectibles: {
|
onRemoteSelfDestructCollectibles: {
|
||||||
communityTokensStore.remoteSelfDestructCollectibles(selfDestructTokensList,
|
communityTokensStore.remoteSelfDestructCollectibles(root.community.id,
|
||||||
chainId,
|
selfDestructTokensList,
|
||||||
accountName,
|
contractUniqueKey)
|
||||||
accountAddress)
|
|
||||||
}
|
}
|
||||||
onSignBurnTransactionOpened: communityTokensStore.computeBurnFee(chainId)
|
onSignBurnTransactionOpened: communityTokensStore.computeBurnFee(chainId)
|
||||||
onBurnCollectibles: communityTokensStore.burnCollectibles(tokenKey, amount)
|
onBurnCollectibles: communityTokensStore.burnCollectibles(tokenKey, amount)
|
||||||
|
@ -329,22 +347,43 @@ StatusSectionLayout {
|
||||||
Connections {
|
Connections {
|
||||||
target: rootStore.communityTokensStore
|
target: rootStore.communityTokensStore
|
||||||
function onDeployFeeUpdated(ethCurrency, fiatCurrency, errorCode) {
|
function onDeployFeeUpdated(ethCurrency, fiatCurrency, errorCode) {
|
||||||
if (errorCode === Constants.ComputeFeeErrorCode.Success || errorCode === Constants.ComputeFeeErrorCode.Balance) {
|
mintPanel.setFeesInfo(ethCurrency, fiatCurrency, errorCode)
|
||||||
let valueStr = LocaleUtils.currencyAmountToLocaleString(ethCurrency) + "(" + LocaleUtils.currencyAmountToLocaleString(fiatCurrency) + ")"
|
}
|
||||||
mintPanel.feeText = valueStr
|
|
||||||
if (errorCode === Constants.ComputeFeeErrorCode.Balance) {
|
function onSelfDestructFeeUpdated(ethCurrency, fiatCurrency, errorCode) {
|
||||||
mintPanel.errorText = qsTr("Not enough funds to make transaction")
|
mintPanel.setFeesInfo(ethCurrency, fiatCurrency, errorCode)
|
||||||
}
|
}
|
||||||
mintPanel.isFeeLoading = false
|
|
||||||
return
|
function onRemoteDestructStateChanged(communityId, tokenName, status, url) {
|
||||||
} else if (errorCode === Constants.ComputeFeeErrorCode.Infura) {
|
if (root.community.id !== communityId) {
|
||||||
mintPanel.errorText = qsTr("Infura error")
|
|
||||||
mintPanel.isFeeLoading = true
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
mintPanel.errorText = qsTr("Unknown error")
|
let title = ""
|
||||||
mintPanel.isFeeLoading = true
|
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) {
|
function onDeploymentStateChanged(communityId, status, url) {
|
||||||
|
@ -356,15 +395,15 @@ StatusSectionLayout {
|
||||||
let loading = false
|
let loading = false
|
||||||
let type = Constants.ephemeralNotificationType.normal
|
let type = Constants.ephemeralNotificationType.normal
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case Constants.BackendProcessState.InProgress:
|
case Constants.ContractTransactionStatus.InProgress:
|
||||||
title = qsTr("Token is being minted...")
|
title = qsTr("Token is being minted...")
|
||||||
loading = true
|
loading = true
|
||||||
break
|
break
|
||||||
case Constants.BackendProcessState.Completed:
|
case Constants.ContractTransactionStatus.Completed:
|
||||||
title = qsTr("Token minting finished")
|
title = qsTr("Token minting finished")
|
||||||
type = Constants.ephemeralNotificationType.success
|
type = Constants.ephemeralNotificationType.success
|
||||||
break
|
break
|
||||||
case Constants.BackendProcessState.Failed:
|
case Constants.ContractTransactionStatus.Failed:
|
||||||
title = qsTr("Token minting failed")
|
title = qsTr("Token minting failed")
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -17,6 +17,7 @@ StatusScrollView {
|
||||||
|
|
||||||
signal itemClicked(int index,
|
signal itemClicked(int index,
|
||||||
int chainId,
|
int chainId,
|
||||||
|
string contractUniqueKey,
|
||||||
string chainName,
|
string chainName,
|
||||||
string accountName,
|
string accountName,
|
||||||
string accountAddress)
|
string accountAddress)
|
||||||
|
@ -25,11 +26,11 @@ StatusScrollView {
|
||||||
id: d
|
id: d
|
||||||
|
|
||||||
function getSubtitle(deployState, remainingTokens, supply) {
|
function getSubtitle(deployState, remainingTokens, supply) {
|
||||||
if(deployState === Constants.BackendProcessState.Failed) {
|
if(deployState === Constants.ContractTransactionStatus.Failed) {
|
||||||
return qsTr("Minting failed")
|
return qsTr("Minting failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
if(deployState === Constants.BackendProcessState.InProgress) {
|
if(deployState === Constants.ContractTransactionStatus.InProgress) {
|
||||||
return qsTr("Minting...")
|
return qsTr("Minting...")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,13 +72,13 @@ StatusScrollView {
|
||||||
width: gridView.cellWidth
|
width: gridView.cellWidth
|
||||||
title: model.name ? model.name : "..."
|
title: model.name ? model.name : "..."
|
||||||
subTitle: d.getSubtitle(model.deployState, model.remainingTokens, model.supply)
|
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 : ""
|
fallbackImageUrl: model.image ? model.image : ""
|
||||||
backgroundColor: model.backgroundColor ? model.backgroundColor : "transparent" // TODO BACKEND
|
backgroundColor: model.backgroundColor ? model.backgroundColor : "transparent" // TODO BACKEND
|
||||||
isLoading: false
|
isLoading: false
|
||||||
navigationIconVisible: true
|
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 var tokenOwnersModel
|
||||||
|
|
||||||
property int deployState: Constants.BackendProcessState.None
|
property int deployState: Constants.ContractTransactionStatus.None
|
||||||
property int burnState: Constants.BackendProcessState.None
|
property int burnState: Constants.ContractTransactionStatus.None
|
||||||
|
|
||||||
// Collectible object properties (ERC721)
|
// Collectible object properties (ERC721)
|
||||||
property bool transferable
|
property bool transferable
|
||||||
property bool selfDestruct
|
property bool selfDestruct
|
||||||
property int remotelyDestructState: Constants.BackendProcessState.None
|
property int remotelyDestructState: Constants.ContractTransactionStatus.None
|
||||||
|
|
||||||
// Asset properties (ERC20)
|
// Asset properties (ERC20)
|
||||||
property alias assetDecimals: decimalsBox.value
|
property alias assetDecimals: decimalsBox.value
|
||||||
|
@ -88,8 +88,8 @@ StatusScrollView {
|
||||||
contentHeight: mainLayout.height
|
contentHeight: mainLayout.height
|
||||||
padding: 0
|
padding: 0
|
||||||
|
|
||||||
onRemotelyDestructStateChanged: if(remotelyDestructState === Constants.BackendProcessState.Completed) d.startAnimation(false)
|
onRemotelyDestructStateChanged: if(remotelyDestructState === Constants.ContractTransactionStatus.Completed) d.startAnimation(false)
|
||||||
onBurnStateChanged: if(burnState === Constants.BackendProcessState.Completed) d.startAnimation(true)
|
onBurnStateChanged: if(burnState === Constants.ContractTransactionStatus.Completed) d.startAnimation(true)
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: mainLayout
|
id: mainLayout
|
||||||
|
@ -98,16 +98,16 @@ StatusScrollView {
|
||||||
spacing: Style.current.padding
|
spacing: Style.current.padding
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
visible: !root.preview && ((root.deployState === Constants.BackendProcessState.InProgress) ||
|
visible: !root.preview && ((root.deployState === Constants.ContractTransactionStatus.InProgress) ||
|
||||||
(root.deployState === Constants.BackendProcessState.Failed))
|
(root.deployState === Constants.ContractTransactionStatus.Failed))
|
||||||
spacing: Style.current.halfPadding
|
spacing: Style.current.halfPadding
|
||||||
|
|
||||||
StatusDotsLoadingIndicator {
|
StatusDotsLoadingIndicator {
|
||||||
visible: (root.deployState === Constants.BackendProcessState.InProgress)
|
visible: (root.deployState === Constants.ContractTransactionStatus.InProgress)
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusIcon {
|
StatusIcon {
|
||||||
visible: (root.deployState === Constants.BackendProcessState.Failed)
|
visible: (root.deployState === Constants.ContractTransactionStatus.Failed)
|
||||||
icon: "warning"
|
icon: "warning"
|
||||||
color: Theme.palette.dangerColor1
|
color: Theme.palette.dangerColor1
|
||||||
}
|
}
|
||||||
|
@ -115,12 +115,12 @@ StatusScrollView {
|
||||||
StatusBaseText {
|
StatusBaseText {
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
font.pixelSize: Theme.primaryTextFontSize
|
font.pixelSize: Theme.primaryTextFontSize
|
||||||
text: (root.deployState === Constants.BackendProcessState.InProgress) ?
|
text: (root.deployState === Constants.ContractTransactionStatus.InProgress) ?
|
||||||
(root.isAssetView ?
|
(root.isAssetView ?
|
||||||
qsTr("Asset is being minted") : qsTr("Collectible is being minted")) :
|
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")) : ""
|
(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")
|
label: qsTr("Total")
|
||||||
value: root.infiniteSupply ? d.infiniteSymbol : LocaleUtils.numberToLocaleString(root.supplyAmount)
|
value: root.infiniteSupply ? d.infiniteSymbol : LocaleUtils.numberToLocaleString(root.supplyAmount)
|
||||||
isLoading: !root.infiniteSupply &&
|
isLoading: !root.infiniteSupply &&
|
||||||
((root.remotelyDestructState === Constants.BackendProcessState.InProgress) ||
|
((root.remotelyDestructState === Constants.ContractTransactionStatus.InProgress) ||
|
||||||
(root.burnState === Constants.BackendProcessState.InProgress))
|
(root.burnState === Constants.ContractTransactionStatus.InProgress))
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomPreviewBox {
|
CustomPreviewBox {
|
||||||
|
@ -248,7 +248,7 @@ StatusScrollView {
|
||||||
|
|
||||||
label: qsTr("Remaining")
|
label: qsTr("Remaining")
|
||||||
value: root.infiniteSupply ? d.infiniteSymbol : LocaleUtils.numberToLocaleString(root.remainingTokens)
|
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 {
|
CustomPreviewBox {
|
||||||
|
|
|
@ -14,10 +14,14 @@ QtObject {
|
||||||
property var allNetworks: networksModule.all
|
property var allNetworks: networksModule.all
|
||||||
|
|
||||||
signal deployFeeUpdated(var ethCurrency, var fiatCurrency, int error)
|
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 deploymentStateChanged(string communityId, int status, string url)
|
||||||
signal selfDestructFeeUpdated(string value) // TO BE REMOVED
|
|
||||||
signal burnFeeUpdated(string value) // TO BE REMOVED
|
signal burnFeeUpdated(string value) // TO BE REMOVED
|
||||||
|
|
||||||
|
signal remoteDestructStateChanged(string communityId, string tokenName, int status, string url)
|
||||||
|
|
||||||
// Minting tokens:
|
// Minting tokens:
|
||||||
function deployCollectible(communityId, accountAddress, name, symbol, description, supply,
|
function deployCollectible(communityId, accountAddress, name, symbol, description, supply,
|
||||||
infiniteSupply, transferable, selfDestruct, chainId, artworkSource, accountName, artworkCropRect)
|
infiniteSupply, transferable, selfDestruct, chainId, artworkSource, accountName, artworkCropRect)
|
||||||
|
@ -43,26 +47,27 @@ QtObject {
|
||||||
function onDeployFeeUpdated(ethCurrency, fiatCurrency, errorCode) {
|
function onDeployFeeUpdated(ethCurrency, fiatCurrency, errorCode) {
|
||||||
root.deployFeeUpdated(ethCurrency, fiatCurrency, errorCode)
|
root.deployFeeUpdated(ethCurrency, fiatCurrency, errorCode)
|
||||||
}
|
}
|
||||||
|
function onSelfDestructFeeUpdated(ethCurrency, fiatCurrency, errorCode) {
|
||||||
|
root.selfDestructFeeUpdated(ethCurrency, fiatCurrency, errorCode)
|
||||||
|
}
|
||||||
function onDeploymentStateChanged(communityId, status, url) {
|
function onDeploymentStateChanged(communityId, status, url) {
|
||||||
root.deploymentStateChanged(communityId, status, url)
|
root.deploymentStateChanged(communityId, status, url)
|
||||||
}
|
}
|
||||||
|
function onRemoteDestructStateChanged(communityId, tokenName, status, url) {
|
||||||
|
root.remoteDestructStateChanged(communityId, tokenName, status, url)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeDeployFee(chainId, accountAddress) {
|
function computeDeployFee(chainId, accountAddress) {
|
||||||
communityTokensModuleInst.computeDeployFee(chainId, accountAddress)
|
communityTokensModuleInst.computeDeployFee(chainId, accountAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remotely destruct:
|
function computeSelfDestructFee(selfDestructTokensList, contractUniqueKey) {
|
||||||
function computeSelfDestructFee(chainId) {
|
communityTokensModuleInst.computeSelfDestructFee(JSON.stringify(selfDestructTokensList), contractUniqueKey)
|
||||||
// TODO BACKEND
|
|
||||||
root.selfDestructFeeUpdated("0,0005 ETH")
|
|
||||||
console.warn("TODO: Compute self-destruct fee backend")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function remoteSelfDestructCollectibles(selfDestructTokensList, chainId, accountName, accountAddress) {
|
function remoteSelfDestructCollectibles(communityId, selfDestructTokensList, contractUniqueKey) {
|
||||||
// TODO BACKEND
|
communityTokensModuleInst.selfDestructCollectibles(communityId, JSON.stringify(selfDestructTokensList), contractUniqueKey)
|
||||||
// selfDestructTokensList is a js array with properties: `walletAddress` and `amount`
|
|
||||||
console.warn("TODO: Remote self-destruct collectible backend")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Burn:
|
// Burn:
|
||||||
|
|
|
@ -893,7 +893,8 @@ QtObject {
|
||||||
Everyone = 4
|
Everyone = 4
|
||||||
}
|
}
|
||||||
|
|
||||||
enum BackendProcessState {
|
// refers to ContractTransactionStatus and DeployState in Nim
|
||||||
|
enum ContractTransactionStatus {
|
||||||
Failed,
|
Failed,
|
||||||
InProgress,
|
InProgress,
|
||||||
Completed,
|
Completed,
|
||||||
|
|
Loading…
Reference in New Issue