feat: release ENS names
This commit is contained in:
parent
ef1140d0a7
commit
80343446ec
|
@ -11,7 +11,7 @@ import ../../../status/wallet
|
||||||
import sets
|
import sets
|
||||||
import web3/ethtypes
|
import web3/ethtypes
|
||||||
import ../../../status/tasks/[qt, task_runner_impl]
|
import ../../../status/tasks/[qt, task_runner_impl]
|
||||||
|
import chronicles
|
||||||
type
|
type
|
||||||
EnsRoles {.pure.} = enum
|
EnsRoles {.pure.} = enum
|
||||||
UserName = UserRole + 1
|
UserName = UserRole + 1
|
||||||
|
@ -45,10 +45,20 @@ const detailsTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
arg = decode[DetailsTaskArg](argEncoded)
|
arg = decode[DetailsTaskArg](argEncoded)
|
||||||
address = status_ens.address(arg.username)
|
address = status_ens.address(arg.username)
|
||||||
pubkey = status_ens.pubkey(arg.username)
|
pubkey = status_ens.pubkey(arg.username)
|
||||||
json = %* {
|
|
||||||
|
var isStatus:bool = false
|
||||||
|
var expirationTime:int = 0
|
||||||
|
if arg.username.endsWith(domain):
|
||||||
|
isStatus = true
|
||||||
|
var success = false
|
||||||
|
expirationTime = status_ens.getExpirationTime(arg.username.replace(domain, ""), success)
|
||||||
|
|
||||||
|
let json = %* {
|
||||||
"ensName": arg.username,
|
"ensName": arg.username,
|
||||||
"address": address,
|
"address": address,
|
||||||
"pubkey": pubkey
|
"pubkey": pubkey,
|
||||||
|
"isStatus": isStatus,
|
||||||
|
"expirationTime": expirationTime
|
||||||
}
|
}
|
||||||
arg.finish(json)
|
arg.finish(json)
|
||||||
|
|
||||||
|
@ -87,8 +97,9 @@ QtObject:
|
||||||
let pendingTransactions = self.status.wallet.getPendingTransactions()
|
let pendingTransactions = self.status.wallet.getPendingTransactions()
|
||||||
if (pendingTransactions == ""):
|
if (pendingTransactions == ""):
|
||||||
return
|
return
|
||||||
|
|
||||||
for trx in pendingTransactions.parseJson{"result"}.getElems():
|
for trx in pendingTransactions.parseJson{"result"}.getElems():
|
||||||
if trx["type"].getStr == $PendingTransactionType.RegisterENS:
|
if trx["type"].getStr == $PendingTransactionType.RegisterENS or trx["type"].getStr == $PendingTransactionType.SetPubKey:
|
||||||
self.usernames.add trx["additionalData"].getStr
|
self.usernames.add trx["additionalData"].getStr
|
||||||
self.pendingUsernames.incl trx["additionalData"].getStr
|
self.pendingUsernames.incl trx["additionalData"].getStr
|
||||||
|
|
||||||
|
@ -106,6 +117,19 @@ QtObject:
|
||||||
self.usernames.add(username)
|
self.usernames.add(username)
|
||||||
self.endInsertRows()
|
self.endInsertRows()
|
||||||
|
|
||||||
|
proc remove*(self: EnsManager, username: string) =
|
||||||
|
var idx = -1
|
||||||
|
var i = 0
|
||||||
|
for u in self.usernames:
|
||||||
|
if u == username:
|
||||||
|
idx = i
|
||||||
|
break
|
||||||
|
i = i + 1
|
||||||
|
if idx == -1: return
|
||||||
|
self.beginRemoveRows(newQModelIndex(), idx, idx)
|
||||||
|
self.usernames.delete(idx)
|
||||||
|
self.endRemoveRows()
|
||||||
|
|
||||||
proc getPreferredUsername(self: EnsManager): string {.slot.} =
|
proc getPreferredUsername(self: EnsManager): string {.slot.} =
|
||||||
result = self.status.settings.getSetting[:string](Setting.PreferredUsername, "")
|
result = self.status.settings.getSetting[:string](Setting.PreferredUsername, "")
|
||||||
|
|
||||||
|
@ -138,12 +162,12 @@ QtObject:
|
||||||
self.loading(true)
|
self.loading(true)
|
||||||
self.details("setDetails", username)
|
self.details("setDetails", username)
|
||||||
|
|
||||||
proc detailsObtained(self: EnsManager, ensName: string, address: string, pubkey: string) {.signal.}
|
proc detailsObtained(self: EnsManager, ensName: string, address: string, pubkey: string, isStatus: bool, expirationTime: int) {.signal.}
|
||||||
|
|
||||||
proc setDetails(self: EnsManager, details: string): string {.slot.} =
|
proc setDetails(self: EnsManager, details: string): string {.slot.} =
|
||||||
self.loading(false)
|
self.loading(false)
|
||||||
let detailsJson = details.parseJson
|
let detailsJson = details.parseJson
|
||||||
self.detailsObtained(detailsJson["ensName"].getStr, detailsJson["address"].getStr, detailsJson["pubkey"].getStr)
|
self.detailsObtained(detailsJson["ensName"].getStr, detailsJson["address"].getStr, detailsJson["pubkey"].getStr, detailsJson["isStatus"].getBool, detailsJson["expirationTime"].getInt)
|
||||||
|
|
||||||
method rowCount(self: EnsManager, index: QModelIndex = nil): int =
|
method rowCount(self: EnsManager, index: QModelIndex = nil): int =
|
||||||
return self.usernames.len
|
return self.usernames.len
|
||||||
|
@ -228,6 +252,22 @@ QtObject:
|
||||||
self.pendingUsernames.incl(ensUsername)
|
self.pendingUsernames.incl(ensUsername)
|
||||||
self.add ensUsername
|
self.add ensUsername
|
||||||
|
|
||||||
|
proc releaseEstimate(self: EnsManager, ensUsername: string, address: string): int {.slot.} =
|
||||||
|
var success: bool
|
||||||
|
result = releaseEstimateGas(ensUsername, address, success)
|
||||||
|
if not success:
|
||||||
|
result = 100000
|
||||||
|
|
||||||
|
proc release*(self: EnsManager, username: string, address: string, gas: string, gasPrice: string, password: string): string {.slot.} =
|
||||||
|
var success: bool
|
||||||
|
let response = release(username, address, gas, gasPrice, password, success)
|
||||||
|
result = $(%* { "result": %response, "success": %success })
|
||||||
|
|
||||||
|
if success:
|
||||||
|
self.transactionWasSent(response)
|
||||||
|
self.pendingUsernames.excl(username)
|
||||||
|
self.remove(username)
|
||||||
|
|
||||||
proc setPubKeyGasEstimate(self: EnsManager, ensUsername: string, address: string): int {.slot.} =
|
proc setPubKeyGasEstimate(self: EnsManager, ensUsername: string, address: string): int {.slot.} =
|
||||||
var success: bool
|
var success: bool
|
||||||
let pubKey = self.status.settings.getSetting[:string](Setting.PublicKey, "0x0")
|
let pubKey = self.status.settings.getSetting[:string](Setting.PublicKey, "0x0")
|
||||||
|
|
|
@ -16,6 +16,7 @@ import transactions
|
||||||
import algorithm
|
import algorithm
|
||||||
import web3/[ethtypes, conversions], stew/byteutils, stint
|
import web3/[ethtypes, conversions], stew/byteutils, stint
|
||||||
import libstatus/eth/contracts
|
import libstatus/eth/contracts
|
||||||
|
import libstatus/eth/transactions as eth_transactions
|
||||||
import chronicles, libp2p/[multihash, multicodec, cid]
|
import chronicles, libp2p/[multihash, multicodec, cid]
|
||||||
|
|
||||||
import ./settings as status_settings
|
import ./settings as status_settings
|
||||||
|
@ -172,6 +173,54 @@ proc getPrice*(): Stuint[256] =
|
||||||
raise newException(RpcException, "Error getting ens username price: 0x")
|
raise newException(RpcException, "Error getting ens username price: 0x")
|
||||||
result = fromHex(Stuint[256], response.result)
|
result = fromHex(Stuint[256], response.result)
|
||||||
|
|
||||||
|
proc releaseEstimateGas*(username: string, address: string, success: var bool): int =
|
||||||
|
let
|
||||||
|
label = fromHex(FixedBytes[32], label(username))
|
||||||
|
ensUsernamesContract = contracts.getContract("ens-usernames")
|
||||||
|
release = Release(label: label)
|
||||||
|
|
||||||
|
var tx = transactions.buildTokenTransaction(parseAddress(address), ensUsernamesContract.address, "", "")
|
||||||
|
try:
|
||||||
|
let response = ensUsernamesContract.methods["release"].estimateGas(tx, release, success)
|
||||||
|
if success:
|
||||||
|
result = fromHex[int](response)
|
||||||
|
except RpcException as e:
|
||||||
|
raise
|
||||||
|
|
||||||
|
proc release*(username: string, address: string, gas, gasPrice, password: string, success: var bool): string =
|
||||||
|
let
|
||||||
|
label = fromHex(FixedBytes[32], label(username))
|
||||||
|
ensUsernamesContract = contracts.getContract("ens-usernames")
|
||||||
|
release = Release(label: label)
|
||||||
|
|
||||||
|
var tx = transactions.buildTokenTransaction(parseAddress(address), ensUsernamesContract.address, "", "")
|
||||||
|
try:
|
||||||
|
result = ensUsernamesContract.methods["release"].send(tx, release, password, success)
|
||||||
|
if success:
|
||||||
|
trackPendingTransaction(result, address, $ensUsernamesContract.address, PendingTransactionType.ReleaseENS, username)
|
||||||
|
except RpcException as e:
|
||||||
|
raise
|
||||||
|
|
||||||
|
proc getExpirationTime*(username: string, success: var bool): int =
|
||||||
|
let
|
||||||
|
label = fromHex(FixedBytes[32], label(username))
|
||||||
|
expTime = ExpirationTime(label: label)
|
||||||
|
ensUsernamesContract = contracts.getContract("ens-usernames")
|
||||||
|
|
||||||
|
var tx = transactions.buildTransaction(parseAddress("0x0000000000000000000000000000000000000000"), 0.u256)
|
||||||
|
tx.to = ensUsernamesContract.address.some
|
||||||
|
tx.data = ensUsernamesContract.methods["getExpirationTime"].encodeAbi(expTime)
|
||||||
|
var response = ""
|
||||||
|
try:
|
||||||
|
response = eth_transactions.call(tx).result
|
||||||
|
success = true
|
||||||
|
except RpcException as e:
|
||||||
|
success = false
|
||||||
|
error "Error obtaining expiration time", err=e.msg
|
||||||
|
|
||||||
|
if success:
|
||||||
|
result = fromHex[int](response)
|
||||||
|
|
||||||
proc extractCoordinates*(pubkey: string):tuple[x: string, y:string] =
|
proc extractCoordinates*(pubkey: string):tuple[x: string, y:string] =
|
||||||
result = ("0x" & pubkey[4..67], "0x" & pubkey[68..131])
|
result = ("0x" & pubkey[4..67], "0x" & pubkey[68..131])
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,12 @@ type
|
||||||
x*: FixedBytes[32]
|
x*: FixedBytes[32]
|
||||||
y*: FixedBytes[32]
|
y*: FixedBytes[32]
|
||||||
|
|
||||||
|
ExpirationTime* = object
|
||||||
|
label*: FixedBytes[32]
|
||||||
|
|
||||||
|
Release* = object
|
||||||
|
label*: FixedBytes[32]
|
||||||
|
|
||||||
ApproveAndCall*[N: static[int]] = object
|
ApproveAndCall*[N: static[int]] = object
|
||||||
to*: Address
|
to*: Address
|
||||||
value*: Stuint[256]
|
value*: Stuint[256]
|
||||||
|
|
|
@ -10,7 +10,7 @@ import
|
||||||
export
|
export
|
||||||
GetPackData, PackData, BuyToken, ApproveAndCall, Transfer, BalanceOf, Register, SetPubkey,
|
GetPackData, PackData, BuyToken, ApproveAndCall, Transfer, BalanceOf, Register, SetPubkey,
|
||||||
TokenOfOwnerByIndex, TokenPackId, TokenUri, FixedBytes, DynamicBytes, toHex, fromHex,
|
TokenOfOwnerByIndex, TokenPackId, TokenUri, FixedBytes, DynamicBytes, toHex, fromHex,
|
||||||
decodeContractResponse, encodeAbi, estimateGas, send, call
|
decodeContractResponse, encodeAbi, estimateGas, send, call, ExpirationTime, Release
|
||||||
|
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
|
@ -204,7 +204,9 @@ proc allContracts(): seq[Contract] =
|
||||||
Contract(name: "ens-usernames", network: Network.Mainnet, address: parseAddress("0xDB5ac1a559b02E12F29fC0eC0e37Be8E046DEF49"),
|
Contract(name: "ens-usernames", network: Network.Mainnet, address: parseAddress("0xDB5ac1a559b02E12F29fC0eC0e37Be8E046DEF49"),
|
||||||
methods: [
|
methods: [
|
||||||
("register", Method(signature: "register(bytes32,address,bytes32,bytes32)")),
|
("register", Method(signature: "register(bytes32,address,bytes32,bytes32)")),
|
||||||
("getPrice", Method(signature: "getPrice()"))
|
("getPrice", Method(signature: "getPrice()")),
|
||||||
|
("getExpirationTime", Method(signature: "getExpirationTime(bytes32)")),
|
||||||
|
("release", Method(signature: "release(bytes32)"))
|
||||||
].toTable
|
].toTable
|
||||||
),
|
),
|
||||||
Contract(name: "ens-resolver", network: Network.Mainnet, address: parseAddress("0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41"),
|
Contract(name: "ens-resolver", network: Network.Mainnet, address: parseAddress("0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41"),
|
||||||
|
@ -234,10 +236,12 @@ proc allContracts(): seq[Contract] =
|
||||||
),
|
),
|
||||||
newErc721Contract("sticker-pack", Network.Testnet, parseAddress("0xf852198d0385c4b871e0b91804ecd47c6ba97351"), "PACK", false, @[("tokenPackId", Method(signature: "tokenPackId(uint256)"))]),
|
newErc721Contract("sticker-pack", Network.Testnet, parseAddress("0xf852198d0385c4b871e0b91804ecd47c6ba97351"), "PACK", false, @[("tokenPackId", Method(signature: "tokenPackId(uint256)"))]),
|
||||||
newErc721Contract("kudos", Network.Testnet, parseAddress("0xcd520707fc68d153283d518b29ada466f9091ea8"), "KDO", true),
|
newErc721Contract("kudos", Network.Testnet, parseAddress("0xcd520707fc68d153283d518b29ada466f9091ea8"), "KDO", true),
|
||||||
Contract(name: "ens-usernames", network: Network.Testnet, address: parseAddress("0x11d9F481effd20D76cEE832559bd9Aca25405841"),
|
Contract(name: "ens-usernames", network: Network.Testnet, address: parseAddress("0xdaae165beb8c06e0b7613168138ebba774aff071"),
|
||||||
methods: [
|
methods: [
|
||||||
("register", Method(signature: "register(bytes32,address,bytes32,bytes32)")),
|
("register", Method(signature: "register(bytes32,address,bytes32,bytes32)")),
|
||||||
("getPrice", Method(signature: "getPrice()"))
|
("getPrice", Method(signature: "getPrice()")),
|
||||||
|
("getExpirationTime", Method(signature: "getExpirationTime(bytes32)")),
|
||||||
|
("release", Method(signature: "release(bytes32)"))
|
||||||
].toTable
|
].toTable
|
||||||
),
|
),
|
||||||
Contract(name: "ens-resolver", network: Network.Testnet, address: parseAddress("0x42D63ae25990889E35F215bC95884039Ba354115"),
|
Contract(name: "ens-resolver", network: Network.Testnet, address: parseAddress("0x42D63ae25990889E35F215bC95884039Ba354115"),
|
||||||
|
|
|
@ -24,7 +24,7 @@ proc sendTransaction*(tx: EthSend, password: string): RpcResponse =
|
||||||
trace "Transaction sent succesfully", hash=result.result
|
trace "Transaction sent succesfully", hash=result.result
|
||||||
|
|
||||||
proc call*(tx: EthSend): RpcResponse =
|
proc call*(tx: EthSend): RpcResponse =
|
||||||
let responseStr = core.callPrivateRPC("eth_call", %*[%tx])
|
let responseStr = core.callPrivateRPC("eth_call", %*[%tx, "latest"])
|
||||||
result = Json.decode(responseStr, RpcResponse)
|
result = Json.decode(responseStr, RpcResponse)
|
||||||
if not result.error.isNil:
|
if not result.error.isNil:
|
||||||
raise newException(RpcException, "Error calling method: " & result.error.message)
|
raise newException(RpcException, "Error calling method: " & result.error.message)
|
|
@ -10,8 +10,10 @@ Item {
|
||||||
property string username: ""
|
property string username: ""
|
||||||
property string walletAddress: "-"
|
property string walletAddress: "-"
|
||||||
property string key: "-"
|
property string key: "-"
|
||||||
|
property var expiration: 0
|
||||||
|
|
||||||
signal backBtnClicked();
|
signal backBtnClicked();
|
||||||
|
signal usernameReleased(username: string);
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
id: sectionTitle
|
id: sectionTitle
|
||||||
|
@ -49,12 +51,17 @@ Item {
|
||||||
keyLbl.textToCopy = pubkey;
|
keyLbl.textToCopy = pubkey;
|
||||||
walletAddressLbl.visible = true;
|
walletAddressLbl.visible = true;
|
||||||
keyLbl.visible = true;
|
keyLbl.visible = true;
|
||||||
|
releaseBtn.visible = isStatus
|
||||||
|
releaseBtn.enabled = (Date.now() / 1000) > expirationTime && expirationTime > 0 && profileModel.ens.preferredUsername != username
|
||||||
|
expiration = new Date(expirationTime * 1000).getTime()
|
||||||
}
|
}
|
||||||
onLoading: {
|
onLoading: {
|
||||||
loadingImg.active = isLoading
|
loadingImg.active = isLoading
|
||||||
if(!isLoading) return;
|
if(!isLoading) return;
|
||||||
walletAddressLbl.visible = false;
|
walletAddressLbl.visible = false;
|
||||||
keyLbl.visible = false;
|
keyLbl.visible = false;
|
||||||
|
releaseBtn.visible = false;
|
||||||
|
expiration = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,6 +91,63 @@ Item {
|
||||||
anchors.topMargin: 24
|
anchors.topMargin: 24
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: transactionDialogComponent
|
||||||
|
StatusETHTransactionModal {
|
||||||
|
onOpened: {
|
||||||
|
walletModel.gasView.getGasPricePredictions()
|
||||||
|
}
|
||||||
|
title: qsTr("Connect username with your pubkey")
|
||||||
|
onClosed: {
|
||||||
|
destroy()
|
||||||
|
}
|
||||||
|
estimateGasFunction: function(selectedAccount) {
|
||||||
|
if (username === "" || !selectedAccount) return 100000;
|
||||||
|
return profileModel.ens.releaseEstimate(Utils.removeStatusEns(username), selectedAccount.address)
|
||||||
|
}
|
||||||
|
onSendTransaction: function(selectedAddress, gasLimit, gasPrice, password) {
|
||||||
|
return profileModel.ens.release(username,
|
||||||
|
selectedAddress,
|
||||||
|
gasLimit,
|
||||||
|
gasPrice,
|
||||||
|
password)
|
||||||
|
}
|
||||||
|
onSuccess: function(){
|
||||||
|
usernameReleased(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
width: 475
|
||||||
|
height: 500
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusButton {
|
||||||
|
id: releaseBtn
|
||||||
|
visible: false
|
||||||
|
enabled: false
|
||||||
|
anchors.top: keyLbl.bottom
|
||||||
|
anchors.topMargin: 24
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: 24
|
||||||
|
text: qsTrId("Release username")
|
||||||
|
onClicked: {
|
||||||
|
openPopup(transactionDialogComponent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
visible: releaseBtn.visible && !releaseBtn.enabled
|
||||||
|
anchors.top: releaseBtn.bottom
|
||||||
|
anchors.topMargin: 2
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: 24
|
||||||
|
text: profileModel.ens.preferredUsername != username ?
|
||||||
|
qsTr("Username locked. You won’t be able to release it until %1").arg(Utils.formatShortDateStr(new Date(expiration).toDateString())):
|
||||||
|
qsTr("This is current preferred username. It can't be released")
|
||||||
|
color: Style.current.darkGrey
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
StatusButton {
|
StatusButton {
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.bottomMargin: Style.current.padding
|
anchors.bottomMargin: Style.current.padding
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
import QtQuick 2.14
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
import QtQuick.Controls 2.14
|
||||||
|
import "../../../../../imports"
|
||||||
|
import "../../../../../shared"
|
||||||
|
import "../../../../../shared/status"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property string ensUsername: ""
|
||||||
|
signal okBtnClicked()
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: sectionTitle
|
||||||
|
//% "ENS usernames"
|
||||||
|
text: qsTrId("ens-usernames")
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: Style.current.bigPadding
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: Style.current.bigPadding
|
||||||
|
font.weight: Font.Bold
|
||||||
|
font.pixelSize: 20
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: circle
|
||||||
|
anchors.top: sectionTitle.bottom
|
||||||
|
anchors.topMargin: Style.current.bigPadding
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
width: 60
|
||||||
|
height: 60
|
||||||
|
radius: 120
|
||||||
|
color: Style.current.blue
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "✓"
|
||||||
|
opacity: 0.7
|
||||||
|
font.weight: Font.Bold
|
||||||
|
font.pixelSize: 18
|
||||||
|
color: Style.current.white
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: title
|
||||||
|
text: qsTr("Username removed")
|
||||||
|
anchors.top: circle.bottom
|
||||||
|
anchors.topMargin: Style.current.bigPadding
|
||||||
|
font.weight: Font.Bold
|
||||||
|
font.pixelSize: 24
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: subtitle
|
||||||
|
text: qsTr("The username %1 will be removed and your deposit will be returned once the transaction is mined").arg(ensUsername)
|
||||||
|
anchors.top: title.bottom
|
||||||
|
anchors.topMargin: 24
|
||||||
|
font.pixelSize: 14
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: progress
|
||||||
|
//% "You can follow the progress in the Transaction History section of your wallet."
|
||||||
|
text: qsTrId("ens-username-you-can-follow-progress")
|
||||||
|
anchors.top: subtitle.bottom
|
||||||
|
anchors.topMargin: 24
|
||||||
|
font.pixelSize: 12
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
color: Style.current.secondaryText
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusButton {
|
||||||
|
id: startBtn
|
||||||
|
anchors.top: progress.bottom
|
||||||
|
anchors.topMargin: Style.current.padding
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
//% "Ok, got it"
|
||||||
|
text: qsTrId("ens-got-it")
|
||||||
|
onClicked: okBtnClicked()
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,25 +47,33 @@ Item {
|
||||||
Qt.callLater(validateENS, ensUsername, isStatus)
|
Qt.callLater(validateENS, ensUsername, isStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Component {
|
||||||
id: transactionDialog
|
id: transactionDialogComponent
|
||||||
function open() {
|
StatusETHTransactionModal {
|
||||||
this.active = true
|
|
||||||
this.item.open()
|
|
||||||
}
|
|
||||||
function closed() {
|
|
||||||
this.active = false // kill an opened instance
|
|
||||||
}
|
|
||||||
sourceComponent: SetPubKeyModal {
|
|
||||||
onOpened: {
|
onOpened: {
|
||||||
walletModel.gasView.getGasPricePredictions()
|
walletModel.gasView.getGasPricePredictions()
|
||||||
}
|
}
|
||||||
|
title: qsTr("Connect username with your pubkey")
|
||||||
onClosed: {
|
onClosed: {
|
||||||
transactionDialog.closed()
|
destroy()
|
||||||
}
|
}
|
||||||
ensUsername: ensUsername.text || ""
|
estimateGasFunction: function(selectedAccount) {
|
||||||
width: 400
|
if (ensUsername.text === "" || !selectedAccount) return 80000;
|
||||||
height: 400
|
return profileModel.ens.setPubKeyGasEstimate(ensUsername.text + (isStatus ? ".stateofus.eth" : "" ), selectedAccount.address)
|
||||||
|
}
|
||||||
|
onSendTransaction: function(selectedAddress, gasLimit, gasPrice, password) {
|
||||||
|
return profileModel.ens.setPubKey(ensUsername.text + (isStatus ? ".stateofus.eth" : "" ),
|
||||||
|
selectedAddress,
|
||||||
|
gasLimit,
|
||||||
|
gasPrice,
|
||||||
|
password)
|
||||||
|
}
|
||||||
|
onSuccess: function(){
|
||||||
|
usernameUpdated(ensUsername.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
width: 475
|
||||||
|
height: 500
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +189,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ensStatus === Constants.ens_connected_dkey || ensStatus === Constants.ens_owned){
|
if(ensStatus === Constants.ens_connected_dkey || ensStatus === Constants.ens_owned){
|
||||||
transactionDialog.open();
|
openPopup(transactionDialogComponent)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,6 +140,10 @@ Item {
|
||||||
targetState: welcomeState
|
targetState: welcomeState
|
||||||
signal: goToWelcome
|
signal: goToWelcome
|
||||||
}
|
}
|
||||||
|
DSM.SignalTransition {
|
||||||
|
targetState: ensReleasedState
|
||||||
|
signal: done
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DSM.State {
|
DSM.State {
|
||||||
|
@ -176,6 +180,15 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DSM.State {
|
||||||
|
id: ensReleasedState
|
||||||
|
onEntered:loader.sourceComponent = ensReleased
|
||||||
|
DSM.SignalTransition {
|
||||||
|
targetState: listState
|
||||||
|
signal: next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DSM.State {
|
DSM.State {
|
||||||
id: ensConnectedState
|
id: ensConnectedState
|
||||||
onEntered:loader.sourceComponent = ensConnected
|
onEntered:loader.sourceComponent = ensConnected
|
||||||
|
@ -240,6 +253,14 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: ensReleased
|
||||||
|
ENSReleased {
|
||||||
|
ensUsername: selectedUsername
|
||||||
|
onOkBtnClicked: next(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: ensConnected
|
id: ensConnected
|
||||||
ENSConnected {
|
ENSConnected {
|
||||||
|
@ -265,6 +286,10 @@ Item {
|
||||||
ENSDetails {
|
ENSDetails {
|
||||||
username: selectedUsername
|
username: selectedUsername
|
||||||
onBackBtnClicked: back();
|
onBackBtnClicked: back();
|
||||||
|
onUsernameReleased: {
|
||||||
|
selectedUsername = username;
|
||||||
|
done(username);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,17 +2,52 @@ import QtQuick 2.13
|
||||||
import QtQuick.Controls 2.13
|
import QtQuick.Controls 2.13
|
||||||
import QtQuick.Layouts 1.13
|
import QtQuick.Layouts 1.13
|
||||||
import QtQuick.Dialogs 1.3
|
import QtQuick.Dialogs 1.3
|
||||||
import "../../../../../imports"
|
import "../../imports"
|
||||||
import "../../../../../shared"
|
import "../../shared"
|
||||||
import "../../../../../shared/status"
|
import "../../shared/status"
|
||||||
|
|
||||||
ModalPopup {
|
ModalPopup {
|
||||||
id: root
|
id: root
|
||||||
readonly property var asset: {"name": "Ethereum", "symbol": "ETH"}
|
readonly property var asset: {"name": "Ethereum", "symbol": "ETH"}
|
||||||
property string ensUsername: ""
|
|
||||||
|
|
||||||
//% "Connect username with your pubkey"
|
title: qsTr("Contract interaction")
|
||||||
title: qsTrId("connect-username-with-your-pubkey")
|
|
||||||
|
property var estimateGasFunction: (function(userAddress) { return 0; })
|
||||||
|
property var onSendTransaction: (function(userAddress, gasLimit, gasPrice, password){ return ""; })
|
||||||
|
property var onSuccess: (function(){})
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
walletModel.gasView.getGasPricePredictions()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function sendTransaction() {
|
||||||
|
try {
|
||||||
|
let responseStr = onSendTransaction(selectFromAccount.selectedAccount.address,
|
||||||
|
gasSelector.selectedGasLimit,
|
||||||
|
gasSelector.selectedGasPrice,
|
||||||
|
transactionSigner.enteredPassword);
|
||||||
|
|
||||||
|
let response = JSON.parse(responseStr)
|
||||||
|
|
||||||
|
if (!response.success) {
|
||||||
|
if (Utils.isInvalidPasswordMessage(response.result)){
|
||||||
|
//% "Wrong password"
|
||||||
|
transactionSigner.validationError = qsTrId("wrong-password")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sendingError.text = response.result
|
||||||
|
return sendingError.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuccess();
|
||||||
|
root.close();
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error sending the transaction', e)
|
||||||
|
sendingError.text = "Error sending the transaction: " + e.message;
|
||||||
|
return sendingError.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
property MessageDialog sendingError: MessageDialog {
|
property MessageDialog sendingError: MessageDialog {
|
||||||
id: sendingError
|
id: sendingError
|
||||||
|
@ -22,33 +57,6 @@ ModalPopup {
|
||||||
standardButtons: StandardButton.Ok
|
standardButtons: StandardButton.Ok
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendTransaction() {
|
|
||||||
try {
|
|
||||||
let responseStr = profileModel.ens.setPubKey(root.ensUsername,
|
|
||||||
selectFromAccount.selectedAccount.address,
|
|
||||||
gasSelector.selectedGasLimit,
|
|
||||||
gasSelector.selectedGasPrice,
|
|
||||||
transactionSigner.enteredPassword)
|
|
||||||
let response = JSON.parse(responseStr)
|
|
||||||
|
|
||||||
if (!response.success) {
|
|
||||||
if (Utils.isInvalidPasswordMessage(response.error.message)){
|
|
||||||
//% "Wrong password"
|
|
||||||
transactionSigner.validationError = qsTrId("wrong-password")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
sendingError.text = response.error.message
|
|
||||||
return sendingError.open()
|
|
||||||
}
|
|
||||||
|
|
||||||
usernameUpdated(root.ensUsername);
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Error sending the transaction', e)
|
|
||||||
sendingError.text = "Error sending the transaction: " + e.message;
|
|
||||||
return sendingError.open()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TransactionStackView {
|
TransactionStackView {
|
||||||
id: stack
|
id: stack
|
||||||
height: parent.height
|
height: parent.height
|
||||||
|
@ -61,8 +69,7 @@ ModalPopup {
|
||||||
}
|
}
|
||||||
TransactionFormGroup {
|
TransactionFormGroup {
|
||||||
id: group1
|
id: group1
|
||||||
//% "Connect username with your pubkey"
|
headerText: root.title
|
||||||
headerText: qsTrId("connect-username-with-your-pubkey")
|
|
||||||
//% "Continue"
|
//% "Continue"
|
||||||
footerText: qsTrId("continue")
|
footerText: qsTrId("continue")
|
||||||
|
|
||||||
|
@ -104,11 +111,9 @@ ModalPopup {
|
||||||
getFiatValue: walletModel.balanceView.getFiatValue
|
getFiatValue: walletModel.balanceView.getFiatValue
|
||||||
defaultCurrency: walletModel.balanceView.defaultCurrency
|
defaultCurrency: walletModel.balanceView.defaultCurrency
|
||||||
property var estimateGas: Backpressure.debounce(gasSelector, 600, function() {
|
property var estimateGas: Backpressure.debounce(gasSelector, 600, function() {
|
||||||
if (!(root.ensUsername !== "" && selectFromAccount.selectedAccount)) {
|
let estimatedGas = root.estimateGasFunction(selectFromAccount.selectedAccount);
|
||||||
selectedGasLimit = 80000;
|
gasSelector.selectedGasLimit = estimatedGas
|
||||||
return;
|
return estimatedGas;
|
||||||
}
|
|
||||||
selectedGasLimit = profileModel.ens.setPubKeyGasEstimate(root.ensUsername, selectFromAccount.selectedAccount.address)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
GasValidator {
|
GasValidator {
|
||||||
|
@ -123,8 +128,7 @@ ModalPopup {
|
||||||
}
|
}
|
||||||
TransactionFormGroup {
|
TransactionFormGroup {
|
||||||
id: group3
|
id: group3
|
||||||
//% "Connect username with your pubkey"
|
headerText: root.title
|
||||||
headerText: qsTrId("connect-username-with-your-pubkey")
|
|
||||||
//% "Sign with password"
|
//% "Sign with password"
|
||||||
footerText: qsTrId("sign-with-password")
|
footerText: qsTrId("sign-with-password")
|
||||||
|
|
||||||
|
@ -148,8 +152,7 @@ ModalPopup {
|
||||||
}
|
}
|
||||||
TransactionFormGroup {
|
TransactionFormGroup {
|
||||||
id: group4
|
id: group4
|
||||||
//% "Connect username with your pubkey"
|
headerText: root.title
|
||||||
headerText: qsTrId("connect-username-with-your-pubkey")
|
|
||||||
//% "Sign with password"
|
//% "Sign with password"
|
||||||
footerText: qsTrId("sign-with-password")
|
footerText: qsTrId("sign-with-password")
|
||||||
|
|
||||||
|
@ -165,6 +168,23 @@ ModalPopup {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: btnNext.height
|
height: btnNext.height
|
||||||
|
|
||||||
|
StatusRoundButton {
|
||||||
|
id: btnBack
|
||||||
|
anchors.left: parent.left
|
||||||
|
icon.name: "arrow-right"
|
||||||
|
icon.width: 20
|
||||||
|
icon.height: 16
|
||||||
|
rotation: 180
|
||||||
|
visible: stack.currentGroup.showBackBtn
|
||||||
|
enabled: stack.currentGroup.isValid || stack.isLastGroup
|
||||||
|
onClicked: {
|
||||||
|
if (typeof stack.currentGroup.onBackClicked === "function") {
|
||||||
|
return stack.currentGroup.onBackClicked()
|
||||||
|
}
|
||||||
|
stack.back()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
StatusButton {
|
StatusButton {
|
||||||
id: btnNext
|
id: btnNext
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
|
@ -115,7 +115,9 @@ ModalPopup {
|
||||||
defaultCurrency: walletModel.balanceView.defaultCurrency
|
defaultCurrency: walletModel.balanceView.defaultCurrency
|
||||||
width: stack.width
|
width: stack.width
|
||||||
property var estimateGas: Backpressure.debounce(gasSelector, 600, function() {
|
property var estimateGas: Backpressure.debounce(gasSelector, 600, function() {
|
||||||
return root.estimateGasFunction(selectFromAccount.selectedAccount, uuid);
|
let estimatedGas = root.estimateGasFunction(selectFromAccount.selectedAccount, uuid);
|
||||||
|
gasSelector.selectedGasLimit = estimatedGas
|
||||||
|
return estimatedGas;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
GasValidator {
|
GasValidator {
|
||||||
|
|
Loading…
Reference in New Issue