Skip to content

Commit

Permalink
feat(@desktop/communities): Burn and mint functionality for assets.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
endulab committed Jul 6, 2023
1 parent 0efca3f commit f2f78bf
Show file tree
Hide file tree
Showing 16 changed files with 131 additions and 104 deletions.
15 changes: 8 additions & 7 deletions src/app/modules/main/communities/tokens/controller.nim
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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 =
Expand Down
12 changes: 6 additions & 6 deletions src/app/modules/main/communities/tokens/io_interface.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand All @@ -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.} =
Expand Down
6 changes: 3 additions & 3 deletions src/app/modules/main/communities/tokens/models/token_item.nim
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -14,15 +14,15 @@ type
chainName*: string
chainIcon*: string
accountName*: string
remainingSupply*: int
remainingSupply*: Uint256
tokenOwnersModel*: token_owners_model.TokenOwnersModel

proc initTokenItem*(
tokenDto: CommunityTokenDto,
network: NetworkDto,
tokenOwners: seq[CollectibleOwner],
accountName: string,
remainingSupply: int
remainingSupply: Uint256
): TokenItem =
result.tokenDto = tokenDto
if network != nil:
Expand Down
10 changes: 5 additions & 5 deletions src/app/modules/main/communities/tokens/models/token_model.nim
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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:
Expand All @@ -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:
Expand Down Expand Up @@ -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:
Expand All @@ -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)

Expand Down
59 changes: 37 additions & 22 deletions src/app/modules/main/communities/tokens/module.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -39,7 +40,7 @@ type
tempWalletAddresses: seq[string]
tempContractAction: ContractAction
tempContractUniqueKey: string
tempAmount: int
tempAmount: Uint256

proc newCommunityTokensModule*(
parent: parent_interface.AccessInterface,
Expand Down Expand Up @@ -84,32 +85,44 @@ 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])
self.tempCommunityId = communityId
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
Expand All @@ -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
Expand All @@ -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) & "/"
Expand All @@ -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)
Expand All @@ -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)
Expand Down
Loading

0 comments on commit f2f78bf

Please sign in to comment.