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
This commit is contained in:
Michal Iskierko 2023-06-21 13:22:11 +02:00 committed by Michał Iskierko
parent 37448b01f3
commit 3632a169be
16 changed files with 133 additions and 104 deletions

View File

@ -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, tokensAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) =
self.communityTokensService.airdropTokens(communityId, password, tokensAndAmounts, walletAddresses)
proc computeAirdropCollectiblesFee*(self: Controller, collectiblesAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) =
self.communityTokensService.computeAirdropCollectiblesFee(collectiblesAndAmounts, walletAddresses)
proc computeAirdropFee*(self: Controller, tokensAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) =
self.communityTokensService.computeAirdropFee(tokensAndAmounts, 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 =

View File

@ -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.} =

View File

@ -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:

View File

@ -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)

View File

@ -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.int, 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,11 @@ 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)
if len(tokenAndAmountList) == 0:
return
self.controller.computeAirdropFee(tokenAndAmountList, walletsJsonString.parseJson.to(seq[string]))
proc getWalletAndAmountListFromJson(self: Module, collectiblesToBurnJsonString: string): seq[WalletAndAmount] =
let collectiblesToBurnJson = collectiblesToBurnJsonString.parseJson
@ -125,21 +140,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 +166,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 +192,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 +217,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)

View File

@ -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) =

View File

@ -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 =

View File

@ -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.} =

View File

@ -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)

View File

@ -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.} =

View File

@ -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

View File

@ -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())
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

View File

@ -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

View File

@ -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)

View File

@ -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].} =

View File

@ -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))
}