feat(@desktop/communities): Airdrop community tokens

Issue #9783
This commit is contained in:
Michal Iskierko 2023-03-13 11:16:08 +01:00 committed by Michał Iskierko
parent 5f765e3542
commit c8aefe4e66
10 changed files with 108 additions and 17 deletions

View File

@ -42,6 +42,9 @@ proc init*(self: Controller) =
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 airdropCollectibles*(self: Controller, communityId: string, password: string, collectiblesAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) =
self.communityTokensService.airdropCollectibles(communityId, password, collectiblesAndAmounts, walletAddresses)
proc authenticateUser*(self: Controller, keyUid = "") =
let data = SharedKeycarModuleAuthenticationArgs(uniqueIdentifier: UNIQUE_DEPLOY_COLLECTIBLES_COMMUNITY_TOKENS_MODULE_IDENTIFIER, keyUid: keyUid)
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_AUTHENTICATE_USER, data)
@ -54,3 +57,6 @@ proc getSuggestedFees*(self: Controller, chainId: int): SuggestedFeesDto =
proc getFiatValue*(self: Controller, cryptoBalance: string, cryptoSymbol: string): string =
return self.communityTokensService.getFiatValue(cryptoBalance, cryptoSymbol)
proc getCommunityTokenBySymbol*(self: Controller, communityId: string, symbol: string): CommunityTokenDto =
return self.communityTokensService.getCommunityTokenBySymbol(communityId, symbol)

View File

@ -9,6 +9,9 @@ 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.} =
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,
selfDestruct: bool, chainId: int, image: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -1,9 +1,10 @@
import NimQml, json, stint, strformat, strutils
import NimQml, json, stint, strformat, strutils, chronicles
import ../../../../../app_service/service/community_tokens/service as community_tokens_service
import ../../../../../app_service/service/transaction/service as transaction_service
import ../../../../../app_service/service/community/dto/community
import ../../../../../app_service/common/conversion
import ../../../../../app_service/service/accounts/utils as utl
import ../../../../core/eventemitter
import ../../../../global/global_singleton
import ../io_interface as parent_interface
@ -11,17 +12,27 @@ import ./io_interface, ./view , ./controller
export io_interface
type
ContractAction {.pure.} = enum
Unknown = 0
Deploy = 1
Airdrop = 2
type
Module* = ref object of io_interface.AccessInterface
parent: parent_interface.AccessInterface
controller: Controller
view: View
viewVariant: QVariant
tempTokenAndAmountList: seq[CommunityTokenAndAmount]
tempAddressFrom: string
tempCommunityId: string
tempChainId: int
tempContractAddress: string
tempDeploymentParams: DeploymentParameters
tempTokenMetadata: CommunityTokensMetadataDto
tempWalletAddresses: seq[string]
tempContractAction: ContractAction
proc newCommunityTokensModule*(
parent: parent_interface.AccessInterface,
@ -45,12 +56,40 @@ method resetTempValues(self:Module) =
self.tempDeploymentParams = DeploymentParameters()
self.tempTokenMetadata = CommunityTokensMetadataDto()
self.tempChainId = 0
self.tempContractAddress = ""
self.tempWalletAddresses = @[]
self.tempContractAction = ContractAction.Unknown
self.tempTokenAndAmountList = @[]
method load*(self: Module) =
singletonInstance.engine.setRootContextProperty("communityTokensModule", self.viewVariant)
self.controller.init()
self.view.load()
proc authenticate(self: Module) =
if singletonInstance.userProfile.getIsKeycardUser():
let keyUid = singletonInstance.userProfile.getKeyUid()
self.controller.authenticateUser(keyUid)
else:
self.controller.authenticateUser()
method airdropCollectibles*(self: Module, communityId: string, collectiblesJsonString: string, walletsJsonString: string) =
let collectiblesJson = collectiblesJsonString.parseJson
self.tempTokenAndAmountList = @[]
for collectible in collectiblesJson:
let symbol = collectible["key"].getStr
let amount = collectible["amount"].getInt
let tokenDto = self.controller.getCommunityTokenBySymbol(communityId, symbol)
if tokenDto.tokenType == TokenType.Unknown:
error "Can't find token for community", communityId=communityId, symbol=symbol
return
self.tempTokenAndAmountList.add(CommunityTokenAndAmount(communityToken: tokenDto, amount: amount))
self.tempWalletAddresses = walletsJsonString.parseJson.to(seq[string])
self.tempCommunityId = communityId
self.tempContractAction = ContractAction.Airdrop
self.authenticate()
method deployCollectible*(self: Module, communityId: string, fromAddress: string, name: string, symbol: string, description: string,
supply: int, infiniteSupply: bool, transferable: bool, selfDestruct: bool, chainId: int, image: string) =
self.tempAddressFrom = fromAddress
@ -62,13 +101,11 @@ method deployCollectible*(self: Module, communityId: string, fromAddress: string
self.tempDeploymentParams.infiniteSupply = infiniteSupply
self.tempDeploymentParams.transferable = transferable
self.tempDeploymentParams.remoteSelfDestruct = selfDestruct
self.tempDeploymentParams.tokenUri = utl.changeCommunityKeyCompression(communityId) & "/"
self.tempTokenMetadata.image = singletonInstance.utils.formatImagePath(image)
self.tempTokenMetadata.description = description
if singletonInstance.userProfile.getIsKeycardUser():
let keyUid = singletonInstance.userProfile.getKeyUid()
self.controller.authenticateUser(keyUid)
else:
self.controller.authenticateUser()
self.tempContractAction = ContractAction.Deploy
self.authenticate()
method onUserAuthenticated*(self: Module, password: string) =
defer: self.resetTempValues()
@ -76,7 +113,10 @@ method onUserAuthenticated*(self: Module, password: string) =
discard
#TODO signalize somehow
else:
self.controller.deployCollectibles(self.tempCommunityId, self.tempAddressFrom, password, self.tempDeploymentParams, self.tempTokenMetadata, self.tempChainId)
if self.tempContractAction == ContractAction.Deploy:
self.controller.deployCollectibles(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)
method computeDeployFee*(self: Module, chainId: int): string =
let suggestedFees = self.controller.getSuggestedFees(chainId)
@ -93,4 +133,4 @@ method computeDeployFee*(self: Module, chainId: int): string =
let fiatValue = self.controller.getFiatValue(ethValueStr, "ETH")
return fmt"{ethValue:.4f}ETH (${fiatValue})"
return fmt"{ethValue:.4f}ETH (${fiatValue})"

View File

@ -22,6 +22,9 @@ QtObject:
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)
proc airdropCollectibles*(self: View, communityId: string, collectiblesJsonString: string, walletsJsonString: string) {.slot.} =
self.communityTokensModule.airdropCollectibles(communityId, collectiblesJsonString, walletsJsonString)
proc deployFeeUpdated*(self: View) {.signal.}
proc computeDeployFee*(self: View, chainId: int) {.slot.} =

View File

@ -23,6 +23,11 @@ export deployment_parameters
logScope:
topics = "community-tokens-service"
type
CommunityTokenAndAmount* = object
communityToken*: CommunityTokenDto
amount*: int
type
CommunityTokenDeployedStatusArgs* = ref object of Args
communityId*: string
@ -155,4 +160,21 @@ QtObject:
let price = self.tokenService.getTokenPrice(cryptoSymbol, currentCurrency)
let value = parseFloat(cryptoBalance) * price
return fmt"{value:.2f}"
return fmt"{value:.2f}"
proc contractOwner*(self: Service, chainId: int, contractAddress: string): string =
try:
let response = tokens_backend.contractOwner(chainId, contractAddress)
return response.result.getStr()
except RpcException:
error "Error getting contract owner", message = getCurrentExceptionMsg()
proc airdropCollectibles*(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 = TransactionDataDto(source: parseAddress(addressFrom)) #TODO estimate fee in UI
let response = tokens_backend.mintTo(collectibleAndAmount.communityToken.chainId, collectibleAndAmount.communityToken.address, %txData, password, walletAddresses, collectibleAndAmount.amount)
echo "!!! Transaction hash ", response.result.getStr()
except RpcException:
error "Error minting collectibles", message = getCurrentExceptionMsg()

View File

@ -18,4 +18,12 @@ proc addCommunityToken*(token: CommunityTokenDto): RpcResponse[JsonNode] {.raise
proc updateCommunityTokenState*(contractAddress: string, deployState: DeployState): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [contractAddress, deployState.int]
return core.callPrivateRPC("wakuext_updateCommunityTokenState", payload)
return core.callPrivateRPC("wakuext_updateCommunityTokenState", 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 contractOwner*(chainId: int, contractAddress: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [chainId, contractAddress]
return core.callPrivateRPC("collectibles_contractOwner", payload)

View File

@ -19,7 +19,7 @@ SettingsPageLayout {
property int viewWidth: 560 // by design
signal airdropClicked(var airdropTokens, string address)
signal airdropClicked(var airdropTokens, var addresses)
signal navigateToMintTokenSettings
// TODO: Update with stackmanager when #8736 is integrated
@ -96,7 +96,7 @@ SettingsPageLayout {
collectiblesModel: root.collectiblesModel
onAirdropClicked: {
root.airdropClicked(airdropTokens, address)
root.airdropClicked(airdropTokens, addresses)
stackManager.clear(d.welcomeViewState, StackView.Immediate)
}
onNavigateToMintTokenSettings: root.navigateToMintTokenSettings()

View File

@ -67,7 +67,11 @@ QtObject {
}
// Airdrop tokens:
function airdrop(airdropTokens, address) {
console.warn("TODO: Airdrop backend call!")
function airdrop(communityId, airdropTokens, addresses) {
const addrArray = []
for(var i = 0; i < addresses.length; i++) {
addrArray.push(addresses[i]["text"])
}
communityTokensModuleInst.airdropCollectibles(communityId, JSON.stringify(airdropTokens), JSON.stringify(addrArray))
}
}

View File

@ -345,7 +345,7 @@ StatusSectionLayout {
collectiblesModel: rootStore.collectiblesModel
onPreviousPageNameChanged: root.backButtonName = previousPageName
onAirdropClicked: communityTokensStore.airdrop(airdropTokens, chainId, address)
onAirdropClicked: communityTokensStore.airdrop(root.community.id, airdropTokens, addresses)
onNavigateToMintTokenSettings: d.currentIndex = d.mintTokensSettingsIndex
}

View File

@ -31,7 +31,7 @@ StatusScrollView {
readonly property bool isFullyFilled: selectedHoldingsModel.count > 0 &&
addressess.model.count > 0
signal airdropClicked(var airdropTokens, string address)
signal airdropClicked(var airdropTokens, var addresses)
signal navigateToMintTokenSettings
QtObject {
@ -205,6 +205,7 @@ StatusScrollView {
id: addressInput
Layout.fillWidth: true
placeholderText: qsTr("Example: 0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7999")
}
@ -249,7 +250,11 @@ StatusScrollView {
root.selectedHoldingsModel,
["key", "type", "amount"])
root.airdropClicked(airdropTokens, addressess.model)
const addresses = ModelUtils.modelToArray(
addressess.model,
["text"])
root.airdropClicked(airdropTokens, addresses)
}
}
}