From f2f78bf67509bc600b0ee54b4976aa3fe744832d Mon Sep 17 00:00:00 2001 From: Michal Iskierko Date: Wed, 21 Jun 2023 13:22:11 +0200 Subject: [PATCH] feat(@desktop/communities): Burn and mint functionality for assets. Adjst burning and minting flows to handle assets. Supplies are passed from qml to nim as strings - "2" for ERC721, "1.5" for ERC20 String amounts are converted to Uint256 type. Additionally ERC20 amounts are converted to basic units (wei-like, decimals=18). Uint256 values are passed to backend functions and then coverted to strings which can be converted to bigInt.BigInt types. Supply and RemainingSupply are exposed to qml as floats. Issue #11129 --- .../main/communities/tokens/controller.nim | 15 ++--- .../main/communities/tokens/io_interface.nim | 12 ++-- .../communities/tokens/models/token_item.nim | 6 +- .../communities/tokens/models/token_model.nim | 10 ++-- .../main/communities/tokens/module.nim | 59 ++++++++++++------- .../modules/main/communities/tokens/view.nim | 18 +++--- src/app/modules/main/controller.nim | 6 +- src/app/modules/main/io_interface.nim | 4 +- src/app/modules/main/module.nim | 6 +- .../modules/shared_models/section_item.nim | 6 +- .../service/community_tokens/async_tasks.nim | 4 +- .../community_tokens/dto/community_token.nim | 23 ++++++-- .../dto/deployment_parameters.nim | 6 +- .../service/community_tokens/service.nim | 28 ++++----- src/backend/community_tokens.nim | 24 ++++---- .../shared/stores/CommunityTokensStore.qml | 8 +-- 16 files changed, 131 insertions(+), 104 deletions(-) diff --git a/src/app/modules/main/communities/tokens/controller.nim b/src/app/modules/main/communities/tokens/controller.nim index e6e50359a2f..eb781ad264e 100644 --- a/src/app/modules/main/communities/tokens/controller.nim +++ b/src/app/modules/main/communities/tokens/controller.nim @@ -1,3 +1,4 @@ +import stint import ./io_interface as community_tokens_module_interface import ../../../../../app_service/service/community_tokens/service as community_tokens_service @@ -73,17 +74,17 @@ proc init*(self: Controller) = proc deployContract*(self: Controller, communityId: string, addressFrom: string, password: string, deploymentParams: DeploymentParameters, tokenMetadata: CommunityTokensMetadataDto, tokenImageCropInfoJson: string, chainId: int) = self.communityTokensService.deployContract(communityId, addressFrom, password, deploymentParams, tokenMetadata, tokenImageCropInfoJson, chainId) -proc airdropCollectibles*(self: Controller, communityId: string, password: string, collectiblesAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) = - self.communityTokensService.airdropCollectibles(communityId, password, collectiblesAndAmounts, walletAddresses) +proc airdropTokens*(self: Controller, communityId: string, password: string, collectiblesAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) = + self.communityTokensService.airdropTokens(communityId, password, collectiblesAndAmounts, walletAddresses) -proc computeAirdropCollectiblesFee*(self: Controller, collectiblesAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) = - self.communityTokensService.computeAirdropCollectiblesFee(collectiblesAndAmounts, walletAddresses) +proc computeAirdropFee*(self: Controller, collectiblesAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) = + self.communityTokensService.computeAirdropFee(collectiblesAndAmounts, walletAddresses) proc selfDestructCollectibles*(self: Controller, communityId: string, password: string, walletAndAmounts: seq[WalletAndAmount], contractUniqueKey: string) = self.communityTokensService.selfDestructCollectibles(communityId, password, walletAndAmounts, contractUniqueKey) -proc burnCollectibles*(self: Controller, communityId: string, password: string, contractUniqueKey: string, amount: int) = - self.communityTokensService.burnCollectibles(communityId, password, contractUniqueKey, amount) +proc burnTokens*(self: Controller, communityId: string, password: string, contractUniqueKey: string, amount: Uint256) = + self.communityTokensService.burnTokens(communityId, password, contractUniqueKey, amount) proc authenticateUser*(self: Controller, keyUid = "") = let data = SharedKeycarModuleAuthenticationArgs(uniqueIdentifier: UNIQUE_DEPLOY_COLLECTIBLES_COMMUNITY_TOKENS_MODULE_IDENTIFIER, keyUid: keyUid) @@ -101,7 +102,7 @@ proc computeSelfDestructFee*(self: Controller, walletAndAmountList: seq[WalletAn proc findContractByUniqueId*(self: Controller, contractUniqueKey: string): CommunityTokenDto = return self.communityTokensService.findContractByUniqueId(contractUniqueKey) -proc computeBurnFee*(self: Controller, contractUniqueKey: string, amount: int) = +proc computeBurnFee*(self: Controller, contractUniqueKey: string, amount: Uint256) = self.communityTokensService.computeBurnFee(contractUniqueKey, amount) proc getNetwork*(self:Controller, chainId: int): NetworkDto = diff --git a/src/app/modules/main/communities/tokens/io_interface.nim b/src/app/modules/main/communities/tokens/io_interface.nim index 27f8c01e7bf..a86d6572e76 100644 --- a/src/app/modules/main/communities/tokens/io_interface.nim +++ b/src/app/modules/main/communities/tokens/io_interface.nim @@ -11,23 +11,23 @@ method delete*(self: AccessInterface) {.base.} = method load*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") -method airdropCollectibles*(self: AccessInterface, communityId: string, collectiblesJsonString: string, walletsJsonString: string) {.base.} = +method airdropTokens*(self: AccessInterface, communityId: string, tokensJsonString: string, walletsJsonString: string) {.base.} = raise newException(ValueError, "No implementation available") -method computeAirdropCollectiblesFee*(self: AccessInterface, communityId: string, collectiblesJsonString: string, walletsJsonString: string) {.base.} = +method computeAirdropFee*(self: AccessInterface, communityId: string, tokensJsonString: 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 burnCollectibles*(self: AccessInterface, communityId: string, contractUniqueKey: string, amount: int) {.base.} = +method burnTokens*(self: AccessInterface, communityId: string, contractUniqueKey: string, amount: float64) {.base.} = raise newException(ValueError, "No implementation available") -method deployCollectibles*(self: AccessInterface, communityId: string, address: string, name: string, symbol: string, description: string, supply: int, infiniteSupply: bool, transferable: bool, +method deployCollectibles*(self: AccessInterface, communityId: string, address: string, name: string, symbol: string, description: string, supply: float64, infiniteSupply: bool, transferable: bool, selfDestruct: bool, chainId: int, imageCropInfoJson: string) {.base.} = raise newException(ValueError, "No implementation available") -method deployAssets*(self: AccessInterface, communityId: string, address: string, name: string, symbol: string, description: string, supply: int, infiniteSupply: bool, decimals: int, +method deployAssets*(self: AccessInterface, communityId: string, address: string, name: string, symbol: string, description: string, supply: float64, infiniteSupply: bool, decimals: int, chainId: int, imageCropInfoJson: string) {.base.} = raise newException(ValueError, "No implementation available") @@ -43,7 +43,7 @@ method computeDeployFee*(self: AccessInterface, chainId: int, accountAddress: st method computeSelfDestructFee*(self: AccessInterface, collectiblesToBurnJsonString: string, contractUniqueKey: string) {.base.} = raise newException(ValueError, "No implementation available") -method computeBurnFee*(self: AccessInterface, contractUniqueKey: string, amount: int) {.base.} = +method computeBurnFee*(self: AccessInterface, contractUniqueKey: string, amount: float64) {.base.} = raise newException(ValueError, "No implementation available") method onDeployFeeComputed*(self: AccessInterface, ethCurrency: CurrencyAmount, fiatCurrency: CurrencyAmount, errorCode: ComputeFeeErrorCode) {.base.} = diff --git a/src/app/modules/main/communities/tokens/models/token_item.nim b/src/app/modules/main/communities/tokens/models/token_item.nim index ba02e5ab1d5..cd70440dfea 100644 --- a/src/app/modules/main/communities/tokens/models/token_item.nim +++ b/src/app/modules/main/communities/tokens/models/token_item.nim @@ -1,4 +1,4 @@ -import strformat, sequtils +import strformat, sequtils, stint import ../../../../../../app_service/service/community_tokens/dto/community_token import ../../../../../../app_service/service/collectible/dto import ../../../../../../app_service/service/network/dto @@ -14,7 +14,7 @@ type chainName*: string chainIcon*: string accountName*: string - remainingSupply*: int + remainingSupply*: Uint256 tokenOwnersModel*: token_owners_model.TokenOwnersModel proc initTokenItem*( @@ -22,7 +22,7 @@ proc initTokenItem*( network: NetworkDto, tokenOwners: seq[CollectibleOwner], accountName: string, - remainingSupply: int + remainingSupply: Uint256 ): TokenItem = result.tokenDto = tokenDto if network != nil: diff --git a/src/app/modules/main/communities/tokens/models/token_model.nim b/src/app/modules/main/communities/tokens/models/token_model.nim index 3a6d6332c75..3e33a89e791 100644 --- a/src/app/modules/main/communities/tokens/models/token_model.nim +++ b/src/app/modules/main/communities/tokens/models/token_model.nim @@ -1,4 +1,4 @@ -import NimQml, Tables, strformat, sequtils +import NimQml, Tables, strformat, sequtils, stint import token_item import token_owners_item import token_owners_model @@ -52,7 +52,7 @@ QtObject: self.dataChanged(index, index, @[ModelRole.DeployState.int]) return - proc updateSupply*(self: TokenModel, chainId: int, contractAddress: string, supply: int) = + proc updateSupply*(self: TokenModel, chainId: int, contractAddress: string, supply: Uint256) = for i in 0 ..< self.items.len: if((self.items[i].tokenDto.address == contractAddress) and (self.items[i].tokenDto.chainId == chainId)): if self.items[i].tokenDto.supply != supply: @@ -62,7 +62,7 @@ QtObject: self.dataChanged(index, index, @[ModelRole.Supply.int]) return - proc updateRemainingSupply*(self: TokenModel, chainId: int, contractAddress: string, remainingSupply: int) = + proc updateRemainingSupply*(self: TokenModel, chainId: int, contractAddress: string, remainingSupply: Uint256) = for i in 0 ..< self.items.len: if((self.items[i].tokenDto.address == contractAddress) and (self.items[i].tokenDto.chainId == chainId)): if self.items[i].remainingSupply != remainingSupply: @@ -155,7 +155,7 @@ QtObject: of ModelRole.Description: result = newQVariant(item.tokenDto.description) of ModelRole.Supply: - result = newQVariant(item.tokenDto.supply) + result = newQVariant(supplyByType(item.tokenDto.supply, item.tokenDto.tokenType)) of ModelRole.InfiniteSupply: result = newQVariant(item.tokenDto.infiniteSupply) of ModelRole.Transferable: @@ -177,7 +177,7 @@ QtObject: of ModelRole.AccountName: result = newQVariant(item.accountName) of ModelRole.RemainingSupply: - result = newQVariant(item.remainingSupply) + result = newQVariant(supplyByType(item.remainingSupply, item.tokenDto.tokenType)) of ModelRole.Decimals: result = newQVariant(item.tokenDto.decimals) diff --git a/src/app/modules/main/communities/tokens/module.nim b/src/app/modules/main/communities/tokens/module.nim index 8891cc6cae3..0107f04124d 100644 --- a/src/app/modules/main/communities/tokens/module.nim +++ b/src/app/modules/main/communities/tokens/module.nim @@ -5,6 +5,7 @@ import ../../../../../app_service/service/transaction/service as transaction_ser import ../../../../../app_service/service/network/service as networks_service import ../../../../../app_service/service/community/dto/community import ../../../../../app_service/service/accounts/utils as utl +import ../../../../../app_service/common/conversion import ../../../../core/eventemitter import ../../../../global/global_singleton import ../../../shared_models/currency_amount @@ -39,7 +40,7 @@ type tempWalletAddresses: seq[string] tempContractAction: ContractAction tempContractUniqueKey: string - tempAmount: int + tempAmount: Uint256 proc newCommunityTokensModule*( parent: parent_interface.AccessInterface, @@ -84,22 +85,34 @@ proc authenticate(self: Module) = else: self.controller.authenticateUser() -proc getTokenAndAmountList(self: Module, communityId: string, collectiblesJsonString: string): seq[CommunityTokenAndAmount] = +# for collectibles conversion is: "1" -> Uint256(1) +# for assets amount is converted to basic units (wei-like): "1.5" -> Uint256(1500000000000000000) +proc convertAmountByTokenType(self: Module, tokenType: TokenType, amount: float64): Uint256 = + const decimals = 18 + case tokenType + of TokenType.ERC721: + return stint.parse($amount, Uint256) + of TokenType.ERC20: + return conversion.eth2Wei(amount, decimals) + else: + error "Converting amount - unknown token type", tokenType=tokenType + +proc getTokenAndAmountList(self: Module, communityId: string, tokensJsonString: string): seq[CommunityTokenAndAmount] = try: - let collectiblesJson = collectiblesJsonString.parseJson - for collectible in collectiblesJson: - let contractUniqueKey = collectible["contractUniqueKey"].getStr - let amount = collectible["amount"].getInt + let tokensJson = tokensJsonString.parseJson + for token in tokensJson: + let contractUniqueKey = token["contractUniqueKey"].getStr let tokenDto = self.controller.findContractByUniqueId(contractUniqueKey) + let amountStr = token["amount"].getFloat if tokenDto.tokenType == TokenType.Unknown: error "Can't find token for community", contractUniqueKey=contractUniqueKey return @[] - result.add(CommunityTokenAndAmount(communityToken: tokenDto, amount: amount)) + result.add(CommunityTokenAndAmount(communityToken: tokenDto, amount: self.convertAmountByTokenType(tokenDto.tokenType, amountStr))) except Exception as e: error "Error getTokenAndAmountList", msg = e.msg -method airdropCollectibles*(self: Module, communityId: string, collectiblesJsonString: string, walletsJsonString: string) = - self.tempTokenAndAmountList = self.getTokenAndAmountList(communityId, collectiblesJsonString) +method airdropTokens*(self: Module, communityId: string, tokensJsonString: string, walletsJsonString: string) = + self.tempTokenAndAmountList = self.getTokenAndAmountList(communityId, tokensJsonString) if len(self.tempTokenAndAmountList) == 0: return self.tempWalletAddresses = walletsJsonString.parseJson.to(seq[string]) @@ -107,9 +120,9 @@ method airdropCollectibles*(self: Module, communityId: string, collectiblesJsonS self.tempContractAction = ContractAction.Airdrop self.authenticate() -method computeAirdropCollectiblesFee*(self: Module, communityId: string, collectiblesJsonString: string, walletsJsonString: string) = - let tokenAndAmountList = self.getTokenAndAmountList(communityId, collectiblesJsonString) - self.controller.computeAirdropCollectiblesFee(tokenAndAmountList, walletsJsonString.parseJson.to(seq[string])) +method computeAirdropFee*(self: Module, communityId: string, tokensJsonString: string, walletsJsonString: string) = + let tokenAndAmountList = self.getTokenAndAmountList(communityId, tokensJsonString) + self.controller.computeAirdropFee(tokenAndAmountList, walletsJsonString.parseJson.to(seq[string])) proc getWalletAndAmountListFromJson(self: Module, collectiblesToBurnJsonString: string): seq[WalletAndAmount] = let collectiblesToBurnJson = collectiblesToBurnJsonString.parseJson @@ -125,21 +138,22 @@ method selfDestructCollectibles*(self: Module, communityId: string, collectibles self.tempContractAction = ContractAction.SelfDestruct self.authenticate() -method burnCollectibles*(self: Module, communityId: string, contractUniqueKey: string, amount: int) = +method burnTokens*(self: Module, communityId: string, contractUniqueKey: string, amount: float64) = + let tokenDto = self.controller.findContractByUniqueId(contractUniqueKey) self.tempCommunityId = communityId self.tempContractUniqueKey = contractUniqueKey - self.tempAmount = amount + self.tempAmount = self.convertAmountByTokenType(tokenDto.tokenType, amount) self.tempContractAction = ContractAction.Burn self.authenticate() method deployCollectibles*(self: Module, communityId: string, fromAddress: string, name: string, symbol: string, description: string, - supply: int, infiniteSupply: bool, transferable: bool, selfDestruct: bool, chainId: int, imageCropInfoJson: string) = + supply: float64, infiniteSupply: bool, transferable: bool, selfDestruct: bool, chainId: int, imageCropInfoJson: string) = self.tempAddressFrom = fromAddress self.tempCommunityId = communityId self.tempChainId = chainId self.tempDeploymentParams.name = name self.tempDeploymentParams.symbol = symbol - self.tempDeploymentParams.supply = supply + self.tempDeploymentParams.supply = self.convertAmountByTokenType(TokenType.ERC721, supply) self.tempDeploymentParams.infiniteSupply = infiniteSupply self.tempDeploymentParams.transferable = transferable self.tempDeploymentParams.remoteSelfDestruct = selfDestruct @@ -150,14 +164,14 @@ method deployCollectibles*(self: Module, communityId: string, fromAddress: strin self.tempContractAction = ContractAction.Deploy self.authenticate() -method deployAssets*(self: Module, communityId: string, fromAddress: string, name: string, symbol: string, description: string, supply: int, infiniteSupply: bool, decimals: int, +method deployAssets*(self: Module, communityId: string, fromAddress: string, name: string, symbol: string, description: string, supply: float64, infiniteSupply: bool, decimals: int, chainId: int, imageCropInfoJson: string) = self.tempAddressFrom = fromAddress self.tempCommunityId = communityId self.tempChainId = chainId self.tempDeploymentParams.name = name self.tempDeploymentParams.symbol = symbol - self.tempDeploymentParams.supply = supply + self.tempDeploymentParams.supply = self.convertAmountByTokenType(TokenType.ERC20, supply) self.tempDeploymentParams.infiniteSupply = infiniteSupply self.tempDeploymentParams.decimals = decimals self.tempDeploymentParams.tokenUri = utl.changeCommunityKeyCompression(communityId) & "/" @@ -176,11 +190,11 @@ method onUserAuthenticated*(self: Module, password: string) = if self.tempContractAction == ContractAction.Deploy: self.controller.deployContract(self.tempCommunityId, self.tempAddressFrom, password, self.tempDeploymentParams, self.tempTokenMetadata, self.tempTokenImageCropInfoJson, self.tempChainId) elif self.tempContractAction == ContractAction.Airdrop: - self.controller.airdropCollectibles(self.tempCommunityId, password, self.tempTokenAndAmountList, self.tempWalletAddresses) + self.controller.airdropTokens(self.tempCommunityId, password, self.tempTokenAndAmountList, self.tempWalletAddresses) elif self.tempContractAction == ContractAction.SelfDestruct: self.controller.selfDestructCollectibles(self.tempCommunityId, password, self.tempWalletAndAmountList, self.tempContractUniqueKey) elif self.tempContractAction == ContractAction.Burn: - self.controller.burnCollectibles(self.tempCommunityId, password, self.tempContractUniqueKey, self.tempAmount) + self.controller.burnTokens(self.tempCommunityId, password, self.tempContractUniqueKey, self.tempAmount) method onDeployFeeComputed*(self: Module, ethCurrency: CurrencyAmount, fiatCurrency: CurrencyAmount, errorCode: ComputeFeeErrorCode) = self.view.updateDeployFee(ethCurrency, fiatCurrency, errorCode.int) @@ -201,8 +215,9 @@ method computeSelfDestructFee*(self: Module, collectiblesToBurnJsonString: strin let walletAndAmountList = self.getWalletAndAmountListFromJson(collectiblesToBurnJsonString) self.controller.computeSelfDestructFee(walletAndAmountList, contractUniqueKey) -method computeBurnFee*(self: Module, contractUniqueKey: string, amount: int) = - self.controller.computeBurnFee(contractUniqueKey, amount) +method computeBurnFee*(self: Module, contractUniqueKey: string, amount: float64) = + let tokenDto = self.controller.findContractByUniqueId(contractUniqueKey) + self.controller.computeBurnFee(contractUniqueKey, self.convertAmountByTokenType(tokenDto.tokenType, amount)) proc createUrl(self: Module, chainId: int, transactionHash: string): string = let network = self.controller.getNetwork(chainId) diff --git a/src/app/modules/main/communities/tokens/view.nim b/src/app/modules/main/communities/tokens/view.nim index b2525a1e17a..549ce5e85bf 100644 --- a/src/app/modules/main/communities/tokens/view.nim +++ b/src/app/modules/main/communities/tokens/view.nim @@ -21,23 +21,23 @@ QtObject: result.QObject.setup result.communityTokensModule = communityTokensModule - proc deployCollectible*(self: View, communityId: string, fromAddress: string, name: string, symbol: string, description: string, supply: int, infiniteSupply: bool, transferable: bool, selfDestruct: bool, chainId: int, imageCropInfoJson: string) {.slot.} = + proc deployCollectible*(self: View, communityId: string, fromAddress: string, name: string, symbol: string, description: string, supply: float, infiniteSupply: bool, transferable: bool, selfDestruct: bool, chainId: int, imageCropInfoJson: string) {.slot.} = self.communityTokensModule.deployCollectibles(communityId, fromAddress, name, symbol, description, supply, infiniteSupply, transferable, selfDestruct, chainId, imageCropInfoJson) - proc deployAssets*(self: View, communityId: string, fromAddress: string, name: string, symbol: string, description: string, supply: int, infiniteSupply: bool, decimals: int, chainId: int, imageCropInfoJson: string) {.slot.} = + proc deployAssets*(self: View, communityId: string, fromAddress: string, name: string, symbol: string, description: string, supply: float, infiniteSupply: bool, decimals: int, chainId: int, imageCropInfoJson: string) {.slot.} = self.communityTokensModule.deployAssets(communityId, fromAddress, name, symbol, description, supply, infiniteSupply, decimals, chainId, imageCropInfoJson) - proc airdropCollectibles*(self: View, communityId: string, collectiblesJsonString: string, walletsJsonString: string) {.slot.} = - self.communityTokensModule.airdropCollectibles(communityId, collectiblesJsonString, walletsJsonString) + proc airdropTokens*(self: View, communityId: string, tokensJsonString: string, walletsJsonString: string) {.slot.} = + self.communityTokensModule.airdropTokens(communityId, tokensJsonString, walletsJsonString) - proc computeAirdropCollectiblesFee*(self: View, communityId: string, collectiblesJsonString: string, walletsJsonString: string) {.slot.} = - self.communityTokensModule.computeAirdropCollectiblesFee(communityId, collectiblesJsonString, walletsJsonString) + proc computeAirdropFee*(self: View, communityId: string, tokensJsonString: string, walletsJsonString: string) {.slot.} = + self.communityTokensModule.computeAirdropFee(communityId, tokensJsonString, walletsJsonString) proc selfDestructCollectibles*(self: View, communityId: string, collectiblesToBurnJsonString: string, contractUniqueKey: string) {.slot.} = self.communityTokensModule.selfDestructCollectibles(communityId, collectiblesToBurnJsonString, contractUniqueKey) - proc burnCollectibles*(self: View, communityId: string, contractUniqueKey: string, amount: int) {.slot.} = - self.communityTokensModule.burnCollectibles(communityId, contractUniqueKey, amount) + proc burnTokens*(self: View, communityId: string, contractUniqueKey: string, amount: float) {.slot.} = + self.communityTokensModule.burnTokens(communityId, contractUniqueKey, amount) proc deployFeeUpdated*(self: View, ethCurrency: QVariant, fiatCurrency: QVariant, errorCode: int) {.signal.} proc selfDestructFeeUpdated*(self: View, ethCurrency: QVariant, fiatCurrency: QVariant, errorCode: int) {.signal.} @@ -50,7 +50,7 @@ QtObject: proc computeSelfDestructFee*(self: View, collectiblesToBurnJsonString: string, contractUniqueKey: string) {.slot.} = self.communityTokensModule.computeSelfDestructFee(collectiblesToBurnJsonString, contractUniqueKey) - proc computeBurnFee*(self: View, contractUniqueKey: string, amount: int) {.slot.} = + proc computeBurnFee*(self: View, contractUniqueKey: string, amount: float) {.slot.} = self.communityTokensModule.computeBurnFee(contractUniqueKey, amount) proc updateDeployFee*(self: View, ethCurrency: CurrencyAmount, fiatCurrency: CurrencyAmount, errorCode: int) = diff --git a/src/app/modules/main/controller.nim b/src/app/modules/main/controller.nim index 537dcb1000e..bc21dad2f64 100644 --- a/src/app/modules/main/controller.nim +++ b/src/app/modules/main/controller.nim @@ -1,4 +1,4 @@ -import chronicles +import chronicles, stint import ../../global/app_sections_config as conf import ../../global/global_singleton import ../../global/app_signals @@ -57,7 +57,7 @@ type # Forward declaration proc setActiveSection*(self: Controller, sectionId: string, skipSavingInSettings: bool = false) -proc getRemainingSupply*(self: Controller, chainId: int, contractAddress: string): int +proc getRemainingSupply*(self: Controller, chainId: int, contractAddress: string): Uint256 proc newController*(delegate: io_interface.AccessInterface, events: EventEmitter, @@ -491,7 +491,7 @@ proc getCommunityTokenOwners*(self: Controller, communityId: string, chainId: in proc getCommunityTokenOwnerName*(self: Controller, chainId: int, contractAddress: string): string = return self.communityTokensService.contractOwnerName(chainId, contractAddress) -proc getRemainingSupply*(self: Controller, chainId: int, contractAddress: string): int = +proc getRemainingSupply*(self: Controller, chainId: int, contractAddress: string): Uint256 = return self.communityTokensService.getRemainingSupply(chainId, contractAddress) proc getNetwork*(self:Controller, chainId: int): NetworkDto = diff --git a/src/app/modules/main/io_interface.nim b/src/app/modules/main/io_interface.nim index 6edd8070559..d5d2ff11f06 100644 --- a/src/app/modules/main/io_interface.nim +++ b/src/app/modules/main/io_interface.nim @@ -1,4 +1,4 @@ -import NimQml +import NimQml, stint import ../../../app_service/service/settings/service as settings_service import ../../../app_service/service/node_configuration/service as node_configuration_service @@ -300,7 +300,7 @@ method onCommunityTokenOwnersFetched*(self: AccessInterface, communityId: string method onCommunityTokenDeployStateChanged*(self: AccessInterface, communityId: string, chainId: int, contractAddress: string, deployState: DeployState) {.base.} = raise newException(ValueError, "No implementation available") -method onCommunityTokenSupplyChanged*(self: AccessInterface, communityId: string, chainId: int, contractAddress: string, supply: int, remainingSupply: int) {.base.} = +method onCommunityTokenSupplyChanged*(self: AccessInterface, communityId: string, chainId: int, contractAddress: string, supply: Uint256, remainingSupply: Uint256) {.base.} = raise newException(ValueError, "No implementation available") method onAcceptRequestToJoinFailed*(self: AccessInterface, communityId: string, memberKey: string, requestId: string) {.base.} = diff --git a/src/app/modules/main/module.nim b/src/app/modules/main/module.nim index 8b42edb037c..1aa372befc3 100644 --- a/src/app/modules/main/module.nim +++ b/src/app/modules/main/module.nim @@ -1,4 +1,4 @@ -import NimQml, tables, json, sugar, sequtils, strformat, marshal, times, chronicles +import NimQml, tables, json, sugar, sequtils, strformat, marshal, times, chronicles, stint import io_interface, view, controller, chat_search_item, chat_search_model import ephemeral_notification_item, ephemeral_notification_model @@ -238,7 +238,7 @@ proc createTokenItem[T](self: Module[T], tokenDto: CommunityTokenDto) : TokenIte let network = self.controller.getNetwork(tokenDto.chainId) let tokenOwners = self.controller.getCommunityTokenOwners(tokenDto.communityId, tokenDto.chainId, tokenDto.address) let ownerAddressName = self.controller.getCommunityTokenOwnerName(tokenDto.chainId, tokenDto.address) - let remainingSupply = if tokenDto.infiniteSupply: 0 else: self.controller.getRemainingSupply(tokenDto.chainId, tokenDto.address) + let remainingSupply = if tokenDto.infiniteSupply: stint.parse("0", Uint256) else: self.controller.getRemainingSupply(tokenDto.chainId, tokenDto.address) result = initTokenItem(tokenDto, network, tokenOwners, ownerAddressName, remainingSupply) proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto): SectionItem = @@ -1009,7 +1009,7 @@ method onCommunityTokenDeployStateChanged*[T](self: Module[T], communityId: stri if item.id != "": item.updateCommunityTokenDeployState(chainId, contractAddress, deployState) -method onCommunityTokenSupplyChanged*[T](self: Module[T], communityId: string, chainId: int, contractAddress: string, supply: int, remainingSupply: int) = +method onCommunityTokenSupplyChanged*[T](self: Module[T], communityId: string, chainId: int, contractAddress: string, supply: Uint256, remainingSupply: Uint256) = let item = self.view.model().getItemById(communityId) if item.id != "": item.updateCommunityTokenSupply(chainId, contractAddress, supply) diff --git a/src/app/modules/shared_models/section_item.nim b/src/app/modules/shared_models/section_item.nim index f4e64815ce7..b756ce99ac4 100644 --- a/src/app/modules/shared_models/section_item.nim +++ b/src/app/modules/shared_models/section_item.nim @@ -1,4 +1,4 @@ -import strformat +import strformat, stint import ./member_model, ./member_item import ../main/communities/models/[pending_request_item, pending_request_model] import ../main/communities/tokens/models/token_model as community_tokens_model @@ -328,10 +328,10 @@ proc appendCommunityToken*(self: SectionItem, item: TokenItem) {.inline.} = proc updateCommunityTokenDeployState*(self: SectionItem, chainId: int, contractAddress: string, deployState: DeployState) {.inline.} = self.communityTokensModel.updateDeployState(chainId, contractAddress, deployState) -proc updateCommunityTokenSupply*(self: SectionItem, chainId: int, contractAddress: string, supply: int) {.inline.} = +proc updateCommunityTokenSupply*(self: SectionItem, chainId: int, contractAddress: string, supply: Uint256) {.inline.} = self.communityTokensModel.updateSupply(chainId, contractAddress, supply) -proc updateCommunityRemainingSupply*(self: SectionItem, chainId: int, contractAddress: string, remainingSupply: int) {.inline.} = +proc updateCommunityRemainingSupply*(self: SectionItem, chainId: int, contractAddress: string, remainingSupply: Uint256) {.inline.} = self.communityTokensModel.updateRemainingSupply(chainId, contractAddress, remainingSupply) proc setCommunityTokenOwners*(self: SectionItem, chainId: int, contractAddress: string, owners: seq[CollectibleOwner]) {.inline.} = diff --git a/src/app_service/service/community_tokens/async_tasks.nim b/src/app_service/service/community_tokens/async_tasks.nim index 240d27da8a9..4ce57cd95d5 100644 --- a/src/app_service/service/community_tokens/async_tasks.nim +++ b/src/app_service/service/community_tokens/async_tasks.nim @@ -70,7 +70,7 @@ type AsyncGetBurnFees = ref object of QObjectTaskArg chainId: int contractAddress: string - amount: int + amount: Uint256 const asyncGetBurnFeesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = let arg = decode[AsyncGetBurnFees](argEncoded) @@ -108,7 +108,7 @@ const asyncGetMintFeesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} feeTable[chainId] = feesResponse.toSuggestedFeesDto() # get gas for smart contract - let gas = community_tokens.estimateMintTo(chainId, + let gas = community_tokens.estimateMintTokens(chainId, collectibleAndAmount.communityToken.address, arg.walletAddresses, collectibleAndAmount.amount).result.getInt gasTable[(chainId, collectibleAndAmount.communityToken.address)] = gas diff --git a/src/app_service/service/community_tokens/dto/community_token.nim b/src/app_service/service/community_tokens/dto/community_token.nim index ac9437ec7ed..17eb3a49fbc 100644 --- a/src/app_service/service/community_tokens/dto/community_token.nim +++ b/src/app_service/service/community_tokens/dto/community_token.nim @@ -1,4 +1,4 @@ -import json, sequtils +import json, sequtils, stint, strutils, chronicles import ../../../../backend/response_type include ../../../common/json_utils import ../../../common/conversion @@ -18,7 +18,7 @@ type name*: string symbol*: string description*: string - supply*: int + supply*: Uint256 infiniteSupply*: bool transferable*: bool remoteSelfDestruct*: bool @@ -36,7 +36,7 @@ proc toJsonNode*(self: CommunityTokenDto): JsonNode = "name": self.name, "symbol": self.symbol, "description": self.description, - "supply": self.supply, + "supply": self.supply.toString(10), "infiniteSupply": self.infiniteSupply, "transferable": self.transferable, "remoteSelfDestruct": self.remoteSelfDestruct, @@ -57,7 +57,9 @@ proc toCommunityTokenDto*(jsonObj: JsonNode): CommunityTokenDto = discard jsonObj.getProp("name", result.name) discard jsonObj.getProp("symbol", result.symbol) discard jsonObj.getProp("description", result.description) - discard jsonObj.getProp("supply", result.supply) + var supplyStr: string + discard jsonObj.getProp("supply", supplyStr) + result.supply = stint.parse(supplyStr, Uint256) discard jsonObj.getProp("infiniteSupply", result.infiniteSupply) discard jsonObj.getProp("transferable", result.transferable) discard jsonObj.getProp("remoteSelfDestruct", result.remoteSelfDestruct) @@ -71,4 +73,15 @@ proc toCommunityTokenDto*(jsonObj: JsonNode): CommunityTokenDto = proc parseCommunityTokens*(response: RpcResponse[JsonNode]): seq[CommunityTokenDto] = result = map(response.result.getElems(), - proc(x: JsonNode): CommunityTokenDto = x.toCommunityTokenDto()) \ No newline at end of file + proc(x: JsonNode): CommunityTokenDto = x.toCommunityTokenDto()) + +proc supplyByType*(supply: Uint256, tokenType: TokenType): float64 = + try: + var eths: string + if tokenType == TokenType.ERC20: + eths = wei2Eth(supply, 18) + else: + eths = supply.toString(10) + return parseFloat(eths) + except Exception as e: + error "Error parsing supply by type ", msg=e.msg, supply=supply, tokenType=tokenType \ No newline at end of file diff --git a/src/app_service/service/community_tokens/dto/deployment_parameters.nim b/src/app_service/service/community_tokens/dto/deployment_parameters.nim index 1061e90bd7c..5467bf4c899 100644 --- a/src/app_service/service/community_tokens/dto/deployment_parameters.nim +++ b/src/app_service/service/community_tokens/dto/deployment_parameters.nim @@ -1,10 +1,10 @@ -import json +import json, stint type DeploymentParameters* = object name*: string symbol*: string - supply*: int + supply*: Uint256 infiniteSupply*: bool transferable*: bool remoteSelfDestruct*: bool @@ -15,7 +15,7 @@ proc `%`*(x: DeploymentParameters): JsonNode = result = newJobject() result["name"] = %x.name result["symbol"] = %x.symbol - result["supply"] = %x.supply + result["supply"] = %x.supply.toString(10) result["infiniteSupply"] = %x.infiniteSupply result["transferable"] = %x.transferable result["remoteSelfDestruct"] = %x.remoteSelfDestruct diff --git a/src/app_service/service/community_tokens/service.nim b/src/app_service/service/community_tokens/service.nim index bbf0a69ce62..3346c670630 100644 --- a/src/app_service/service/community_tokens/service.nim +++ b/src/app_service/service/community_tokens/service.nim @@ -33,7 +33,7 @@ const ethSymbol = "ETH" type CommunityTokenAndAmount* = object communityToken*: CommunityTokenDto - amount*: int + amount*: Uint256 # for assets the value is converted to wei type ContractTuple* = tuple @@ -317,7 +317,7 @@ QtObject: communityToken.name = deploymentParams.name communityToken.symbol = deploymentParams.symbol communityToken.description = tokenMetadata.description - communityToken.supply = deploymentParams.supply + communityToken.supply = stint.parse($deploymentParams.supply, Uint256) communityToken.infiniteSupply = deploymentParams.infiniteSupply communityToken.transferable = deploymentParams.transferable communityToken.remoteSelfDestruct = deploymentParams.remoteSelfDestruct @@ -346,7 +346,7 @@ QtObject: ) except RpcException: - error "Error deploying collectibles", message = getCurrentExceptionMsg() + error "Error deploying contract", message = getCurrentExceptionMsg() proc getCommunityTokens*(self: Service, communityId: string): seq[CommunityTokenDto] = try: @@ -382,22 +382,22 @@ QtObject: except RpcException: error "Error getting contract owner name", message = getCurrentExceptionMsg() - proc getRemainingSupply*(self: Service, chainId: int, contractAddress: string): int = + proc getRemainingSupply*(self: Service, chainId: int, contractAddress: string): Uint256 = try: let response = tokens_backend.remainingSupply(chainId, contractAddress) - return response.result.getInt() + return stint.parse(response.result.getStr(), Uint256) except RpcException: error "Error getting remaining supply", message = getCurrentExceptionMsg() - proc airdropCollectibles*(self: Service, communityId: string, password: string, collectiblesAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) = + proc airdropTokens*(self: Service, communityId: string, password: string, collectiblesAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) = try: for collectibleAndAmount in collectiblesAndAmounts: let addressFrom = self.contractOwner(collectibleAndAmount.communityToken.chainId, collectibleAndAmount.communityToken.address) let txData = self.buildTransactionDataDto(addressFrom, collectibleAndAmount.communityToken.chainId, collectibleAndAmount.communityToken.address) if txData.source == parseAddress(ZERO_ADDRESS): return - debug "Airdrop collectibles ", chainId=collectibleAndAmount.communityToken.chainId, address=collectibleAndAmount.communityToken.address, amount=collectibleAndAmount.amount - let response = tokens_backend.mintTo(collectibleAndAmount.communityToken.chainId, collectibleAndAmount.communityToken.address, %txData, password, walletAddresses, collectibleAndAmount.amount) + debug "Airdrop tokens ", chainId=collectibleAndAmount.communityToken.chainId, address=collectibleAndAmount.communityToken.address, amount=collectibleAndAmount.amount + let response = tokens_backend.mintTokens(collectibleAndAmount.communityToken.chainId, collectibleAndAmount.communityToken.address, %txData, password, walletAddresses, collectibleAndAmount.amount) let transactionHash = response.result.getStr() debug "Airdrop transaction hash ", transactionHash=transactionHash @@ -414,9 +414,9 @@ QtObject: collectibleAndAmount.communityToken.chainId, ) except RpcException: - error "Error airdropping collectibles", message = getCurrentExceptionMsg() + error "Error airdropping tokens", message = getCurrentExceptionMsg() - proc computeAirdropCollectiblesFee*(self: Service, collectiblesAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) = + proc computeAirdropFee*(self: Service, collectiblesAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) = try: self.tempTokensAndAmounts = collectiblesAndAmounts let arg = AsyncGetMintFees( @@ -553,12 +553,12 @@ QtObject: errorCode = ComputeFeeErrorCode.Infura return errorCode - proc burnCollectibles*(self: Service, communityId: string, password: string, contractUniqueKey: string, amount: int) = + proc burnTokens*(self: Service, communityId: string, password: string, contractUniqueKey: string, amount: Uint256) = try: var contract = self.findContractByUniqueId(contractUniqueKey) let addressFrom = self.contractOwner(contract.chainId, contract.address) let txData = self.buildTransactionDataDto(addressFrom, contract.chainId, contract.address) - debug "Burn collectibles ", chainId=contract.chainId, address=contract.address, amount=amount + debug "Burn tokens ", chainId=contract.chainId, address=contract.address, amount=amount let response = tokens_backend.burn(contract.chainId, contract.address, %txData, password, amount) let transactionHash = response.result.getStr() debug "Burn transaction hash ", transactionHash=transactionHash @@ -579,7 +579,7 @@ QtObject: except Exception as e: error "Burn error", msg = e.msg - proc computeBurnFee*(self: Service, contractUniqueKey: string, amount: int) = + proc computeBurnFee*(self: Service, contractUniqueKey: string, amount: Uint256) = try: let contract = self.findContractByUniqueId(contractUniqueKey) self.tempAccountAddress = self.contractOwner(contract.chainId, contract.address) @@ -594,7 +594,7 @@ QtObject: ) self.threadpool.start(arg) except Exception as e: - error "Error loading fees", msg = e.msg + error "Error loading burn fees", msg = e.msg proc createComputeFeeArgsWithError(self:Service, errorMessage: string): ComputeFeeArgs = let errorCode = self.getErrorCodeFromMessage(errorMessage) diff --git a/src/backend/community_tokens.nim b/src/backend/community_tokens.nim index 1adaa0bdb4b..9306254bbae 100644 --- a/src/backend/community_tokens.nim +++ b/src/backend/community_tokens.nim @@ -32,17 +32,17 @@ proc updateCommunityTokenState*(chainId: int, contractAddress: string, deploySta let payload = %* [chainId, contractAddress, deployState.int] return core.callPrivateRPC("wakuext_updateCommunityTokenState", payload) -proc updateCommunityTokenSupply*(chainId: int, contractAddress: string, supply: int): RpcResponse[JsonNode] {.raises: [Exception].} = - let payload = %* [chainId, contractAddress, supply] +proc updateCommunityTokenSupply*(chainId: int, contractAddress: string, supply: Uint256): RpcResponse[JsonNode] {.raises: [Exception].} = + let payload = %* [chainId, contractAddress, supply.toString(10)] return core.callPrivateRPC("wakuext_updateCommunityTokenSupply", payload) -proc mintTo*(chainId: int, contractAddress: string, txData: JsonNode, password: string, walletAddresses: seq[string], amount: int): RpcResponse[JsonNode] {.raises: [Exception].} = - let payload = %* [chainId, contractAddress, txData, utils.hashPassword(password), walletAddresses, amount] - return core.callPrivateRPC("collectibles_mintTo", payload) +proc mintTokens*(chainId: int, contractAddress: string, txData: JsonNode, password: string, walletAddresses: seq[string], amount: Uint256): RpcResponse[JsonNode] {.raises: [Exception].} = + let payload = %* [chainId, contractAddress, txData, utils.hashPassword(password), walletAddresses, amount.toString(10)] + return core.callPrivateRPC("collectibles_mintTokens", payload) -proc estimateMintTo*(chainId: int, contractAddress: string, walletAddresses: seq[string], amount: int): RpcResponse[JsonNode] {.raises: [Exception].} = - let payload = %* [chainId, contractAddress, walletAddresses, amount] - return core.callPrivateRPC("collectibles_estimateMintTo", payload) +proc estimateMintTokens*(chainId: int, contractAddress: string, walletAddresses: seq[string], amount: Uint256): RpcResponse[JsonNode] {.raises: [Exception].} = + let payload = %* [chainId, contractAddress, walletAddresses, amount.toString(10)] + return core.callPrivateRPC("collectibles_estimateMintTokens", 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))] @@ -52,12 +52,12 @@ proc estimateRemoteBurn*(chainId: int, contractAddress: string, tokenIds: seq[UI let payload = %* [chainId, contractAddress, tokenIds.map(x => x.toString(10))] return core.callPrivateRPC("collectibles_estimateRemoteBurn", payload) -proc burn*(chainId: int, contractAddress: string, txData: JsonNode, password: string, amount: int): RpcResponse[JsonNode] {.raises: [Exception].} = - let payload = %* [chainId, contractAddress, txData, utils.hashPassword(password), stint.parse($amount, Uint256).toString(10)] +proc burn*(chainId: int, contractAddress: string, txData: JsonNode, password: string, amount: Uint256): RpcResponse[JsonNode] {.raises: [Exception].} = + let payload = %* [chainId, contractAddress, txData, utils.hashPassword(password), amount.toString(10)] return core.callPrivateRPC("collectibles_burn", payload) -proc estimateBurn*(chainId: int, contractAddress: string, amount: int): RpcResponse[JsonNode] {.raises: [Exception].} = - let payload = %* [chainId, contractAddress, stint.parse($amount, Uint256).toString(10)] +proc estimateBurn*(chainId: int, contractAddress: string, amount: Uint256): RpcResponse[JsonNode] {.raises: [Exception].} = + let payload = %* [chainId, contractAddress, amount.toString(10)] return core.callPrivateRPC("collectibles_estimateBurn", payload) proc contractOwner*(chainId: int, contractAddress: string): RpcResponse[JsonNode] {.raises: [Exception].} = diff --git a/ui/imports/shared/stores/CommunityTokensStore.qml b/ui/imports/shared/stores/CommunityTokensStore.qml index 55125c148e2..0b00031bb27 100644 --- a/ui/imports/shared/stores/CommunityTokensStore.qml +++ b/ui/imports/shared/stores/CommunityTokensStore.qml @@ -26,7 +26,6 @@ QtObject { // Minting tokens: function deployCollectible(communityId, collectibleItem) { - // TODO: Backend needs to create new role `accountName` and update this call accordingly // TODO: Backend will need to check if the collectibleItem has a valid tokenKey, so it means a deployment retry, // otherwise, it is a new deployment. const jsonArtworkFile = Utils.getImageAndCropInfoJson(collectibleItem.artworkSource, collectibleItem.artworkCropRect) @@ -38,7 +37,6 @@ QtObject { function deployAsset(communityId, assetItem) { - // TODO: Backend needs to create new role `accountName` and update this call accordingly // TODO: Backend will need to check if the collectibleItem has a valid tokenKey, so it means a deployment retry, // otherwise, it is a new deployment. const jsonArtworkFile = Utils.getImageAndCropInfoJson(assetItem.artworkSource, assetItem.artworkCropRect) @@ -105,16 +103,16 @@ QtObject { } function burnToken(communityId, tokenKey, burnAmount) { - communityTokensModuleInst.burnCollectibles(communityId, tokenKey, burnAmount) + communityTokensModuleInst.burnTokens(communityId, tokenKey, burnAmount) } // Airdrop tokens: function airdrop(communityId, airdropTokens, addresses) { - communityTokensModuleInst.airdropCollectibles(communityId, JSON.stringify(airdropTokens), JSON.stringify(addresses)) + communityTokensModuleInst.airdropTokens(communityId, JSON.stringify(airdropTokens), JSON.stringify(addresses)) } function computeAirdropFee(communityId, contractKeysAndAmounts, addresses) { - communityTokensModuleInst.computeAirdropCollectiblesFee( + communityTokensModuleInst.computeAirdropFee( communityId, JSON.stringify(contractKeysAndAmounts), JSON.stringify(addresses)) }