feat(@desktop/communities): Assets deployment

Issue #10987
This commit is contained in:
Michal Iskierko 2023-06-14 09:50:54 +02:00 committed by Michał Iskierko
parent 6d6cb7a7a7
commit 6f1957e650
13 changed files with 100 additions and 36 deletions

View File

@ -70,8 +70,8 @@ proc init*(self: Controller) =
let args = AirdropArgs(e)
self.communityTokensModule.onAirdropStateChanged(args.communityToken.communityId, args.communityToken.name, args.communityToken.chainId, args.transactionHash, args.status)
proc deployCollectibles*(self: Controller, communityId: string, addressFrom: string, password: string, deploymentParams: DeploymentParameters, tokenMetadata: CommunityTokensMetadataDto, chainId: int) =
self.communityTokensService.deployCollectibles(communityId, addressFrom, password, deploymentParams, tokenMetadata, chainId)
proc deployContract*(self: Controller, communityId: string, addressFrom: string, password: string, deploymentParams: DeploymentParameters, tokenMetadata: CommunityTokensMetadataDto, chainId: int) =
self.communityTokensService.deployContract(communityId, addressFrom, password, deploymentParams, tokenMetadata, chainId)
proc airdropCollectibles*(self: Controller, communityId: string, password: string, collectiblesAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) =
self.communityTokensService.airdropCollectibles(communityId, password, collectiblesAndAmounts, walletAddresses)
@ -92,8 +92,8 @@ proc authenticateUser*(self: Controller, keyUid = "") =
proc getCommunityTokens*(self: Controller, communityId: string): seq[CommunityTokenDto] =
return self.communityTokensService.getCommunityTokens(communityId)
proc computeDeployFee*(self: Controller, chainId: int, accountAddress: string) =
self.communityTokensService.computeDeployFee(chainId, accountAddress)
proc computeDeployFee*(self: Controller, chainId: int, accountAddress: string, tokenType: TokenType) =
self.communityTokensService.computeDeployFee(chainId, accountAddress, tokenType)
proc computeSelfDestructFee*(self: Controller, walletAndAmountList: seq[WalletAndAmount], contractUniqueKey: string) =
self.communityTokensService.computeSelfDestructFee(walletAndAmountList, contractUniqueKey)

View File

@ -1,4 +1,5 @@
import ../../../../../app_service/service/community_tokens/service
import ../../../../../app_service/service/community/dto/community
import ../../../shared_models/currency_amount
type
@ -22,17 +23,21 @@ method selfDestructCollectibles*(self: AccessInterface, communityId: string, col
method burnCollectibles*(self: AccessInterface, communityId: string, contractUniqueKey: string, amount: int) {.base.} =
raise newException(ValueError, "No implementation available")
method deployCollectible*(self: AccessInterface, communityId: string, address: string, name: string, symbol: string, description: string, supply: int, infiniteSupply: bool, transferable: bool,
method deployCollectibles*(self: AccessInterface, communityId: string, address: string, name: string, symbol: string, description: string, supply: int, infiniteSupply: bool, transferable: bool,
selfDestruct: bool, chainId: int, image: string) {.base.} =
raise newException(ValueError, "No implementation available")
method deployAssets*(self: AccessInterface, communityId: string, address: string, name: string, symbol: string, description: string, supply: int, infiniteSupply: bool, decimals: int,
chainId: int, image: string) {.base.} =
raise newException(ValueError, "No implementation available")
method onUserAuthenticated*(self: AccessInterface, password: string) {.base.} =
raise newException(ValueError, "No implementation available")
method resetTempValues*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method computeDeployFee*(self: AccessInterface, chainId: int, accountAddress: string) {.base.} =
method computeDeployFee*(self: AccessInterface, chainId: int, accountAddress: string, tokenType: TokenType) {.base.} =
raise newException(ValueError, "No implementation available")
method computeSelfDestructFee*(self: AccessInterface, collectiblesToBurnJsonString: string, contractUniqueKey: string) {.base.} =

View File

@ -26,6 +26,7 @@ type
TokenOwnersModel
AccountName
RemainingSupply
Decimals
QtObject:
type TokenModel* = ref object of QAbstractListModel
@ -130,6 +131,7 @@ QtObject:
ModelRole.TokenOwnersModel.int:"tokenOwnersModel",
ModelRole.AccountName.int:"accountName",
ModelRole.RemainingSupply.int:"remainingSupply",
ModelRole.Decimals.int:"decimals",
}.toTable
method data(self: TokenModel, index: QModelIndex, role: int): QVariant =
@ -176,6 +178,8 @@ QtObject:
result = newQVariant(item.accountName)
of ModelRole.RemainingSupply:
result = newQVariant(item.remainingSupply)
of ModelRole.Decimals:
result = newQVariant(item.tokenDto.decimals)
proc `$`*(self: TokenModel): string =
for i in 0 ..< self.items.len:

View File

@ -130,7 +130,7 @@ method burnCollectibles*(self: Module, communityId: string, contractUniqueKey: s
self.tempContractAction = ContractAction.Burn
self.authenticate()
method deployCollectible*(self: Module, communityId: string, fromAddress: string, name: string, symbol: string, description: string,
method deployCollectibles*(self: Module, communityId: string, fromAddress: string, name: string, symbol: string, description: string,
supply: int, infiniteSupply: bool, transferable: bool, selfDestruct: bool, chainId: int, image: string) =
self.tempAddressFrom = fromAddress
self.tempCommunityId = communityId
@ -142,6 +142,24 @@ method deployCollectible*(self: Module, communityId: string, fromAddress: string
self.tempDeploymentParams.transferable = transferable
self.tempDeploymentParams.remoteSelfDestruct = selfDestruct
self.tempDeploymentParams.tokenUri = utl.changeCommunityKeyCompression(communityId) & "/"
self.tempTokenMetadata.tokenType = TokenType.ERC721
self.tempTokenMetadata.image = singletonInstance.utils.formatImagePath(image)
self.tempTokenMetadata.description = description
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,
chainId: int, image: string) =
self.tempAddressFrom = fromAddress
self.tempCommunityId = communityId
self.tempChainId = chainId
self.tempDeploymentParams.name = name
self.tempDeploymentParams.symbol = symbol
self.tempDeploymentParams.supply = supply
self.tempDeploymentParams.infiniteSupply = infiniteSupply
self.tempDeploymentParams.decimals = decimals
self.tempDeploymentParams.tokenUri = utl.changeCommunityKeyCompression(communityId) & "/"
self.tempTokenMetadata.tokenType = TokenType.ERC20
self.tempTokenMetadata.image = singletonInstance.utils.formatImagePath(image)
self.tempTokenMetadata.description = description
self.tempContractAction = ContractAction.Deploy
@ -154,7 +172,7 @@ method onUserAuthenticated*(self: Module, password: string) =
#TODO signalize somehow
else:
if self.tempContractAction == ContractAction.Deploy:
self.controller.deployCollectibles(self.tempCommunityId, self.tempAddressFrom, password, self.tempDeploymentParams, self.tempTokenMetadata, self.tempChainId)
self.controller.deployContract(self.tempCommunityId, self.tempAddressFrom, password, self.tempDeploymentParams, self.tempTokenMetadata, self.tempChainId)
elif self.tempContractAction == ContractAction.Airdrop:
self.controller.airdropCollectibles(self.tempCommunityId, password, self.tempTokenAndAmountList, self.tempWalletAddresses)
elif self.tempContractAction == ContractAction.SelfDestruct:
@ -174,8 +192,8 @@ method onAirdropFeesComputed*(self: Module, args: AirdropFeesArgs) =
method onBurnFeeComputed*(self: Module, ethCurrency: CurrencyAmount, fiatCurrency: CurrencyAmount, errorCode: ComputeFeeErrorCode) =
self.view.updateBurnFee(ethCurrency, fiatCurrency, errorCode.int)
method computeDeployFee*(self: Module, chainId: int, accountAddress: string) =
self.controller.computeDeployFee(chainId, accountAddress)
method computeDeployFee*(self: Module, chainId: int, accountAddress: string, tokenType: TokenType) =
self.controller.computeDeployFee(chainId, accountAddress, tokenType)
method computeSelfDestructFee*(self: Module, collectiblesToBurnJsonString: string, contractUniqueKey: string) =
let walletAndAmountList = self.getWalletAndAmountListFromJson(collectiblesToBurnJsonString)

View File

@ -2,6 +2,8 @@ import NimQml, json, strutils, sequtils
import ./io_interface as community_tokens_module_interface
import ../../../shared_models/currency_amount
import ../../../../../app_service/common/conversion
import ../../../../../app_service/service/community/dto/community
QtObject:
type
@ -20,7 +22,10 @@ QtObject:
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, image: string) {.slot.} =
self.communityTokensModule.deployCollectible(communityId, fromAddress, name, symbol, description, supply, infiniteSupply, transferable, selfDestruct, chainId, image)
self.communityTokensModule.deployCollectibles(communityId, fromAddress, name, symbol, description, supply, infiniteSupply, transferable, selfDestruct, chainId, image)
proc deployAssets*(self: View, communityId: string, fromAddress: string, name: string, symbol: string, description: string, supply: int, infiniteSupply: bool, decimals: int, chainId: int, image: string) {.slot.} =
self.communityTokensModule.deployAssets(communityId, fromAddress, name, symbol, description, supply, infiniteSupply, decimals, chainId, image)
proc airdropCollectibles*(self: View, communityId: string, collectiblesJsonString: string, walletsJsonString: string) {.slot.} =
self.communityTokensModule.airdropCollectibles(communityId, collectiblesJsonString, walletsJsonString)
@ -39,8 +44,8 @@ QtObject:
proc airdropFeesUpdated*(self: View, json: string) {.signal.}
proc burnFeeUpdated*(self: View, ethCurrency: QVariant, fiatCurrency: QVariant, errorCode: int) {.signal.}
proc computeDeployFee*(self: View, chainId: int, accountAddress: string) {.slot.} =
self.communityTokensModule.computeDeployFee(chainId, accountAddress)
proc computeDeployFee*(self: View, chainId: int, accountAddress: string, tokenType: int) {.slot.} =
self.communityTokensModule.computeDeployFee(chainId, accountAddress, intToEnum(tokenType, TokenType.Unknown))
proc computeSelfDestructFee*(self: View, collectiblesToBurnJsonString: string, contractUniqueKey: string) {.slot.} =
self.communityTokensModule.computeSelfDestructFee(collectiblesToBurnJsonString, contractUniqueKey)

View File

@ -6,6 +6,7 @@ import ../../../backend/collectibles
import ../../../app/core/tasks/common
import ../../../app/core/tasks/qt
import ../transaction/dto
import ../community/dto/community
proc tableToJsonArray[A, B](t: var Table[A, B]): JsonNode =
let data = newJArray()
@ -19,6 +20,7 @@ proc tableToJsonArray[A, B](t: var Table[A, B]): JsonNode =
type
AsyncGetDeployFeesArg = ref object of QObjectTaskArg
chainId: int
tokenType: TokenType
const asyncGetDeployFeesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[AsyncGetDeployFeesArg](argEncoded)
@ -27,7 +29,8 @@ const asyncGetDeployFeesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.
var feeTable: Table[int, SuggestedFeesDto] # fees for chain
let response = eth.suggestedFees(arg.chainId).result
feeTable[arg.chainId] = response.toSuggestedFeesDto()
let deployGas = community_tokens.deployCollectiblesEstimate().result.getInt
let deployGas = if arg.tokenType == TokenType.ERC721: community_tokens.deployCollectiblesEstimate().result.getInt
else: community_tokens.deployAssetsEstimate().result.getInt
gasTable[(arg.chainId, "")] = deployGas
arg.finish(%* {
"feeTable": tableToJsonArray(feeTable),

View File

@ -26,6 +26,7 @@ type
chainId*: int
deployState*: DeployState
image*: string
decimals*: int
proc toJsonNode*(self: CommunityTokenDto): JsonNode =
result = %* {
@ -42,7 +43,8 @@ proc toJsonNode*(self: CommunityTokenDto): JsonNode =
"tokenUri": self.tokenUri,
"chainId": self.chainId,
"deployState": self.deployState.int,
"image": self.image
"image": self.image,
"decimals": self.decimals
}
proc toCommunityTokenDto*(jsonObj: JsonNode): CommunityTokenDto =
@ -65,6 +67,7 @@ proc toCommunityTokenDto*(jsonObj: JsonNode): CommunityTokenDto =
discard jsonObj.getProp("deployState", deployStateInt)
result.deployState = intToEnum(deployStateInt, DeployState.Failed)
discard jsonObj.getProp("image", result.image)
discard jsonObj.getProp("decimals", result.decimals)
proc parseCommunityTokens*(response: RpcResponse[JsonNode]): seq[CommunityTokenDto] =
result = map(response.result.getElems(),

View File

@ -9,6 +9,7 @@ type
transferable*: bool
remoteSelfDestruct*: bool
tokenUri*: string
decimals*: int
proc `%`*(x: DeploymentParameters): JsonNode =
result = newJobject()
@ -19,5 +20,6 @@ proc `%`*(x: DeploymentParameters): JsonNode =
result["transferable"] = %x.transferable
result["remoteSelfDestruct"] = %x.remoteSelfDestruct
result["tokenUri"] = %x.tokenUri
result["decimals"] = %x.decimals

View File

@ -288,20 +288,29 @@ QtObject:
if suggestedFees.eip1559Enabled: $suggestedFees.maxPriorityFeePerGas else: "",
if suggestedFees.eip1559Enabled: $suggestedFees.maxFeePerGasM else: "")
proc deployCollectibles*(self: Service, communityId: string, addressFrom: string, password: string, deploymentParams: DeploymentParameters, tokenMetadata: CommunityTokensMetadataDto, chainId: int) =
proc deployContract*(self: Service, communityId: string, addressFrom: string, password: string, deploymentParams: DeploymentParameters, tokenMetadata: CommunityTokensMetadataDto, chainId: int) =
try:
let txData = self.buildTransactionDataDto(addressFrom, chainId, "")
if txData.source == parseAddress(ZERO_ADDRESS):
return
let response = tokens_backend.deployCollectibles(chainId, %deploymentParams, %txData, password)
var response: RpcResponse[JsonNode]
case tokenMetadata.tokenType
of TokenType.ERC721:
response = tokens_backend.deployCollectibles(chainId, %deploymentParams, %txData, password)
of TokenType.ERC20:
response = tokens_backend.deployAssets(chainId, %deploymentParams, %txData, password)
else:
error "Contract deployment error - unknown token type", tokenType=tokenMetadata.tokenType
return
let contractAddress = response.result["contractAddress"].getStr()
let transactionHash = response.result["transactionHash"].getStr()
debug "Deployed contract address ", contractAddress=contractAddress
debug "Deployment transaction hash ", transactionHash=transactionHash
var communityToken: CommunityTokenDto
communityToken.tokenType = TokenType.ERC721
communityToken.tokenType = tokenMetadata.tokenType
communityToken.communityId = communityId
communityToken.address = contractAddress
communityToken.name = deploymentParams.name
@ -315,6 +324,7 @@ QtObject:
communityToken.chainId = chainId
communityToken.deployState = DeployState.InProgress
communityToken.image = tokenMetadata.image
communityToken.decimals = deploymentParams.decimals
# save token to db
let communityTokenJson = tokens_backend.addCommunityToken(communityToken)
@ -424,8 +434,11 @@ QtObject:
let price = self.tokenService.getTokenPrice(cryptoSymbol, currentCurrency)
return cryptoBalance * price
proc computeDeployFee*(self: Service, chainId: int, accountAddress: string) =
proc computeDeployFee*(self: Service, chainId: int, accountAddress: string, tokenType: TokenType) =
try:
if tokenType != TokenType.ERC20 and tokenType != TokenType.ERC721:
error "Error loading fees: unknown token type", tokenType = tokenType
return
self.tempAccountAddress = accountAddress
self.tempChainId = chainId
let arg = AsyncGetDeployFeesArg(
@ -433,6 +446,7 @@ QtObject:
vptr: cast[ByteAddress](self.vptr),
slot: "onDeployFees",
chainId: chainId,
tokenType: tokenType
)
self.threadpool.start(arg)
except Exception as e:
@ -732,14 +746,18 @@ QtObject:
except Exception as e:
error "Error computing airdrop fees", msg = e.msg
proc fetchCommunityOwners*(self: Service, communityId: string, chainId: int, contractAddress: string) =
proc fetchCommunityOwners*(self: Service, communityToken: CommunityTokenDto) =
if communityToken.tokenType != TokenType.ERC721:
# TODO we need a new implementation for ERC20
# we will be able to show only tokens hold by community members
return
let arg = FetchCollectibleOwnersArg(
tptr: cast[ByteAddress](fetchCollectibleOwnersTaskArg),
vptr: cast[ByteAddress](self.vptr),
slot: "onCommunityTokenOwnersFetched",
chainId: chainId,
contractAddress: contractAddress,
communityId: communityId
chainId: communityToken.chainId,
contractAddress: communityToken.address,
communityId: communityToken.communityId
)
self.threadpool.start(arg)
@ -767,12 +785,12 @@ QtObject:
let allTokens = self.getAllCommunityTokens()
for token in allTokens:
if token.transferable:
self.fetchCommunityOwners(token.communityId, token.chainId, token.address)
self.fetchCommunityOwners(token)
proc onFetchTempTokenOwners*(self: Service) {.slot.} =
self.fetchCommunityOwners(self.tempTokenOwnersToFetch.communityId, self.tempTokenOwnersToFetch.chainId, self.tempTokenOwnersToFetch.address)
self.fetchCommunityOwners(self.tempTokenOwnersToFetch)
proc fetchAllTokenOwners*(self: Service) =
let allTokens = self.getAllCommunityTokens()
for token in allTokens:
self.fetchCommunityOwners(token.communityId, token.chainId, token.address)
self.fetchCommunityOwners(token)

View File

@ -8,7 +8,11 @@ import ../app_service/service/community_tokens/dto/community_token
proc deployCollectibles*(chainId: int, deploymentParams: JsonNode, txData: JsonNode, password: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [chainId, deploymentParams, txData, utils.hashPassword(password)]
return core.callPrivateRPC("collectibles_deploy", payload)
return core.callPrivateRPC("collectibles_deployCollectibles", payload)
proc deployAssets*(chainId: int, deploymentParams: JsonNode, txData: JsonNode, password: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [chainId, deploymentParams, txData, utils.hashPassword(password)]
return core.callPrivateRPC("collectibles_deployAssets", payload)
proc getCommunityTokens*(communityId: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [communityId]
@ -66,6 +70,6 @@ proc deployCollectiblesEstimate*(): RpcResponse[JsonNode] {.raises: [Exception].
let payload = %*[]
return core.callPrivateRPC("collectibles_deployCollectiblesEstimate", payload)
proc addTokenOwners*(chainId: int, contractAddress: string, walletAddresses: seq[string], amount: int): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [chainId, contractAddress, walletAddresses, amount]
return core.callPrivateRPC("collectibles_addTokenOwners", payload)
proc deployAssetsEstimate*(): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %*[]
return core.callPrivateRPC("collectibles_deployAssetsEstimate", payload)

View File

@ -40,7 +40,7 @@ SettingsPageLayout {
signal mintCollectible(var collectibleItem)
signal mintAsset(var assetItem)
signal signMintTransactionOpened(int chainId, string accountAddress)
signal signMintTransactionOpened(int chainId, string accountAddress, int tokenType)
signal signRemoteDestructTransactionOpened(var remotelyDestructTokensList, // [key , amount]
string tokenKey)
@ -389,7 +389,7 @@ SettingsPageLayout {
onOpened: {
root.setFeeLoading()
root.signMintTransactionOpened(preview.chainId, preview.accountAddress)
root.signMintTransactionOpened(preview.chainId, preview.accountAddress, preview.isAssetView ? Constants.TokenType.ERC20 : Constants.TokenType.ERC721)
}
onCancelClicked: close()
onSignTransactionClicked: preview.signMintTransaction()

View File

@ -303,7 +303,7 @@ StatusSectionLayout {
accounts: root.rootStore.accounts
onPreviousPageNameChanged: root.backButtonName = previousPageName
onSignMintTransactionOpened: communityTokensStore.computeDeployFee(chainId, accountAddress)
onSignMintTransactionOpened: communityTokensStore.computeDeployFee(chainId, accountAddress, tokenType)
onMintCollectible: communityTokensStore.deployCollectible(root.community.id, collectibleItem)
onMintAsset: communityTokensStore.deployAsset(root.community.id, assetItem)
onSignRemoteDestructTransactionOpened: communityTokensStore.computeSelfDestructFee(remotelyDestructTokensList, tokenKey)

View File

@ -44,7 +44,9 @@ QtObject {
// otherwise, it is a new deployment.
// TODO: Backend needs to modify the call to expect an image JSON file with cropped artwork information:
const jsonArtworkFile = Utils.getImageAndCropInfoJson(assetItem.artworkSource, assetItem.artworkCropRect)
console.log("TODO: Deploy Asset backend!")
communityTokensModuleInst.deployAssets(communityId, assetItem.accountAddress, assetItem.name,
assetItem.symbol, assetItem.description, assetItem.supply,
assetItem.infiniteSupply, assetItem.decimals, assetItem.chainId, assetItem.artworkSource/*instead: jsonArtworkFile*/)
}
function deleteToken(communityId, contractUniqueKey) {
@ -87,8 +89,8 @@ QtObject {
}
}
function computeDeployFee(chainId, accountAddress) {
communityTokensModuleInst.computeDeployFee(chainId, accountAddress)
function computeDeployFee(chainId, accountAddress, tokenType) {
communityTokensModuleInst.computeDeployFee(chainId, accountAddress, tokenType)
}
function computeSelfDestructFee(selfDestructTokensList, tokenKey) {