fix: rebase gone wrong

This commit is contained in:
Richard Ramos 2020-09-11 13:23:57 -04:00 committed by Iuri Matias
parent 2f1416e042
commit f2a56c70e1
21 changed files with 214 additions and 98 deletions

View File

@ -5,7 +5,7 @@ import ../../status/messages as messages_model
import ../../status/signals/types
import ../../status/libstatus/types as status_types
import ../../status/libstatus/settings as status_settings
import ../../status/[chat, contacts, status, wallet]
import ../../status/[chat, contacts, status, wallet, stickers]
import view, views/channels_list, views/message_list
logScope:

View File

@ -75,9 +75,13 @@ proc handleChatEvents(self: ChatController) =
self.status.events.on("chat:connected") do(e: Args):
self.view.setConnected(true)
self.status.events.on(PendingTransactionType.BuyingStickerPack.event) do(e: Args):
var data = TransactionMinedArgs(e).data
self.view.installStickerPack(data.parseInt)
self.status.events.on(PendingTransactionType.BuyStickerPack.confirmed) do(e: Args):
var tx = TransactionMinedArgs(e)
if tx.success:
self.view.installStickerPack(tx.data.parseInt)
else:
discard
# TODO: self.view.toastMessage(message = tx.revertReason, error = true) # for when the toast messages in the design are implemented
proc handleMailserverEvents(self: ChatController) =
self.status.events.on("mailserverTopics") do(e: Args):

View File

@ -118,7 +118,6 @@ QtObject:
result = $(%* { "result": %response })
# TODO:
# check if response["error"] is not null and handle the error
self.status.wallet.trackPendingTransaction(address, response, PendingTransactionType.BuyingStickerPack, $packId)
except RpcException as e:
result = $(%* { "error": %* { "message": %e.msg }})

View File

@ -10,6 +10,7 @@ import ../../status/[status, contacts]
import ../../status/chat as status_chat
import ../../status/devices
import ../../status/chat/chat
import ../../status/wallet
import view
import views/ens_manager
import chronicles
@ -78,3 +79,19 @@ proc init*(self: ProfileController, account: Account) =
self.view.updateContactList(msgData.contacts)
if msgData.installations.len > 0:
self.view.addDevices(msgData.installations)
self.status.events.on(PendingTransactionType.RegisterENS.confirmed) do(e: Args):
let tx = TransactionMinedArgs(e)
if tx.success:
self.view.ens.confirm(TransactionMinedArgs(e).data)
else:
discard
# TODO: show toast message indicating transaction reverted
self.status.events.on(PendingTransactionType.SetPubKey.confirmed) do(e: Args):
let tx = TransactionMinedArgs(e)
if tx.success:
self.view.ens.confirm(TransactionMinedArgs(e).data)
else:
discard
# TODO: show toast message indicating transaction reverted

View File

@ -4,7 +4,7 @@ import json
import json_serialization
import sequtils
import strutils
from ../../../status/libstatus/types import Setting
from ../../../status/libstatus/types import Setting, PendingTransactionType
import ../../../status/threads
import ../../../status/ens as status_ens
import ../../../status/libstatus/wallet as status_wallet
@ -13,14 +13,20 @@ import ../../../status/libstatus/utils as libstatus_utils
import ../../../status/libstatus/tokens as tokens
import ../../../status/status
from eth/common/utils import parseAddress
import ../../../status/wallet
import sets
import stew/byteutils
import eth/common/eth_types, stew/byteutils
type
EnsRoles {.pure.} = enum
UserName = UserRole + 1
IsPending = UserRole + 2
QtObject:
type EnsManager* = ref object of QAbstractListModel
usernames*: seq[string]
pendingUsernames*: HashSet[string]
status: Status
proc setup(self: EnsManager) = self.QAbstractListModel.setup
@ -33,10 +39,19 @@ QtObject:
new(result, delete)
result.usernames = @[]
result.status = status
result.pendingUsernames = initHashSet[string]()
result.setup
proc init*(self: EnsManager) =
self.usernames = status_settings.getSetting[seq[string]](Setting.Usernames, @[])
# Get pending ens names
let pendingTransactions = status_wallet.getPendingTransactions().parseJson["result"]
for trx in pendingTransactions.getElems():
if trx["type"].getStr == $PendingTransactionType.RegisterENS:
self.usernames.add trx["data"].getStr
self.pendingUsernames.incl trx["data"].getStr
proc ensWasResolved*(self: EnsManager, ensResult: string) {.signal.}
@ -80,26 +95,27 @@ QtObject:
proc preferredUsernameChanged(self: EnsManager) {.signal.}
proc isPending*(self: EnsManager, ensUsername: string): bool {.slot.} =
self.pendingUsernames.contains(ensUsername)
proc pendingLen*(self: EnsManager): int {.slot.} =
self.pendingUsernames.len
proc setPreferredUsername(self: EnsManager, newENS: string) {.slot.} =
discard status_settings.saveSetting(Setting.PreferredUsername, newENS)
self.preferredUsernameChanged()
if not self.isPending(newENS):
discard status_settings.saveSetting(Setting.PreferredUsername, newENS)
self.preferredUsernameChanged()
QtProperty[string] preferredUsername:
read = getPreferredUsername
notify = preferredUsernameChanged
write = setPreferredUsername
proc connect(self: EnsManager, username: string, isStatus: bool) {.slot.} =
var ensUsername = username
if isStatus:
ensUsername = ensUsername & status_ens.domain
proc connect(self: EnsManager, ensUsername: string) =
var usernames = status_settings.getSetting[seq[string]](Setting.Usernames, @[])
usernames.add ensUsername
discard status_settings.saveSetting(Setting.Usernames, %*usernames)
if usernames.len == 1:
self.setPreferredUsername(ensUsername)
self.add ensUsername
proc loading(self: EnsManager, isLoading: bool) {.signal.}
proc details(self: EnsManager, username: string) {.slot.} =
@ -128,14 +144,28 @@ QtObject:
return
if index.row < 0 or index.row >= self.usernames.len:
return
let username = self.usernames[index.row]
result = newQVariant(username)
let username = self.usernames[index.row]
case role.EnsRoles:
of EnsRoles.UserName: result = newQVariant(username)
of EnsRoles.IsPending: result = newQVariant(self.pendingUsernames.contains(username))
method roleNames(self: EnsManager): Table[int, string] =
{
EnsRoles.UserName.int:"username"
EnsRoles.UserName.int:"username",
EnsRoles.IsPending.int: "isPending"
}.toTable
proc usernameConfirmed(self: EnsManager, username: string) {.signal.}
proc confirm*(self: EnsManager, ensUsername: string) =
self.connect(ensUsername)
self.pendingUsernames.excl ensUsername
let msgIdx = self.usernames.find(ensUsername)
let topLeft = self.createIndex(msgIdx, 0, nil)
let bottomRight = self.createIndex(msgIdx, 0, nil)
self.dataChanged(topLeft, bottomRight, @[EnsRoles.IsPending.int])
self.usernameConfirmed(ensUsername)
proc getPrice(self: EnsManager): string {.slot.} =
result = libstatus_utils.wei2Eth(getPrice())
@ -145,15 +175,37 @@ QtObject:
proc getENSRegistry(self: EnsManager): string {.slot.} =
result = registry
proc formatUsername(username: string, isStatus: bool): string =
result = username
if isStatus:
result = result & status_ens.domain
proc connectOwnedUsername(self: EnsManager, username: string, isStatus: bool) {.slot.} =
var ensUsername = formatUsername(username, isStatus)
self.usernames.add ensUsername
self.add ensUsername
self.connect(ensUsername)
proc registerENS(self: EnsManager, username: string, password: string) {.slot.} =
let pubKey = status_settings.getSetting[string](Setting.PublicKey, "0x0")
let address = parseAddress(status_wallet.getWalletAccounts()[0].address)
discard registerUsername(username, address, pubKey, password)
self.connect(username, true)
let address = status_wallet.getWalletAccounts()[0].address
let walletAddress = parseAddress(address)
let trxHash = registerUsername(username, walletAddress, pubKey, password)
# TODO: handle transaction failure
var ensUsername = formatUsername(username, true)
self.pendingUsernames.incl(ensUsername)
self.add ensUsername
proc setPubKey(self: EnsManager, username: string, password: string) {.slot.} =
let pubKey = status_settings.getSetting[string](Setting.PublicKey, "0x0")
let address = parseAddress(status_wallet.getWalletAccounts()[0].address)
discard setPubKey(username, address, pubKey, password)
self.connect(username, username.endsWith(domain))
let address = status_wallet.getWalletAccounts()[0].address
let walletAddress = parseAddress(address)
let trxHash = setPubKey(username, walletAddress, pubKey, password)
# TODO: handle transaction failure
self.pendingUsernames.incl(username)
self.add username

View File

@ -25,7 +25,6 @@ proc delete*(self: WalletController) =
delete self.view
proc init*(self: WalletController) =
status_wallet.startWallet()
self.status.wallet.initAccounts()
var accounts = self.status.wallet.accounts
for account in accounts:
@ -60,3 +59,9 @@ proc init*(self: WalletController) =
# TODO: handle these data.eventType: history, reorg
# see status-react/src/status_im/ethereum/subscriptions.cljs
proc checkPendingTransactions*(self: WalletController) =
self.status.wallet.checkPendingTransactions() # TODO: consider doing this in a spawnAndSend
proc start*(self: WalletController) =
status_wallet.startWallet()

View File

@ -85,6 +85,9 @@ proc mainProc() =
wallet.init()
chat.init()
wallet.checkPendingTransactions()
wallet.start()
engine.setRootContextProperty("loginModel", login.variant)
engine.setRootContextProperty("onboardingModel", onboarding.variant)

View File

@ -8,10 +8,11 @@ import strformat
import libstatus/core
import libstatus/types
import libstatus/utils
import libstatus/wallet
import stew/byteutils
import unicode
import algorithm
import eth/common/eth_types, stew/byteutils
import eth/common/eth_types, stew/byteutils, stint
import libstatus/eth/contracts
const domain* = ".stateofus.eth"
@ -168,6 +169,8 @@ proc registerUsername*(username:string, address: EthAddress, pubKey: string, pas
if not response.error.isNil:
raise newException(RpcException, "Error registering ens-username: " & response.error.message)
trackPendingTransaction(response.result, $address, $sntContract.address, PendingTransactionType.RegisterENS, username & domain)
result = response.result
proc setPubKey*(username:string, address: EthAddress, pubKey: string, password: string): string =
@ -184,9 +187,11 @@ proc setPubKey*(username:string, address: EthAddress, pubKey: string, password:
setPubkey = SetPubkey(label: label, x: x, y: y)
setPubkeyAbiEncoded = resolverContract.methods["setPubkey"].encodeAbi(setPubkey)
let resolverAddress = resolver(hash)
let payload = %* {
"from": $address,
"to": resolver(hash),
"to": resolverAddress,
# "gas": 200000, # TODO: obtain gas price?
"data": setPubkeyAbiEncoded
}
@ -195,6 +200,9 @@ proc setPubKey*(username:string, address: EthAddress, pubKey: string, password:
let response = Json.decode(responseStr, RpcResponse)
if not response.error.isNil:
raise newException(RpcException, "Error setting the pubkey: " & response.error.message)
trackPendingTransaction(response.result, $address, resolverAddress, PendingTransactionType.SetPubKey, username)
result = response.result
proc statusRegistrarAddress*():string =

View File

@ -17,7 +17,7 @@ proc callPrivateRPC*(methodName: string, payload = %* []): string =
"method": methodName,
"params": %payload
}
debug "calling json", request = $inputJSON
debug "callPrivateRPC", rpc_method=methodName
let response = nim_status.callPrivateRPC($inputJSON)
result = $response
if parseJSON(result).hasKey("error"):

View File

@ -98,7 +98,7 @@ proc allContracts(): seq[Contract] = @[
("getPrice", Method(signature: "getPrice()"))
].toTable
),
Contract(name: "ens-usernames", network: Network.Testnet, address: parseAddress("0x76fbf2815ead80006d07a64c1fd5dc9964ab3c93"),
Contract(name: "ens-usernames", network: Network.Testnet, address: parseAddress("0x11d9F481effd20D76cEE832559bd9Aca25405841"),
methods: [
("register", Method(signature: "register(bytes32,address,bytes32,bytes32)")),
("getPrice", Method(signature: "getPrice()"))

View File

@ -235,4 +235,11 @@ proc `%`*(x: EthSend): JsonNode =
result["value"] = %("0x" & x.value.unsafeGet.toHex)
result["data"] = %x.data
if x.nonce.isSome:
result["nonce"] = %x.nonce.unsafeGet
result["nonce"] = %x.nonce.unsafeGet
type PendingTransactionType* {.pure.} = enum
RegisterENS = "RegisterENS",
SetPubKey = "SetPubKey",
ReleaseENS = "ReleaseENS",
BuyStickerPack = "BuyStickerPack"
WalletTransfer = "WalletTransfer"

View File

@ -93,3 +93,19 @@ proc hex2Token*(input: string, decimals: int): string =
result = $i
if(r > 0): result = fmt"{result}.{d}"
proc trackPendingTransaction*(transactionHash: string, fromAddress: string, toAddress: string, trxType: PendingTransactionType, data: string) =
let blockNumber = parseInt($fromHex(Stuint[256], getBlockByNumber("latest").parseJson()["result"]["number"].getStr))
let payload = %* [{"transactionHash": transactionHash, "blockNumber": blockNumber, "from_address": fromAddress, "to_address": toAddress, "type": $trxType, "data": data}]
discard callPrivateRPC("wallet_storePendingTransaction", payload)
proc getPendingTransactions*(): string =
let payload = %* []
result = callPrivateRPC("wallet_getPendingTransactions", payload)
proc getPendingOutboundTransactionsByAddress*(address: string): string =
let payload = %* [address]
result = callPrivateRPC("wallet_getPendingOutboundTransactionsByAddress", payload)
proc deletePendingTransaction*(transactionHash: string) =
let payload = %* [transactionHash]
discard callPrivateRPC("wallet_deletePendingTransaction", payload)

View File

@ -4,19 +4,9 @@ import libstatus/accounts as libstatus_accounts
import libstatus/core as libstatus_core
import libstatus/settings as libstatus_settings
import libstatus/types as libstatus_types
import chat, accounts, wallet, node, network, mailservers, messages, contacts, profile, stickers
import chat as chat
import accounts as accounts
import wallet as wallet
import node as node
import mailservers as mailservers
import messages as messages
import contacts as contacts
import profile
import network as network
import stickers
export stickers
export chat, accounts, node, mailservers, messages, contacts, profile, network
type Status* = ref object
events*: EventEmitter

View File

@ -7,9 +7,11 @@ from eth/common/utils import parseAddress
import # local deps
libstatus/types, libstatus/eth/contracts as status_contracts,
libstatus/stickers as status_stickers, transactions
libstatus/stickers as status_stickers, transactions,
libstatus/wallet
from libstatus/utils as libstatus_utils import eth2Wei, gwei2Wei, toUInt64
logScope:
topics = "stickers-model"
@ -82,6 +84,7 @@ proc buyPack*(self: StickersModel, packId: int, address, price, gas, gasPrice, p
)
try:
result = sntContract.methods["approveAndCall"].send(tx, approveAndCall, password)
trackPendingTransaction(result, address, $sntContract.address, PendingTransactionType.BuyStickerPack, $packId)
except RpcException as e:
raise

View File

@ -9,7 +9,8 @@ import libstatus/settings as status_settings
import libstatus/wallet as status_wallet
import libstatus/accounts/constants as constants
import libstatus/eth/[eth, contracts]
from libstatus/types import GeneratedAccount, DerivedAccount, Transaction, Setting, GasPricePrediction, EthSend, Quantity, `%`, StatusGoException, Network, RpcResponse, RpcException, `$`
from libstatus/core import getBlockByNumber
from libstatus/types import PendingTransactionType, GeneratedAccount, DerivedAccount, Transaction, Setting, GasPricePrediction, EthSend, Quantity, `%`, StatusGoException, Network, RpcResponse, RpcException
from libstatus/utils as libstatus_utils import eth2Wei, gwei2Wei, first, toUInt64
import wallet/[balance_manager, account, collectibles]
import transactions
@ -19,23 +20,13 @@ export Transaction
logScope:
topics = "wallet-model"
type PendingTransactionType* {.pure.} = enum
RegisterENS = "RegisterENS",
ReleaseENS = "ReleaseENS",
BuyingStickerPack = "BuyingStickerPack"
proc event*(self:PendingTransactionType):string =
proc confirmed*(self:PendingTransactionType):string =
result = "transaction:" & $self
type PendingTransaction* = object
transactionHash*: string
blockNumber*: int
trxType*: PendingTransactionType
data*: string
mined: bool
type TransactionMinedArgs* = ref object of Args
data*: string
success*: bool
revertReason*: string # TODO: possible to get revert reason in here?
type WalletModel* = ref object
events*: EventEmitter
@ -43,7 +34,6 @@ type WalletModel* = ref object
defaultCurrency*: string
tokens*: JsonNode
totalBalance*: float
pendingTransactions: Table[string, seq[PendingTransaction]]
proc getDefaultCurrency*(self: WalletModel): string
proc calculateTotalFiatBalance*(self: WalletModel)
@ -52,7 +42,6 @@ proc newWalletModel*(events: EventEmitter): WalletModel =
result = WalletModel()
result.accounts = @[]
result.tokens = %* []
result.pendingTransactions = initTable[string, seq[PendingTransaction]]()
result.events = events
result.defaultCurrency = ""
result.totalBalance = 0.0
@ -89,36 +78,28 @@ proc estimateGas*(self: WalletModel, source, to, value: string): int =
except RpcException as e:
raise
proc trackPendingTransaction*(self: WalletModel, address: string, trxHash: string, trxType: PendingTransactionType, data: string) =
let latestBlock = getBlockByNumber("latest").parseJson()["result"].getInt
if not self.pendingTransactions.hasKey(address):
self.pendingTransactions[address] = @[]
self.pendingTransactions[address].add PendingTransaction(
transactionHash: trxHash,
trxType: trxType,
blockNumber: latestBlock,
data: data,
mined: false
)
proc getTransactionReceipt*(self: WalletModel, transactionHash: string): JsonNode =
result = status_wallet.getTransactionReceipt(transactionHash).parseJSON()["result"]
proc checkPendingTransactions*(self: WalletModel, address: string, blockNumber: int) =
if not self.pendingTransactions.hasKey(address): return
for trx in self.pendingTransactions[address].mitems:
if trx.mined: continue
let transactionReceipt = self.getTransactionReceipt(trx.transactionHash)
proc confirmTransactionStatus(self: WalletModel, pendingTransactions: JsonNode, blockNumber: int) =
for trx in pendingTransactions.getElems():
let transactionReceipt = self.getTransactionReceipt(trx["transactionHash"].getStr)
if transactionReceipt.kind != JNull:
trx.mined = true
if transactionReceipt{"status"}.getStr == "0x1": # mined successfully
self.events.emit(trx.trxType.event, TransactionMinedArgs(data: trx.data))
else:
discard # TODO: what should we do if the transaction reverted?
status_wallet.deletePendingTransaction(trx["transactionHash"].getStr)
let ev = TransactionMinedArgs(
data: trx["data"].getStr,
success: transactionReceipt{"status"}.getStr == "0x1",
revertReason: ""
)
self.events.emit(parseEnum[PendingTransactionType](trx["type"].getStr).confirmed, ev)
proc checkPendingTransactions*(self: WalletModel) =
let latestBlock = parseInt($fromHex(Stuint[256], getBlockByNumber("latest").parseJson()["result"]["number"].getStr))
self.confirmTransactionStatus(status_wallet.getPendingTransactions().parseJson["result"], latestBlock)
proc checkPendingTransactions*(self: WalletModel, address: string, blockNumber: int) =
self.confirmTransactionStatus(status_wallet.getPendingOutboundTransactionsByAddress(address).parseJson["result"], blockNumber)
proc estimateTokenGas*(self: WalletModel, source, to, assetAddress, value: string): int =
var
transfer: Transfer

View File

@ -21,8 +21,11 @@ ModalPopup {
StyledText {
id: lbl1
//% "Your messages are displayed to others with this username:"
text: qsTrId("your-messages-are-displayed-to-others-with-this-username-")
text: profileModel.ens.preferredUsername ?
//% "Your messages are displayed to others with this username:"
qsTrId("your-messages-are-displayed-to-others-with-this-username-")
:
qsTr("Once you select a username, you wont be able to disable it afterwards. You will only be able choose a different username to display.")
font.pixelSize: 15
}

View File

@ -22,12 +22,16 @@ Item {
property string identicon: profileModel.profile.identicon
property int timestamp: 1577872140
function shouldDisplayExampleMessage(){
return profileModel.ens.rowCount() > 0 && profileModel.ens.pendingLen() != profileModel.ens.rowCount() && profileModel.ens.preferredUsername !== ""
}
Component {
id: statusENS
Item {
Text {
id: usernameTxt
text: username.substr(0, username.indexOf("."))
text: username.substr(0, username.indexOf(".")) + " " + (isPending ? qsTr("(pending)") : "")
color: Style.current.textColor
}
@ -46,7 +50,7 @@ Item {
Item {
Text {
id: usernameTxt
text: username
text: username + " " + (isPending ? qsTr("(pending)") : "")
font.pixelSize: 16
color: Style.current.textColor
anchors.top: parent.top
@ -90,6 +94,7 @@ Item {
Loader {
sourceComponent: model.username.endsWith(".stateofus.eth") ? statusENS : normalENS
property string username: model.username
property bool isPending: model.isPending
active: true
anchors.left: circle.right
anchors.leftMargin: Style.current.smallPadding
@ -192,7 +197,7 @@ Item {
StyledText {
id: chatSettingsLabel
visible: profileModel.ens.rowCount() > 1
visible: profileModel.ens.rowCount() > 0 && profileModel.ens.pendingLen() != profileModel.ens.rowCount()
//% "Chat Settings"
text: qsTrId("chat-settings")
anchors.left: parent.left
@ -222,7 +227,7 @@ Item {
StyledText {
id: usernameLabel2
visible: chatSettingsLabel.visible
text: profileModel.ens.preferredUsername
text: profileModel.ens.preferredUsername || qsTr("None selected")
anchors.left: usernameLabel.right
anchors.leftMargin: Style.current.padding
font.pixelSize: 14
@ -236,7 +241,9 @@ Item {
}
Item {
anchors.top: profileModel.ens.rowCount() == 1 ? separator.bottom : preferredUsername.bottom
id: messagesShownAs
visible: shouldDisplayExampleMessage()
anchors.top: !visible ? separator.bottom : preferredUsername.bottom
anchors.topMargin: Style.current.padding * 2
UserImage {
@ -290,7 +297,28 @@ Item {
anchors.right: chatBox.right
anchors.rightMargin: Style.current.padding
}
StyledText {
anchors.top: chatTime.bottom
anchors.left: chatImage.left
anchors.topMargin: Style.current.padding
text: qsTr("Youre displaying your ENS username in chats")
font.pixelSize: 14
color: Style.current.secondaryText
}
}
Connections {
target: profileModel.ens
onPreferredUsernameChanged: {
messagesShownAs.visible = shouldDisplayExampleMessage()
}
onUsernameConfirmed: {
messagesShownAs.visible = shouldDisplayExampleMessage()
chatSettingsLabel.visible = true
}
}
}

View File

@ -202,7 +202,7 @@ Item {
if(!valid) return;
if(ensStatus === "connected"){
profileModel.ens.connect(ensUsername.text, isStatus);
profileModel.ens.connectOwnedUsername(ensUsername.text, isStatus);
continueClicked(ensStatus, ensUsername.text)
return;
}

View File

@ -282,7 +282,7 @@ Item {
anchors.bottom: parent.bottom
anchors.bottomMargin: Style.current.padding
anchors.horizontalCenter: parent.horizontalCenter
disabled: profileModel.network !== "mainnet_rpc"
disabled: profileModel.network !== "mainnet_rpc" // Comment this to use on testnet
//% "Start"
label: !disabled ? qsTrId("start") : qsTr("Only available on Mainnet")
onClicked: startBtnClicked()

View File

@ -25,8 +25,8 @@ Item {
signal goToWelcome();
signal goToList();
function goToStart(){
if(profileModel.ens.rowCount() > 0){
function goToStart(){ /* Comment this to use on testnet */
if(profileModel.ens.rowCount() > 0 && profileModel.network === "mainnet_rpc"){
goToList();
} else {
goToWelcome();

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit 8f83c5f462de854fa9b616273ccfdd4b0bda4748
Subproject commit abf9c789c3b688611a053e1ddb49d28d21d6d162