feat(@desktop/communities): Compute minting fees and displaying minting toast messages
Issue #10536
This commit is contained in:
parent
523ddd0572
commit
db55d10b37
|
@ -48,6 +48,9 @@ proc init*(self: Controller) =
|
||||||
self.events.on(SIGNAL_COMPUTE_SELF_DESTRUCT_FEE) do(e:Args):
|
self.events.on(SIGNAL_COMPUTE_SELF_DESTRUCT_FEE) do(e:Args):
|
||||||
let args = ComputeFeeArgs(e)
|
let args = ComputeFeeArgs(e)
|
||||||
self.communityTokensModule.onSelfDestructFeeComputed(args.ethCurrency, args.fiatCurrency, args.errorCode)
|
self.communityTokensModule.onSelfDestructFeeComputed(args.ethCurrency, args.fiatCurrency, args.errorCode)
|
||||||
|
self.events.on(SIGNAL_COMPUTE_AIRDROP_FEE) do(e:Args):
|
||||||
|
let args = AirdropFeesArgs(e)
|
||||||
|
self.communityTokensModule.onAirdropFeesComputed(args)
|
||||||
self.events.on(SIGNAL_COMMUNITY_TOKEN_DEPLOYED) do(e: Args):
|
self.events.on(SIGNAL_COMMUNITY_TOKEN_DEPLOYED) do(e: Args):
|
||||||
let args = CommunityTokenDeployedArgs(e)
|
let args = CommunityTokenDeployedArgs(e)
|
||||||
self.communityTokensModule.onCommunityTokenDeployStateChanged(args.communityToken.communityId, args.communityToken.chainId, args.transactionHash, args.communityToken.deployState)
|
self.communityTokensModule.onCommunityTokenDeployStateChanged(args.communityToken.communityId, args.communityToken.chainId, args.transactionHash, args.communityToken.deployState)
|
||||||
|
@ -57,6 +60,9 @@ proc init*(self: Controller) =
|
||||||
self.events.on(SIGNAL_REMOTE_DESTRUCT_STATUS) do(e: Args):
|
self.events.on(SIGNAL_REMOTE_DESTRUCT_STATUS) do(e: Args):
|
||||||
let args = RemoteDestructArgs(e)
|
let args = RemoteDestructArgs(e)
|
||||||
self.communityTokensModule.onRemoteDestructStateChanged(args.communityToken.communityId, args.communityToken.name, args.communityToken.chainId, args.transactionHash, args.status)
|
self.communityTokensModule.onRemoteDestructStateChanged(args.communityToken.communityId, args.communityToken.name, args.communityToken.chainId, args.transactionHash, args.status)
|
||||||
|
self.events.on(SIGNAL_AIRDROP_STATUS) do(e: Args):
|
||||||
|
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) =
|
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)
|
self.communityTokensService.deployCollectibles(communityId, addressFrom, password, deploymentParams, tokenMetadata, chainId)
|
||||||
|
@ -64,6 +70,9 @@ proc deployCollectibles*(self: Controller, communityId: string, addressFrom: str
|
||||||
proc airdropCollectibles*(self: Controller, communityId: string, password: string, collectiblesAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) =
|
proc airdropCollectibles*(self: Controller, communityId: string, password: string, collectiblesAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) =
|
||||||
self.communityTokensService.airdropCollectibles(communityId, password, collectiblesAndAmounts, walletAddresses)
|
self.communityTokensService.airdropCollectibles(communityId, password, collectiblesAndAmounts, walletAddresses)
|
||||||
|
|
||||||
|
proc computeAirdropCollectiblesFee*(self: Controller, collectiblesAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) =
|
||||||
|
self.communityTokensService.computeAirdropCollectiblesFee(collectiblesAndAmounts, walletAddresses)
|
||||||
|
|
||||||
proc selfDestructCollectibles*(self: Controller, communityId: string, password: string, walletAndAmounts: seq[WalletAndAmount], contractUniqueKey: string) =
|
proc selfDestructCollectibles*(self: Controller, communityId: string, password: string, walletAndAmounts: seq[WalletAndAmount], contractUniqueKey: string) =
|
||||||
self.communityTokensService.selfDestructCollectibles(communityId, password, walletAndAmounts, contractUniqueKey)
|
self.communityTokensService.selfDestructCollectibles(communityId, password, walletAndAmounts, contractUniqueKey)
|
||||||
|
|
||||||
|
@ -80,8 +89,8 @@ proc computeDeployFee*(self: Controller, chainId: int, accountAddress: string) =
|
||||||
proc computeSelfDestructFee*(self: Controller, walletAndAmountList: seq[WalletAndAmount], contractUniqueKey: string) =
|
proc computeSelfDestructFee*(self: Controller, walletAndAmountList: seq[WalletAndAmount], contractUniqueKey: string) =
|
||||||
self.communityTokensService.computeSelfDestructFee(walletAndAmountList, contractUniqueKey)
|
self.communityTokensService.computeSelfDestructFee(walletAndAmountList, contractUniqueKey)
|
||||||
|
|
||||||
proc getCommunityTokenBySymbol*(self: Controller, communityId: string, symbol: string): CommunityTokenDto =
|
proc findContractByUniqueId*(self: Controller, contractUniqueKey: string): CommunityTokenDto =
|
||||||
return self.communityTokensService.getCommunityTokenBySymbol(communityId, symbol)
|
return self.communityTokensService.findContractByUniqueId(contractUniqueKey)
|
||||||
|
|
||||||
proc getNetwork*(self:Controller, chainId: int): NetworkDto =
|
proc getNetwork*(self:Controller, chainId: int): NetworkDto =
|
||||||
self.networksService.getNetwork(chainId)
|
self.networksService.getNetwork(chainId)
|
|
@ -13,6 +13,9 @@ method load*(self: AccessInterface) {.base.} =
|
||||||
method airdropCollectibles*(self: AccessInterface, communityId: string, collectiblesJsonString: string, walletsJsonString: string) {.base.} =
|
method airdropCollectibles*(self: AccessInterface, communityId: string, collectiblesJsonString: string, walletsJsonString: string) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method computeAirdropCollectiblesFee*(self: AccessInterface, communityId: string, collectiblesJsonString: string, walletsJsonString: string) {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
method selfDestructCollectibles*(self: AccessInterface, communityId: string, collectiblesToBurnJsonString: string, contractUniqueKey: string) {.base.} =
|
method selfDestructCollectibles*(self: AccessInterface, communityId: string, collectiblesToBurnJsonString: string, contractUniqueKey: string) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
@ -38,8 +41,14 @@ method onDeployFeeComputed*(self: AccessInterface, ethCurrency: CurrencyAmount,
|
||||||
method onSelfDestructFeeComputed*(self: AccessInterface, ethCurrency: CurrencyAmount, fiatCurrency: CurrencyAmount, errorCode: ComputeFeeErrorCode) {.base.} =
|
method onSelfDestructFeeComputed*(self: AccessInterface, ethCurrency: CurrencyAmount, fiatCurrency: CurrencyAmount, errorCode: ComputeFeeErrorCode) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method onAirdropFeesComputed*(self: AccessInterface, args: AirdropFeesArgs) {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
method onCommunityTokenDeployStateChanged*(self: AccessInterface, communityId: string, chainId: int, transactionHash: string, deployState: DeployState) {.base.} =
|
method onCommunityTokenDeployStateChanged*(self: AccessInterface, communityId: string, chainId: int, transactionHash: string, deployState: DeployState) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
method onRemoteDestructStateChanged*(self: AccessInterface, communityId: string, tokenName: string, chainId: int, transactionHash: string, status: ContractTransactionStatus) {.base.} =
|
method onRemoteDestructStateChanged*(self: AccessInterface, communityId: string, tokenName: string, chainId: int, transactionHash: string, status: ContractTransactionStatus) {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method onAirdropStateChanged*(self: AccessInterface, communityId: string, tokenName: string, chainId: int, transactionHash: string, status: ContractTransactionStatus) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
|
@ -80,23 +80,33 @@ proc authenticate(self: Module) =
|
||||||
else:
|
else:
|
||||||
self.controller.authenticateUser()
|
self.controller.authenticateUser()
|
||||||
|
|
||||||
method airdropCollectibles*(self: Module, communityId: string, collectiblesJsonString: string, walletsJsonString: string) =
|
proc getTokenAndAmountList(self: Module, communityId: string, collectiblesJsonString: string): seq[CommunityTokenAndAmount] =
|
||||||
let collectiblesJson = collectiblesJsonString.parseJson
|
try:
|
||||||
self.tempTokenAndAmountList = @[]
|
let collectiblesJson = collectiblesJsonString.parseJson
|
||||||
for collectible in collectiblesJson:
|
for collectible in collectiblesJson:
|
||||||
let symbol = collectible["key"].getStr
|
let contractUniqueKey = collectible["contractUniqueKey"].getStr
|
||||||
let amount = collectible["amount"].getInt
|
let amount = collectible["amount"].getInt
|
||||||
let tokenDto = self.controller.getCommunityTokenBySymbol(communityId, symbol)
|
let tokenDto = self.controller.findContractByUniqueId(contractUniqueKey)
|
||||||
if tokenDto.tokenType == TokenType.Unknown:
|
if tokenDto.tokenType == TokenType.Unknown:
|
||||||
error "Can't find token for community", communityId=communityId, symbol=symbol
|
error "Can't find token for community", contractUniqueKey=contractUniqueKey
|
||||||
return
|
return @[]
|
||||||
self.tempTokenAndAmountList.add(CommunityTokenAndAmount(communityToken: tokenDto, amount: amount))
|
result.add(CommunityTokenAndAmount(communityToken: tokenDto, amount: amount))
|
||||||
|
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)
|
||||||
|
if len(self.tempTokenAndAmountList) == 0:
|
||||||
|
return
|
||||||
self.tempWalletAddresses = walletsJsonString.parseJson.to(seq[string])
|
self.tempWalletAddresses = walletsJsonString.parseJson.to(seq[string])
|
||||||
self.tempCommunityId = communityId
|
self.tempCommunityId = communityId
|
||||||
self.tempContractAction = ContractAction.Airdrop
|
self.tempContractAction = ContractAction.Airdrop
|
||||||
self.authenticate()
|
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]))
|
||||||
|
|
||||||
proc getWalletAndAmountListFromJson(self: Module, collectiblesToBurnJsonString: string): seq[WalletAndAmount] =
|
proc getWalletAndAmountListFromJson(self: Module, collectiblesToBurnJsonString: string): seq[WalletAndAmount] =
|
||||||
let collectiblesToBurnJson = collectiblesToBurnJsonString.parseJson
|
let collectiblesToBurnJson = collectiblesToBurnJsonString.parseJson
|
||||||
for collectibleToBurn in collectiblesToBurnJson:
|
for collectibleToBurn in collectiblesToBurnJson:
|
||||||
|
@ -147,6 +157,9 @@ method onDeployFeeComputed*(self: Module, ethCurrency: CurrencyAmount, fiatCurre
|
||||||
method onSelfDestructFeeComputed*(self: Module, ethCurrency: CurrencyAmount, fiatCurrency: CurrencyAmount, errorCode: ComputeFeeErrorCode) =
|
method onSelfDestructFeeComputed*(self: Module, ethCurrency: CurrencyAmount, fiatCurrency: CurrencyAmount, errorCode: ComputeFeeErrorCode) =
|
||||||
self.view.updateSelfDestructFee(ethCurrency, fiatCurrency, errorCode.int)
|
self.view.updateSelfDestructFee(ethCurrency, fiatCurrency, errorCode.int)
|
||||||
|
|
||||||
|
method onAirdropFeesComputed*(self: Module, args: AirdropFeesArgs) =
|
||||||
|
self.view.updateAirdropFees(%args)
|
||||||
|
|
||||||
method computeDeployFee*(self: Module, chainId: int, accountAddress: string) =
|
method computeDeployFee*(self: Module, chainId: int, accountAddress: string) =
|
||||||
self.controller.computeDeployFee(chainId, accountAddress)
|
self.controller.computeDeployFee(chainId, accountAddress)
|
||||||
|
|
||||||
|
@ -162,4 +175,9 @@ method onCommunityTokenDeployStateChanged*(self: Module, communityId: string, ch
|
||||||
method onRemoteDestructStateChanged*(self: Module, communityId: string, tokenName: string, chainId: int, transactionHash: string, status: ContractTransactionStatus) =
|
method onRemoteDestructStateChanged*(self: Module, communityId: string, tokenName: string, chainId: int, transactionHash: string, status: ContractTransactionStatus) =
|
||||||
let network = self.controller.getNetwork(chainId)
|
let network = self.controller.getNetwork(chainId)
|
||||||
let url = if network != nil: network.blockExplorerURL & "/tx/" & transactionHash else: ""
|
let url = if network != nil: network.blockExplorerURL & "/tx/" & transactionHash else: ""
|
||||||
self.view.emitRemoteDestructStateChanged(communityId, tokenName, status.int, url)
|
self.view.emitRemoteDestructStateChanged(communityId, tokenName, status.int, url)
|
||||||
|
|
||||||
|
method onAirdropStateChanged*(self: Module, communityId: string, tokenName: string, chainId: int, transactionHash: string, status: ContractTransactionStatus) =
|
||||||
|
let network = self.controller.getNetwork(chainId)
|
||||||
|
let url = if network != nil: network.blockExplorerURL & "/tx/" & transactionHash else: ""
|
||||||
|
self.view.emitAirdropStateChanged(communityId, tokenName, status.int, url)
|
|
@ -25,11 +25,15 @@ QtObject:
|
||||||
proc airdropCollectibles*(self: View, communityId: string, collectiblesJsonString: string, walletsJsonString: string) {.slot.} =
|
proc airdropCollectibles*(self: View, communityId: string, collectiblesJsonString: string, walletsJsonString: string) {.slot.} =
|
||||||
self.communityTokensModule.airdropCollectibles(communityId, collectiblesJsonString, walletsJsonString)
|
self.communityTokensModule.airdropCollectibles(communityId, collectiblesJsonString, walletsJsonString)
|
||||||
|
|
||||||
|
proc computeAirdropCollectiblesFee*(self: View, communityId: string, collectiblesJsonString: string, walletsJsonString: string) {.slot.} =
|
||||||
|
self.communityTokensModule.computeAirdropCollectiblesFee(communityId, collectiblesJsonString, walletsJsonString)
|
||||||
|
|
||||||
proc selfDestructCollectibles*(self: View, communityId: string, collectiblesToBurnJsonString: string, contractUniqueKey: string) {.slot.} =
|
proc selfDestructCollectibles*(self: View, communityId: string, collectiblesToBurnJsonString: string, contractUniqueKey: string) {.slot.} =
|
||||||
self.communityTokensModule.selfDestructCollectibles(communityId, collectiblesToBurnJsonString, contractUniqueKey)
|
self.communityTokensModule.selfDestructCollectibles(communityId, collectiblesToBurnJsonString, contractUniqueKey)
|
||||||
|
|
||||||
proc deployFeeUpdated*(self: View, ethCurrency: QVariant, fiatCurrency: QVariant, errorCode: int) {.signal.}
|
proc deployFeeUpdated*(self: View, ethCurrency: QVariant, fiatCurrency: QVariant, errorCode: int) {.signal.}
|
||||||
proc selfDestructFeeUpdated*(self: View, ethCurrency: QVariant, fiatCurrency: QVariant, errorCode: int) {.signal.}
|
proc selfDestructFeeUpdated*(self: View, ethCurrency: QVariant, fiatCurrency: QVariant, errorCode: int) {.signal.}
|
||||||
|
proc airdropFeesUpdated*(self: View, json: string) {.signal.}
|
||||||
|
|
||||||
proc computeDeployFee*(self: View, chainId: int, accountAddress: string) {.slot.} =
|
proc computeDeployFee*(self: View, chainId: int, accountAddress: string) {.slot.} =
|
||||||
self.communityTokensModule.computeDeployFee(chainId, accountAddress)
|
self.communityTokensModule.computeDeployFee(chainId, accountAddress)
|
||||||
|
@ -43,10 +47,17 @@ QtObject:
|
||||||
proc updateSelfDestructFee*(self: View, ethCurrency: CurrencyAmount, fiatCurrency: CurrencyAmount, errorCode: int) =
|
proc updateSelfDestructFee*(self: View, ethCurrency: CurrencyAmount, fiatCurrency: CurrencyAmount, errorCode: int) =
|
||||||
self.selfDestructFeeUpdated(newQVariant(ethCurrency), newQVariant(fiatCurrency), errorCode)
|
self.selfDestructFeeUpdated(newQVariant(ethCurrency), newQVariant(fiatCurrency), errorCode)
|
||||||
|
|
||||||
|
proc updateAirdropFees*(self: View, args: JsonNode) =
|
||||||
|
self.airdropFeesUpdated($args)
|
||||||
|
|
||||||
proc deploymentStateChanged*(self: View, communityId: string, status: int, url: string) {.signal.}
|
proc deploymentStateChanged*(self: View, communityId: string, status: int, url: string) {.signal.}
|
||||||
proc emitDeploymentStateChanged*(self: View, communityId: string, status: int, url: string) =
|
proc emitDeploymentStateChanged*(self: View, communityId: string, status: int, url: string) =
|
||||||
self.deploymentStateChanged(communityId, status, url)
|
self.deploymentStateChanged(communityId, status, url)
|
||||||
|
|
||||||
proc remoteDestructStateChanged*(self: View, communityId: string, tokenName: string, status: int, url: string) {.signal.}
|
proc remoteDestructStateChanged*(self: View, communityId: string, tokenName: string, status: int, url: string) {.signal.}
|
||||||
proc emitRemoteDestructStateChanged*(self: View, communityId: string, tokenName: string, status: int, url: string) =
|
proc emitRemoteDestructStateChanged*(self: View, communityId: string, tokenName: string, status: int, url: string) =
|
||||||
self.remoteDestructStateChanged(communityId, tokenName, status, url)
|
self.remoteDestructStateChanged(communityId, tokenName, status, url)
|
||||||
|
|
||||||
|
proc airdropStateChanged*(self: View, communityId: string, tokenName: string, status: int, url: string) {.signal.}
|
||||||
|
proc emitAirdropStateChanged*(self: View, communityId: string, tokenName: string, status: int, url: string) =
|
||||||
|
self.airdropStateChanged(communityId, tokenName, status, url)
|
|
@ -1,4 +1,4 @@
|
||||||
import stint
|
import stint, Tables
|
||||||
include ../../common/json_utils
|
include ../../common/json_utils
|
||||||
import ../../../backend/eth
|
import ../../../backend/eth
|
||||||
import ../../../backend/community_tokens
|
import ../../../backend/community_tokens
|
||||||
|
@ -7,16 +7,31 @@ import ../../../app/core/tasks/common
|
||||||
import ../../../app/core/tasks/qt
|
import ../../../app/core/tasks/qt
|
||||||
import ../transaction/dto
|
import ../transaction/dto
|
||||||
|
|
||||||
|
proc tableToJsonArray[A, B](t: var Table[A, B]): JsonNode =
|
||||||
|
let data = newJArray()
|
||||||
|
for k,v in t:
|
||||||
|
data.elems.add(%*{
|
||||||
|
"key": k,
|
||||||
|
"value": v
|
||||||
|
})
|
||||||
|
return data
|
||||||
|
|
||||||
type
|
type
|
||||||
AsyncGetSuggestedFees = ref object of QObjectTaskArg
|
AsyncGetDeployFeesArg = ref object of QObjectTaskArg
|
||||||
chainId: int
|
chainId: int
|
||||||
|
|
||||||
const asyncGetSuggestedFeesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
const asyncGetDeployFeesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
let arg = decode[AsyncGetSuggestedFees](argEncoded)
|
let arg = decode[AsyncGetDeployFeesArg](argEncoded)
|
||||||
try:
|
try:
|
||||||
|
var gasTable: Table[ContractTuple, int] # gas per contract
|
||||||
|
var feeTable: Table[int, SuggestedFeesDto] # fees for chain
|
||||||
let response = eth.suggestedFees(arg.chainId).result
|
let response = eth.suggestedFees(arg.chainId).result
|
||||||
|
feeTable[arg.chainId] = response.toSuggestedFeesDto()
|
||||||
|
let deployGas = community_tokens.deployCollectiblesEstimate().result.getInt
|
||||||
|
gasTable[(arg.chainId, "")] = deployGas
|
||||||
arg.finish(%* {
|
arg.finish(%* {
|
||||||
"fees": response.toSuggestedFeesDto(),
|
"feeTable": tableToJsonArray(feeTable),
|
||||||
|
"gasTable": tableToJsonArray(gasTable),
|
||||||
"error": "",
|
"error": "",
|
||||||
})
|
})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -33,17 +48,53 @@ type
|
||||||
const asyncGetBurnFeesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
const asyncGetBurnFeesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
let arg = decode[AsyncGetBurnFees](argEncoded)
|
let arg = decode[AsyncGetBurnFees](argEncoded)
|
||||||
try:
|
try:
|
||||||
let feesResponse = eth.suggestedFees(arg.chainId).result
|
var gasTable: Table[ContractTuple, int] # gas per contract
|
||||||
|
var feeTable: Table[int, SuggestedFeesDto] # fees for chain
|
||||||
|
let fee = eth.suggestedFees(arg.chainId).result.toSuggestedFeesDto()
|
||||||
let burnGas = community_tokens.estimateRemoteBurn(arg.chainId, arg.contractAddress, arg.tokenIds).result.getInt
|
let burnGas = community_tokens.estimateRemoteBurn(arg.chainId, arg.contractAddress, arg.tokenIds).result.getInt
|
||||||
|
feeTable[arg.chainId] = fee
|
||||||
|
gasTable[(arg.chainId, arg.contractAddress)] = burnGas
|
||||||
arg.finish(%* {
|
arg.finish(%* {
|
||||||
"fees": feesResponse.toSuggestedFeesDto(),
|
"feeTable": tableToJsonArray(feeTable),
|
||||||
"burnGas": burnGas,
|
"gasTable": tableToJsonArray(gasTable),
|
||||||
"error": "" })
|
"error": "" })
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
arg.finish(%* {
|
arg.finish(%* {
|
||||||
"error": e.msg,
|
"error": e.msg,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
type
|
||||||
|
AsyncGetMintFees = ref object of QObjectTaskArg
|
||||||
|
collectiblesAndAmounts: seq[CommunityTokenAndAmount]
|
||||||
|
walletAddresses: seq[string]
|
||||||
|
|
||||||
|
const asyncGetMintFeesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let arg = decode[AsyncGetMintFees](argEncoded)
|
||||||
|
try:
|
||||||
|
var gasTable: Table[ContractTuple, int] # gas per contract
|
||||||
|
var feeTable: Table[int, SuggestedFeesDto] # fees for chain
|
||||||
|
for collectibleAndAmount in arg.collectiblesAndAmounts:
|
||||||
|
# get fees if we do not have for this chain yet
|
||||||
|
let chainId = collectibleAndAmount.communityToken.chainId
|
||||||
|
if not feeTable.hasKey(chainId):
|
||||||
|
let feesResponse = eth.suggestedFees(chainId).result
|
||||||
|
feeTable[chainId] = feesResponse.toSuggestedFeesDto()
|
||||||
|
|
||||||
|
# get gas for smart contract
|
||||||
|
let gas = community_tokens.estimateMintTo(chainId,
|
||||||
|
collectibleAndAmount.communityToken.address,
|
||||||
|
arg.walletAddresses, collectibleAndAmount.amount).result.getInt
|
||||||
|
gasTable[(chainId, collectibleAndAmount.communityToken.address)] = gas
|
||||||
|
arg.finish(%* {
|
||||||
|
"feeTable": tableToJsonArray(feeTable),
|
||||||
|
"gasTable": tableToJsonArray(gasTable),
|
||||||
|
"error": "" })
|
||||||
|
except Exception as e:
|
||||||
|
let output = %* {
|
||||||
|
"error": e.msg
|
||||||
|
}
|
||||||
|
arg.finish(output)
|
||||||
|
|
||||||
type
|
type
|
||||||
FetchCollectibleOwnersArg = ref object of QObjectTaskArg
|
FetchCollectibleOwnersArg = ref object of QObjectTaskArg
|
||||||
chainId*: int
|
chainId*: int
|
||||||
|
|
|
@ -23,22 +23,41 @@ import ./dto/deployment_parameters
|
||||||
import ./dto/community_token
|
import ./dto/community_token
|
||||||
import ./dto/community_token_owner
|
import ./dto/community_token_owner
|
||||||
|
|
||||||
import airdrop_details
|
|
||||||
|
|
||||||
include async_tasks
|
|
||||||
|
|
||||||
export community_token
|
export community_token
|
||||||
export deployment_parameters
|
export deployment_parameters
|
||||||
export community_token_owner
|
export community_token_owner
|
||||||
|
|
||||||
logScope:
|
const ethSymbol = "ETH"
|
||||||
topics = "community-tokens-service"
|
|
||||||
|
|
||||||
type
|
type
|
||||||
CommunityTokenAndAmount* = object
|
CommunityTokenAndAmount* = object
|
||||||
communityToken*: CommunityTokenDto
|
communityToken*: CommunityTokenDto
|
||||||
amount*: int
|
amount*: int
|
||||||
|
|
||||||
|
type
|
||||||
|
ContractTuple* = tuple
|
||||||
|
chainId: int
|
||||||
|
address: string
|
||||||
|
|
||||||
|
proc `%`*(self: ContractTuple): JsonNode =
|
||||||
|
result = %* {
|
||||||
|
"address": self.address,
|
||||||
|
"chainId": self.chainId
|
||||||
|
}
|
||||||
|
|
||||||
|
proc toContractTuple*(json: JsonNode): ContractTuple =
|
||||||
|
return (json["chainId"].getInt, json["address"].getStr)
|
||||||
|
|
||||||
|
type
|
||||||
|
ChainWalletTuple* = tuple
|
||||||
|
chainId: int
|
||||||
|
address: string
|
||||||
|
|
||||||
|
include async_tasks
|
||||||
|
|
||||||
|
logScope:
|
||||||
|
topics = "community-tokens-service"
|
||||||
|
|
||||||
type
|
type
|
||||||
WalletAndAmount* = object
|
WalletAndAmount* = object
|
||||||
walletAddress*: string
|
walletAddress*: string
|
||||||
|
@ -69,6 +88,12 @@ type
|
||||||
transactionHash*: string
|
transactionHash*: string
|
||||||
status*: ContractTransactionStatus
|
status*: ContractTransactionStatus
|
||||||
|
|
||||||
|
type
|
||||||
|
AirdropArgs* = ref object of Args
|
||||||
|
communityToken*: CommunityTokenDto
|
||||||
|
transactionHash*: string
|
||||||
|
status*: ContractTransactionStatus
|
||||||
|
|
||||||
type
|
type
|
||||||
ComputeFeeErrorCode* {.pure.} = enum
|
ComputeFeeErrorCode* {.pure.} = enum
|
||||||
Success,
|
Success,
|
||||||
|
@ -81,11 +106,36 @@ type
|
||||||
ethCurrency*: CurrencyAmount
|
ethCurrency*: CurrencyAmount
|
||||||
fiatCurrency*: CurrencyAmount
|
fiatCurrency*: CurrencyAmount
|
||||||
errorCode*: ComputeFeeErrorCode
|
errorCode*: ComputeFeeErrorCode
|
||||||
|
contractUniqueKey*: string # used for minting
|
||||||
|
|
||||||
|
proc `%`*(self: ComputeFeeArgs): JsonNode =
|
||||||
|
result = %* {
|
||||||
|
"ethFee": self.ethCurrency.toJsonNode(),
|
||||||
|
"fiatFee": self.fiatCurrency.toJsonNode(),
|
||||||
|
"errorCode": self.errorCode.int,
|
||||||
|
"contractUniqueKey": self.contractUniqueKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
proc computeFeeArgsToJsonArray(args: seq[ComputeFeeArgs]): JsonNode =
|
||||||
|
let arr = newJArray()
|
||||||
|
for arg in args:
|
||||||
|
arr.elems.add(%arg)
|
||||||
|
return arr
|
||||||
|
|
||||||
type
|
type
|
||||||
ContractTuple = tuple
|
AirdropFeesArgs* = ref object of Args
|
||||||
address: string
|
fees*: seq[ComputeFeeArgs]
|
||||||
chainId: int
|
totalEthFee*: CurrencyAmount
|
||||||
|
totalFiatFee*: CurrencyAmount
|
||||||
|
errorCode*: ComputeFeeErrorCode
|
||||||
|
|
||||||
|
proc `%`*(self: AirdropFeesArgs): JsonNode =
|
||||||
|
result = %* {
|
||||||
|
"fees": computeFeeArgsToJsonArray(self.fees),
|
||||||
|
"totalEthFee": self.totalEthFee.toJsonNode(),
|
||||||
|
"totalFiatFee": self.totalFiatFee.toJsonNode(),
|
||||||
|
"errorCode": self.errorCode.int
|
||||||
|
}
|
||||||
|
|
||||||
type
|
type
|
||||||
CommunityTokenOwnersArgs* = ref object of Args
|
CommunityTokenOwnersArgs* = ref object of Args
|
||||||
|
@ -99,8 +149,10 @@ const SIGNAL_COMMUNITY_TOKEN_DEPLOY_STATUS* = "communityTokenDeployStatus"
|
||||||
const SIGNAL_COMMUNITY_TOKEN_DEPLOYED* = "communityTokenDeployed"
|
const SIGNAL_COMMUNITY_TOKEN_DEPLOYED* = "communityTokenDeployed"
|
||||||
const SIGNAL_COMPUTE_DEPLOY_FEE* = "computeDeployFee"
|
const SIGNAL_COMPUTE_DEPLOY_FEE* = "computeDeployFee"
|
||||||
const SIGNAL_COMPUTE_SELF_DESTRUCT_FEE* = "computeSelfDestructFee"
|
const SIGNAL_COMPUTE_SELF_DESTRUCT_FEE* = "computeSelfDestructFee"
|
||||||
|
const SIGNAL_COMPUTE_AIRDROP_FEE* = "computeAirdropFee"
|
||||||
const SIGNAL_COMMUNITY_TOKEN_OWNERS_FETCHED* = "communityTokenOwnersFetched"
|
const SIGNAL_COMMUNITY_TOKEN_OWNERS_FETCHED* = "communityTokenOwnersFetched"
|
||||||
const SIGNAL_REMOTE_DESTRUCT_STATUS* = "communityTokenRemoteDestructStatus"
|
const SIGNAL_REMOTE_DESTRUCT_STATUS* = "communityTokenRemoteDestructStatus"
|
||||||
|
const SIGNAL_AIRDROP_STATUS* = "airdropStatus"
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
type
|
type
|
||||||
|
@ -117,8 +169,10 @@ QtObject:
|
||||||
tokenOwners1SecTimer: QTimer # used to update 1 sec after changes in owners
|
tokenOwners1SecTimer: QTimer # used to update 1 sec after changes in owners
|
||||||
tempTokenOwnersToFetch: CommunityTokenDto # used by 1sec timer
|
tempTokenOwnersToFetch: CommunityTokenDto # used by 1sec timer
|
||||||
tokenOwnersCache: Table[ContractTuple, seq[CollectibleOwner]]
|
tokenOwnersCache: Table[ContractTuple, seq[CollectibleOwner]]
|
||||||
tempSuggestedFees: SuggestedFeesDto
|
|
||||||
tempGasUnits: int
|
tempFeeTable: Table[int, SuggestedFeesDto] # fees per chain, filled during gas computation, used during operation (deployment, mint, burn)
|
||||||
|
tempGasTable: Table[ContractTuple, int] # gas per contract, filled during gas computation, used during operation (deployment, mint, burn)
|
||||||
|
tempTokensAndAmounts: seq[CommunityTokenAndAmount]
|
||||||
|
|
||||||
# Forward declaration
|
# Forward declaration
|
||||||
proc fetchAllTokenOwners*(self: Service)
|
proc fetchAllTokenOwners*(self: Service)
|
||||||
|
@ -173,11 +227,15 @@ QtObject:
|
||||||
|
|
||||||
self.events.on(PendingTransactionTypeDto.CollectibleAirdrop.event) do(e: Args):
|
self.events.on(PendingTransactionTypeDto.CollectibleAirdrop.event) do(e: Args):
|
||||||
let receivedData = TransactionMinedArgs(e)
|
let receivedData = TransactionMinedArgs(e)
|
||||||
let airdropDetails = toAirdropDetails(parseJson(receivedData.data))
|
let tokenDto = toCommunityTokenDto(parseJson(receivedData.data))
|
||||||
if not receivedData.success:
|
let transactionStatus = if receivedData.success: ContractTransactionStatus.Completed else: ContractTransactionStatus.Failed
|
||||||
error "Collectible airdrop failed", contractAddress=airdropDetails.contractAddress
|
let data = AirdropArgs(communityToken: tokenDto, transactionHash: receivedData.transactionHash, status: transactionStatus)
|
||||||
return
|
self.events.emit(SIGNAL_AIRDROP_STATUS, data)
|
||||||
#TODO signalize about airdrops - add when extending airdrops
|
|
||||||
|
# update owners list if burn was successfull
|
||||||
|
if receivedData.success:
|
||||||
|
self.tempTokenOwnersToFetch = tokenDto
|
||||||
|
self.tokenOwners1SecTimer.start()
|
||||||
self.events.on(PendingTransactionTypeDto.CollectibleRemoteSelfDestruct.event) do(e: Args):
|
self.events.on(PendingTransactionTypeDto.CollectibleRemoteSelfDestruct.event) do(e: Args):
|
||||||
let receivedData = TransactionMinedArgs(e)
|
let receivedData = TransactionMinedArgs(e)
|
||||||
let tokenDto = toCommunityTokenDto(parseJson(receivedData.data))
|
let tokenDto = toCommunityTokenDto(parseJson(receivedData.data))
|
||||||
|
@ -190,26 +248,23 @@ QtObject:
|
||||||
self.tempTokenOwnersToFetch = tokenDto
|
self.tempTokenOwnersToFetch = tokenDto
|
||||||
self.tokenOwners1SecTimer.start()
|
self.tokenOwners1SecTimer.start()
|
||||||
|
|
||||||
proc deployCollectiblesEstimate*(self: Service): int =
|
proc buildTransactionDataDto(self: Service, addressFrom: string, chainId: int, contractAddress: string): TransactionDataDto =
|
||||||
try:
|
let gasUnits = self.tempGasTable.getOrDefault((chainId, contractAddress), 0)
|
||||||
let response = tokens_backend.deployCollectiblesEstimate()
|
let suggestedFees = self.tempFeeTable[chainId]
|
||||||
return response.result.getInt()
|
if suggestedFees == nil:
|
||||||
except RpcException:
|
error "Can't find suggested fees for chainId", chainId=chainId
|
||||||
error "Error getting deploy estimate", message = getCurrentExceptionMsg()
|
return
|
||||||
|
return ens_utils.buildTransaction(parseAddress(addressFrom), 0.u256, $gasUnits,
|
||||||
|
if suggestedFees.eip1559Enabled: "" else: $suggestedFees.gasPrice, suggestedFees.eip1559Enabled,
|
||||||
|
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 deployCollectibles*(self: Service, communityId: string, addressFrom: string, password: string, deploymentParams: DeploymentParameters, tokenMetadata: CommunityTokensMetadataDto, chainId: int) =
|
||||||
try:
|
try:
|
||||||
let suggestedFees = self.transactionService.suggestedFees(chainId)
|
let txData = self.buildTransactionDataDto(addressFrom, chainId, "")
|
||||||
let contractGasUnits = self.deployCollectiblesEstimate()
|
if txData.source == parseAddress(ZERO_ADDRESS):
|
||||||
if suggestedFees == nil:
|
|
||||||
error "Error deploying collectibles", message = "Can't get suggested fees"
|
|
||||||
return
|
return
|
||||||
|
|
||||||
let txData = ens_utils.buildTransaction(parseAddress(addressFrom), 0.u256, $contractGasUnits,
|
|
||||||
if suggestedFees.eip1559Enabled: "" else: $suggestedFees.gasPrice, suggestedFees.eip1559Enabled,
|
|
||||||
if suggestedFees.eip1559Enabled: $suggestedFees.maxPriorityFeePerGas else: "",
|
|
||||||
if suggestedFees.eip1559Enabled: $suggestedFees.maxFeePerGasM else: "")
|
|
||||||
|
|
||||||
let response = tokens_backend.deployCollectibles(chainId, %deploymentParams, %txData, password)
|
let response = tokens_backend.deployCollectibles(chainId, %deploymentParams, %txData, password)
|
||||||
let contractAddress = response.result["contractAddress"].getStr()
|
let contractAddress = response.result["contractAddress"].getStr()
|
||||||
let transactionHash = response.result["transactionHash"].getStr()
|
let transactionHash = response.result["transactionHash"].getStr()
|
||||||
|
@ -289,16 +344,16 @@ QtObject:
|
||||||
try:
|
try:
|
||||||
for collectibleAndAmount in collectiblesAndAmounts:
|
for collectibleAndAmount in collectiblesAndAmounts:
|
||||||
let addressFrom = self.contractOwner(collectibleAndAmount.communityToken.chainId, collectibleAndAmount.communityToken.address)
|
let addressFrom = self.contractOwner(collectibleAndAmount.communityToken.chainId, collectibleAndAmount.communityToken.address)
|
||||||
let txData = TransactionDataDto(source: parseAddress(addressFrom)) #TODO estimate fee in UI
|
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)
|
let response = tokens_backend.mintTo(collectibleAndAmount.communityToken.chainId, collectibleAndAmount.communityToken.address, %txData, password, walletAddresses, collectibleAndAmount.amount)
|
||||||
let transactionHash = response.result.getStr()
|
let transactionHash = response.result.getStr()
|
||||||
debug "Airdrop transaction hash ", transactionHash=transactionHash
|
debug "Airdrop transaction hash ", transactionHash=transactionHash
|
||||||
|
|
||||||
let airdropDetails = AirdropDetails(
|
var data = AirdropArgs(communityToken: collectibleAndAmount.communityToken, transactionHash: transactionHash, status: ContractTransactionStatus.InProgress)
|
||||||
chainId: collectibleAndAmount.communityToken.chainId,
|
self.events.emit(SIGNAL_AIRDROP_STATUS, data)
|
||||||
contractAddress: collectibleAndAmount.communityToken.address,
|
|
||||||
walletAddresses: walletAddresses,
|
|
||||||
amount: collectibleAndAmount.amount)
|
|
||||||
|
|
||||||
# observe transaction state
|
# observe transaction state
|
||||||
self.transactionService.watchTransaction(
|
self.transactionService.watchTransaction(
|
||||||
|
@ -306,12 +361,26 @@ QtObject:
|
||||||
addressFrom,
|
addressFrom,
|
||||||
collectibleAndAmount.communityToken.address,
|
collectibleAndAmount.communityToken.address,
|
||||||
$PendingTransactionTypeDto.CollectibleAirdrop,
|
$PendingTransactionTypeDto.CollectibleAirdrop,
|
||||||
$airdropDetails.toJsonNode(),
|
$collectibleAndAmount.communityToken.toJsonNode(),
|
||||||
collectibleAndAmount.communityToken.chainId,
|
collectibleAndAmount.communityToken.chainId,
|
||||||
)
|
)
|
||||||
except RpcException:
|
except RpcException:
|
||||||
error "Error airdropping collectibles", message = getCurrentExceptionMsg()
|
error "Error airdropping collectibles", message = getCurrentExceptionMsg()
|
||||||
|
|
||||||
|
proc computeAirdropCollectiblesFee*(self: Service, collectiblesAndAmounts: seq[CommunityTokenAndAmount], walletAddresses: seq[string]) =
|
||||||
|
try:
|
||||||
|
self.tempTokensAndAmounts = collectiblesAndAmounts
|
||||||
|
let arg = AsyncGetMintFees(
|
||||||
|
tptr: cast[ByteAddress](asyncGetMintFeesTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: "onAirdropFees",
|
||||||
|
collectiblesAndAmounts: collectiblesAndAmounts,
|
||||||
|
walletAddresses: walletAddresses
|
||||||
|
)
|
||||||
|
self.threadpool.start(arg)
|
||||||
|
except Exception as e:
|
||||||
|
error "Error loading airdrop fees", msg = e.msg
|
||||||
|
|
||||||
proc getFiatValue*(self: Service, cryptoBalance: float, cryptoSymbol: string): float =
|
proc getFiatValue*(self: Service, cryptoBalance: float, cryptoSymbol: string): float =
|
||||||
if (cryptoSymbol == ""):
|
if (cryptoSymbol == ""):
|
||||||
return 0.0
|
return 0.0
|
||||||
|
@ -323,8 +392,8 @@ QtObject:
|
||||||
try:
|
try:
|
||||||
self.tempAccountAddress = accountAddress
|
self.tempAccountAddress = accountAddress
|
||||||
self.tempChainId = chainId
|
self.tempChainId = chainId
|
||||||
let arg = AsyncGetSuggestedFees(
|
let arg = AsyncGetDeployFeesArg(
|
||||||
tptr: cast[ByteAddress](asyncGetSuggestedFeesTask),
|
tptr: cast[ByteAddress](asyncGetDeployFeesTask),
|
||||||
vptr: cast[ByteAddress](self.vptr),
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
slot: "onDeployFees",
|
slot: "onDeployFees",
|
||||||
chainId: chainId,
|
chainId: chainId,
|
||||||
|
@ -333,7 +402,7 @@ QtObject:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error "Error loading fees", msg = e.msg
|
error "Error loading fees", msg = e.msg
|
||||||
|
|
||||||
proc findContractByUniqueId(self: Service, contractUniqueKey: string): CommunityTokenDto =
|
proc findContractByUniqueId*(self: Service, contractUniqueKey: string): CommunityTokenDto =
|
||||||
let allTokens = self.getAllCommunityTokens()
|
let allTokens = self.getAllCommunityTokens()
|
||||||
for token in allTokens:
|
for token in allTokens:
|
||||||
if common_utils.contractUniqueKey(token.chainId, token.address) == contractUniqueKey:
|
if common_utils.contractUniqueKey(token.chainId, token.address) == contractUniqueKey:
|
||||||
|
@ -366,13 +435,6 @@ QtObject:
|
||||||
error "Can't find token ids to burn"
|
error "Can't find token ids to burn"
|
||||||
return tokenIds
|
return tokenIds
|
||||||
|
|
||||||
# TODO use temp fees for deployment also
|
|
||||||
proc buildTransactionFromTempFees(self: Service, addressFrom: string): TransactionDataDto =
|
|
||||||
return ens_utils.buildTransaction(parseAddress(addressFrom), 0.u256, $self.tempGasUnits,
|
|
||||||
if self.tempSuggestedFees.eip1559Enabled: "" else: $self.tempSuggestedFees.gasPrice, self.tempSuggestedFees.eip1559Enabled,
|
|
||||||
if self.tempSuggestedFees.eip1559Enabled: $self.tempSuggestedFees.maxPriorityFeePerGas else: "",
|
|
||||||
if self.tempSuggestedFees.eip1559Enabled: $self.tempSuggestedFees.maxFeePerGasM else: "")
|
|
||||||
|
|
||||||
proc selfDestructCollectibles*(self: Service, communityId: string, password: string, walletAndAmounts: seq[WalletAndAmount], contractUniqueKey: string) =
|
proc selfDestructCollectibles*(self: Service, communityId: string, password: string, walletAndAmounts: seq[WalletAndAmount], contractUniqueKey: string) =
|
||||||
try:
|
try:
|
||||||
let contract = self.findContractByUniqueId(contractUniqueKey)
|
let contract = self.findContractByUniqueId(contractUniqueKey)
|
||||||
|
@ -380,7 +442,7 @@ QtObject:
|
||||||
if len(tokenIds) == 0:
|
if len(tokenIds) == 0:
|
||||||
return
|
return
|
||||||
let addressFrom = self.contractOwner(contract.chainId, contract.address)
|
let addressFrom = self.contractOwner(contract.chainId, contract.address)
|
||||||
let txData = self.buildTransactionFromTempFees(addressFrom)
|
let txData = self.buildTransactionDataDto(addressFrom, contract.chainId, contract.address)
|
||||||
debug "Remote destruct collectibles ", chainId=contract.chainId, address=contract.address, tokens=tokenIds
|
debug "Remote destruct collectibles ", chainId=contract.chainId, address=contract.address, tokens=tokenIds
|
||||||
let response = tokens_backend.remoteBurn(contract.chainId, contract.address, %txData, password, tokenIds)
|
let response = tokens_backend.remoteBurn(contract.chainId, contract.address, %txData, password, tokenIds)
|
||||||
let transactionHash = response.result.getStr()
|
let transactionHash = response.result.getStr()
|
||||||
|
@ -422,28 +484,39 @@ QtObject:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error "Error loading fees", msg = e.msg
|
error "Error loading fees", msg = e.msg
|
||||||
|
|
||||||
proc createComputeFeeArgs(self:Service, jsonNode: JsonNode, gasUnits: int, chainId: int, walletAddress: string): ComputeFeeArgs =
|
proc create0CurrencyAmounts(self: Service): (CurrencyAmount, CurrencyAmount) =
|
||||||
const ethSymbol = "ETH"
|
let ethCurrency = newCurrencyAmount(0.0, ethSymbol, 1, false)
|
||||||
if jsonNode{"error"}.kind != JNull and jsonNode{"error"}.getStr != "":
|
let fiatCurrency = newCurrencyAmount(0.0, self.settingsService.getCurrency(), 1, false)
|
||||||
let errorMessage = jsonNode["error"].getStr
|
return (ethCurrency, fiatCurrency)
|
||||||
var errorCode = ComputeFeeErrorCode.Other
|
|
||||||
if errorMessage.contains("403 Forbidden") or errorMessage.contains("exceed"):
|
|
||||||
errorCode = ComputeFeeErrorCode.Infura
|
|
||||||
let ethCurrency = newCurrencyAmount(0.0, ethSymbol, 1, false)
|
|
||||||
let fiatCurrency = newCurrencyAmount(0.0, self.settingsService.getCurrency(), 1, false)
|
|
||||||
return ComputeFeeArgs(ethCurrency: ethCurrency, fiatCurrency: fiatCurrency, errorCode: errorCode)
|
|
||||||
let suggestedFees = decodeSuggestedFeesDto(jsonNode["fees"])
|
|
||||||
# save suggested fees and use during operation, we always compute fees before operation
|
|
||||||
self.tempSuggestedFees = suggestedFees
|
|
||||||
self.tempGasUnits = gasUnits
|
|
||||||
let maxFees = suggestedFees.maxFeePerGasM
|
|
||||||
let gasPrice = if suggestedFees.eip1559Enabled: maxFees else: suggestedFees.gasPrice
|
|
||||||
|
|
||||||
let weiValue = gwei2Wei(gasPrice) * gasUnits.u256
|
proc createCurrencyAmounts(self: Service, ethValue: float64, fiatValue: float64): (CurrencyAmount, CurrencyAmount) =
|
||||||
let ethValueStr = wei2Eth(weiValue)
|
let ethCurrency = newCurrencyAmount(ethValue, ethSymbol, 4, false)
|
||||||
let ethValue = parseFloat(ethValueStr)
|
let fiatCurrency = newCurrencyAmount(fiatValue, self.settingsService.getCurrency(), 2, false)
|
||||||
let fiatValue = self.getFiatValue(ethValue, ethSymbol)
|
return (ethCurrency, fiatCurrency)
|
||||||
|
|
||||||
|
proc getErrorCodeFromMessage(self: Service, errorMessage: string): ComputeFeeErrorCode =
|
||||||
|
var errorCode = ComputeFeeErrorCode.Other
|
||||||
|
if errorMessage.contains("403 Forbidden") or errorMessage.contains("exceed"):
|
||||||
|
errorCode = ComputeFeeErrorCode.Infura
|
||||||
|
return errorCode
|
||||||
|
|
||||||
|
proc createComputeFeeArgsWithError(self:Service, errorMessage: string): ComputeFeeArgs =
|
||||||
|
let errorCode = self.getErrorCodeFromMessage(errorMessage)
|
||||||
|
let (ethCurrency, fiatCurrency) = self.create0CurrencyAmounts()
|
||||||
|
return ComputeFeeArgs(ethCurrency: ethCurrency, fiatCurrency: fiatCurrency, errorCode: errorCode)
|
||||||
|
|
||||||
|
proc computeEthValue(self:Service, gasUnits: int, suggestedFees: SuggestedFeesDto): float =
|
||||||
|
try:
|
||||||
|
let maxFees = suggestedFees.maxFeePerGasM
|
||||||
|
let gasPrice = if suggestedFees.eip1559Enabled: maxFees else: suggestedFees.gasPrice
|
||||||
|
|
||||||
|
let weiValue = gwei2Wei(gasPrice) * gasUnits.u256
|
||||||
|
let ethValueStr = wei2Eth(weiValue)
|
||||||
|
return parseFloat(ethValueStr)
|
||||||
|
except Exception as e:
|
||||||
|
error "Error computing eth value", msg = e.msg
|
||||||
|
|
||||||
|
proc getWalletBalanceForChain(self:Service, walletAddress: string, chainId: int): float =
|
||||||
let wallet = self.walletAccountService.getAccountByAddress(walletAddress.toLower())
|
let wallet = self.walletAccountService.getAccountByAddress(walletAddress.toLower())
|
||||||
var balance = 0.0
|
var balance = 0.0
|
||||||
let tokens = wallet.tokens
|
let tokens = wallet.tokens
|
||||||
|
@ -451,23 +524,131 @@ QtObject:
|
||||||
if token.symbol == ethSymbol:
|
if token.symbol == ethSymbol:
|
||||||
balance = token.balancesPerChain[chainId].balance
|
balance = token.balancesPerChain[chainId].balance
|
||||||
break
|
break
|
||||||
|
return balance
|
||||||
|
|
||||||
let ethCurrency = newCurrencyAmount(ethValue, ethSymbol, 4, false)
|
proc createComputeFeeArgsFromEthAndBalance(self: Service, ethValue: float, balance: float): ComputeFeeArgs =
|
||||||
let fiatCurrency = newCurrencyAmount(fiatValue, self.settingsService.getCurrency(), 2, false)
|
let fiatValue = self.getFiatValue(ethValue, ethSymbol)
|
||||||
|
let (ethCurrency, fiatCurrency) = self.createCurrencyAmounts(ethValue, fiatValue)
|
||||||
return ComputeFeeArgs(ethCurrency: ethCurrency, fiatCurrency: fiatCurrency,
|
return ComputeFeeArgs(ethCurrency: ethCurrency, fiatCurrency: fiatCurrency,
|
||||||
errorCode: (if ethValue > balance: ComputeFeeErrorCode.Balance else: ComputeFeeErrorCode.Success))
|
errorCode: (if ethValue > balance: ComputeFeeErrorCode.Balance else: ComputeFeeErrorCode.Success))
|
||||||
|
|
||||||
|
proc createComputeFeeArgs(self: Service, gasUnits: int, suggestedFees: SuggestedFeesDto, chainId: int, walletAddress: string): ComputeFeeArgs =
|
||||||
|
let ethValue = self.computeEthValue(gasUnits, suggestedFees)
|
||||||
|
let balance = self.getWalletBalanceForChain(walletAddress, chainId)
|
||||||
|
return self.createComputeFeeArgsFromEthAndBalance(ethValue, balance)
|
||||||
|
|
||||||
|
# convert json returned from async task into gas table
|
||||||
|
proc toGasTable(json: JsonNode): Table[ContractTuple, int] =
|
||||||
|
try:
|
||||||
|
if json.kind != JArray:
|
||||||
|
return
|
||||||
|
for i in json:
|
||||||
|
result[i["key"].toContractTuple] = i["value"].getInt
|
||||||
|
except Exception:
|
||||||
|
error "Error converting to gas table", message = getCurrentExceptionMsg()
|
||||||
|
|
||||||
|
# convert json returned from async task into fee table
|
||||||
|
proc toFeeTable(json: JsonNode): Table[int, SuggestedFeesDto] =
|
||||||
|
try:
|
||||||
|
if json.kind != JArray:
|
||||||
|
return
|
||||||
|
for i in json:
|
||||||
|
result[i["key"].getInt] = decodeSuggestedFeesDto(i["value"])
|
||||||
|
except Exception:
|
||||||
|
error "Error converting to fee table", message = getCurrentExceptionMsg()
|
||||||
|
|
||||||
|
proc parseFeeResponseAndEmitSignal(self:Service, response: string, signalName: string) =
|
||||||
|
try:
|
||||||
|
let responseJson = response.parseJson()
|
||||||
|
let errorMessage = responseJson{"error"}.getStr
|
||||||
|
if errorMessage != "":
|
||||||
|
let data = self.createComputeFeeArgsWithError(errorMessage)
|
||||||
|
self.events.emit(signalName, data)
|
||||||
|
return
|
||||||
|
let gasTable = responseJson{"gasTable"}.toGasTable
|
||||||
|
let feeTable = responseJson{"feeTable"}.toFeeTable
|
||||||
|
self.tempGasTable = gasTable
|
||||||
|
self.tempFeeTable = feeTable
|
||||||
|
let gasUnits = toSeq(gasTable.values())[0]
|
||||||
|
let suggestedFees = toSeq(feeTable.values())[0]
|
||||||
|
let data = self.createComputeFeeArgs(gasUnits, suggestedFees, self.tempChainId, self.tempAccountAddress)
|
||||||
|
self.events.emit(signalName, data)
|
||||||
|
except Exception:
|
||||||
|
error "Error creating self destruct fee args", message = getCurrentExceptionMsg()
|
||||||
|
let data = self.createComputeFeeArgsWithError(getCurrentExceptionMsg())
|
||||||
|
self.events.emit(signalName, data)
|
||||||
|
|
||||||
proc onSelfDestructFees*(self:Service, response: string) {.slot.} =
|
proc onSelfDestructFees*(self:Service, response: string) {.slot.} =
|
||||||
let responseJson = response.parseJson()
|
self.parseFeeResponseAndEmitSignal(response, SIGNAL_COMPUTE_SELF_DESTRUCT_FEE)
|
||||||
let burnGas = if responseJson{"burnGas"}.kind != JNull: responseJson{"burnGas"}.getInt else: 0
|
|
||||||
let data = self.createComputeFeeArgs(responseJson, burnGas, self.tempChainId, self.tempAccountAddress)
|
|
||||||
self.events.emit(SIGNAL_COMPUTE_SELF_DESTRUCT_FEE, data)
|
|
||||||
|
|
||||||
proc onDeployFees*(self:Service, response: string) {.slot.} =
|
proc onDeployFees*(self:Service, response: string) {.slot.} =
|
||||||
let responseJson = response.parseJson()
|
self.parseFeeResponseAndEmitSignal(response, SIGNAL_COMPUTE_DEPLOY_FEE)
|
||||||
let data = self.createComputeFeeArgs(responseJson, self.deployCollectiblesEstimate(), self.tempChainId, self.tempAccountAddress)
|
|
||||||
self.events.emit(SIGNAL_COMPUTE_DEPLOY_FEE, data)
|
proc onAirdropFees*(self:Service, response: string) {.slot.} =
|
||||||
|
var wholeEthCostForChainWallet: Table[ChainWalletTuple, float]
|
||||||
|
var ethValuesForContracts: Table[ContractTuple, float]
|
||||||
|
var allComputeFeeArgs: seq[ComputeFeeArgs]
|
||||||
|
var dataToEmit = AirdropFeesArgs()
|
||||||
|
dataToEmit.errorCode = ComputeFeeErrorCode.Success
|
||||||
|
|
||||||
|
try:
|
||||||
|
let responseJson = response.parseJson()
|
||||||
|
let errorMessage = responseJson{"error"}.getStr
|
||||||
|
if errorMessage != "":
|
||||||
|
for collectibleAndAmount in self.tempTokensAndAmounts:
|
||||||
|
let args = self.createComputeFeeArgsWithError(errorMessage)
|
||||||
|
args.contractUniqueKey = common_utils.contractUniqueKey(collectibleAndAmount.communityToken.chainId, collectibleAndAmount.communityToken.address)
|
||||||
|
dataToEmit.fees.add(args)
|
||||||
|
let (ethTotal, fiatTotal) = self.create0CurrencyAmounts()
|
||||||
|
dataToEmit.totalEthFee = ethTotal
|
||||||
|
dataToEmit.totalFiatFee = fiatTotal
|
||||||
|
dataToEmit.errorCode = self.getErrorCodeFromMessage(errorMessage)
|
||||||
|
self.events.emit(SIGNAL_COMPUTE_AIRDROP_FEE, dataToEmit)
|
||||||
|
return
|
||||||
|
|
||||||
|
let gasTable = responseJson{"gasTable"}.toGasTable
|
||||||
|
let feeTable = responseJson{"feeTable"}.toFeeTable
|
||||||
|
self.tempGasTable = gasTable
|
||||||
|
self.tempFeeTable = feeTable
|
||||||
|
|
||||||
|
# compute eth cost for every contract
|
||||||
|
# also sum all eth costs per (chain, wallet) - it will be needed to compare with (chain, wallet) balance
|
||||||
|
for collectibleAndAmount in self.tempTokensAndAmounts:
|
||||||
|
let gasUnits = self.tempGasTable[(collectibleAndAmount.communityToken.chainId, collectibleAndAmount.communityToken.address)]
|
||||||
|
let suggestedFees = self.tempFeeTable[collectibleAndAmount.communityToken.chainId]
|
||||||
|
let ethValue = self.computeEthValue(gasUnits, suggestedFees)
|
||||||
|
let walletAddress = self.contractOwner(collectibleAndAmount.communityToken.chainId, collectibleAndAmount.communityToken.address)
|
||||||
|
wholeEthCostForChainWallet[(collectibleAndAmount.communityToken.chainId, walletAddress)] = wholeEthCostForChainWallet.getOrDefault((collectibleAndAmount.communityToken.chainId, walletAddress), 0.0) + ethValue
|
||||||
|
ethValuesForContracts[(collectibleAndAmount.communityToken.chainId, collectibleAndAmount.communityToken.address)] = ethValue
|
||||||
|
|
||||||
|
var totalEthVal = 0.0
|
||||||
|
var totalFiatVal = 0.0
|
||||||
|
# for every contract create cost Args
|
||||||
|
for collectibleAndAmount in self.tempTokensAndAmounts:
|
||||||
|
let contractTuple = (chainId: collectibleAndAmount.communityToken.chainId,
|
||||||
|
address: collectibleAndAmount.communityToken.address)
|
||||||
|
let ethValue = ethValuesForContracts[contractTuple]
|
||||||
|
let walletAddress = self.contractOwner(contractTuple.chainId, contractTuple.address)
|
||||||
|
var balance = self.getWalletBalanceForChain(walletAddress, contractTuple.chainId)
|
||||||
|
if balance < wholeEthCostForChainWallet[(contractTuple.chainId, walletAddress)]:
|
||||||
|
# if wallet balance for this chain is less than the whole cost
|
||||||
|
# then we can't afford it; setting balance to 0.0 will set balance error code in Args
|
||||||
|
balance = 0.0
|
||||||
|
dataToEmit.errorCode = ComputeFeeErrorCode.Balance # set total error code to balance error
|
||||||
|
var args = self.createComputeFeeArgsFromEthAndBalance(ethValue, balance)
|
||||||
|
totalEthVal = totalEthVal + ethValue
|
||||||
|
totalFiatVal = totalFiatVal + args.fiatCurrency.getAmountFloat()
|
||||||
|
args.contractUniqueKey = common_utils.contractUniqueKey(collectibleAndAmount.communityToken.chainId, collectibleAndAmount.communityToken.address)
|
||||||
|
allComputeFeeArgs.add(args)
|
||||||
|
|
||||||
|
dataToEmit.fees = allComputeFeeArgs
|
||||||
|
let (ethTotal, fiatTotal) = self.createCurrencyAmounts(totalEthVal, totalFiatVal)
|
||||||
|
dataToEmit.totalEthFee = ethTotal
|
||||||
|
dataToEmit.totalFiatFee = fiatTotal
|
||||||
|
self.events.emit(SIGNAL_COMPUTE_AIRDROP_FEE, dataToEmit)
|
||||||
|
|
||||||
|
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, communityId: string, chainId: int, contractAddress: string) =
|
||||||
let arg = FetchCollectibleOwnersArg(
|
let arg = FetchCollectibleOwnersArg(
|
||||||
|
@ -482,7 +663,7 @@ QtObject:
|
||||||
|
|
||||||
# get owners from cache
|
# get owners from cache
|
||||||
proc getCommunityTokenOwners*(self: Service, communityId: string, chainId: int, contractAddress: string): seq[CollectibleOwner] =
|
proc getCommunityTokenOwners*(self: Service, communityId: string, chainId: int, contractAddress: string): seq[CollectibleOwner] =
|
||||||
return self.tokenOwnersCache.getOrDefault((address: contractAddress, chainId: chainId))
|
return self.tokenOwnersCache.getOrDefault((chainId: chainId, address: contractAddress))
|
||||||
|
|
||||||
proc onCommunityTokenOwnersFetched*(self:Service, response: string) {.slot.} =
|
proc onCommunityTokenOwnersFetched*(self:Service, response: string) {.slot.} =
|
||||||
let responseJson = response.parseJson()
|
let responseJson = response.parseJson()
|
||||||
|
@ -496,7 +677,7 @@ QtObject:
|
||||||
let resultJson = responseJson["result"]
|
let resultJson = responseJson["result"]
|
||||||
var owners = collectibles_dto.toCollectibleOwnershipDto(resultJson).owners
|
var owners = collectibles_dto.toCollectibleOwnershipDto(resultJson).owners
|
||||||
owners = owners.filter(x => x.address != ZERO_ADDRESS)
|
owners = owners.filter(x => x.address != ZERO_ADDRESS)
|
||||||
self.tokenOwnersCache[(contractAddress, chainId)] = owners
|
self.tokenOwnersCache[(chainId, contractAddress)] = owners
|
||||||
let data = CommunityTokenOwnersArgs(chainId: chainId, contractAddress: contractAddress, communityId: communityId, owners: owners)
|
let data = CommunityTokenOwnersArgs(chainId: chainId, contractAddress: contractAddress, communityId: communityId, owners: owners)
|
||||||
self.events.emit(SIGNAL_COMMUNITY_TOKEN_OWNERS_FETCHED, data)
|
self.events.emit(SIGNAL_COMMUNITY_TOKEN_OWNERS_FETCHED, data)
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,10 @@ proc mintTo*(chainId: int, contractAddress: string, txData: JsonNode, password:
|
||||||
let payload = %* [chainId, contractAddress, txData, utils.hashPassword(password), walletAddresses, amount]
|
let payload = %* [chainId, contractAddress, txData, utils.hashPassword(password), walletAddresses, amount]
|
||||||
return core.callPrivateRPC("collectibles_mintTo", payload)
|
return core.callPrivateRPC("collectibles_mintTo", 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 remoteBurn*(chainId: int, contractAddress: string, txData: JsonNode, password: string, tokenIds: seq[UInt256]): RpcResponse[JsonNode] {.raises: [Exception].} =
|
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))]
|
let payload = %* [chainId, contractAddress, txData, utils.hashPassword(password), tokenIds.map(x => x.toString(10))]
|
||||||
return core.callPrivateRPC("collectibles_remoteBurn", payload)
|
return core.callPrivateRPC("collectibles_remoteBurn", payload)
|
||||||
|
|
|
@ -79,7 +79,8 @@ StatusScrollView {
|
||||||
networkText: modelItem.chainName,
|
networkText: modelItem.chainName,
|
||||||
networkImage: Style.svg(modelItem.chainIcon),
|
networkImage: Style.svg(modelItem.chainIcon),
|
||||||
supply: modelItem.supply,
|
supply: modelItem.supply,
|
||||||
infiniteSupply: modelItem.infiniteSupply
|
infiniteSupply: modelItem.infiniteSupply,
|
||||||
|
contractUniqueKey: modelItem.contractUniqueKey,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -402,7 +403,7 @@ StatusScrollView {
|
||||||
onClicked: {
|
onClicked: {
|
||||||
const airdropTokens = ModelUtils.modelToArray(
|
const airdropTokens = ModelUtils.modelToArray(
|
||||||
root.selectedHoldingsModel,
|
root.selectedHoldingsModel,
|
||||||
["key", "amount"])
|
["contractUniqueKey", "amount"])
|
||||||
|
|
||||||
const addresses_ = ModelUtils.modelToArray(
|
const addresses_ = ModelUtils.modelToArray(
|
||||||
addresses, ["address"]).map(e => e.address)
|
addresses, ["address"]).map(e => e.address)
|
||||||
|
|
|
@ -58,6 +58,10 @@ QtObject {
|
||||||
function onSelfDestructFeeUpdated(ethCurrency, fiatCurrency, errorCode) {
|
function onSelfDestructFeeUpdated(ethCurrency, fiatCurrency, errorCode) {
|
||||||
root.selfDestructFeeUpdated(ethCurrency, fiatCurrency, errorCode)
|
root.selfDestructFeeUpdated(ethCurrency, fiatCurrency, errorCode)
|
||||||
}
|
}
|
||||||
|
function onAirdropFeesUpdated(jsonFees) {
|
||||||
|
console.log("Fees:", jsonFees)
|
||||||
|
}
|
||||||
|
|
||||||
function onDeploymentStateChanged(communityId, status, url) {
|
function onDeploymentStateChanged(communityId, status, url) {
|
||||||
root.deploymentStateChanged(communityId, status, url)
|
root.deploymentStateChanged(communityId, status, url)
|
||||||
}
|
}
|
||||||
|
@ -94,4 +98,8 @@ QtObject {
|
||||||
function airdrop(communityId, airdropTokens, addresses) {
|
function airdrop(communityId, airdropTokens, addresses) {
|
||||||
communityTokensModuleInst.airdropCollectibles(communityId, JSON.stringify(airdropTokens), JSON.stringify(addresses))
|
communityTokensModuleInst.airdropCollectibles(communityId, JSON.stringify(airdropTokens), JSON.stringify(addresses))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function computeAirdropFee(communityId, airdropTokens, addresses) {
|
||||||
|
communityTokensModuleInst.computeAirdropCollectiblesFee(communityId, JSON.stringify(airdropTokens), JSON.stringify(addresses))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue