diff --git a/src/app/wallet/view.nim b/src/app/wallet/view.nim index fc693019a9..fa7fa9512f 100644 --- a/src/app/wallet/view.nim +++ b/src/app/wallet/view.nim @@ -5,6 +5,7 @@ import strutils import views/asset_list import views/account_list import views/account_item +import views/transaction_list import ../../status/wallet import ../../status/status import chronicles @@ -15,6 +16,7 @@ QtObject: accounts*: AccountList currentAssetList*: AssetList currentAccount: AccountItemView + currentTransactions: TransactionList status: Status totalFiatBalance: string @@ -30,6 +32,7 @@ QtObject: result.accounts = newAccountList() result.currentAccount = newAccountItemView() result.currentAssetList = newAssetList() + result.currentTransactions = newTransactionList() result.totalFiatBalance = "" result.setup @@ -68,6 +71,20 @@ QtObject: write = setCurrentAssetList notify = currentAssetListChanged + proc currentTransactionsChanged*(self: WalletView) {.signal.} + + proc getCurrentTransactions*(self: WalletView): QVariant {.slot.} = + return newQVariant(self.currentTransactions) + + proc setCurrentTransactions*(self: WalletView, transactionList: seq[Transaction]) = + self.currentTransactions.setNewData(transactionList) + self.currentTransactionsChanged() + + QtProperty[QVariant] transactions: + read = getCurrentTransactions + write = setCurrentTransactions + notify = currentTransactionsChanged + proc totalFiatBalanceChanged*(self: WalletView) {.signal.} proc getTotalFiatBalance(self: WalletView): string {.slot.} = @@ -163,3 +180,6 @@ QtObject: proc addCustomToken*(self: WalletView, address: string, name: string, symbol: string, decimals: string) {.slot.} = self.status.wallet.toggleAsset(symbol, true, address, name, parseInt(decimals), "") + + proc loadTransactionsForAccount*(self: WalletView, address: string) {.slot.} = + self.setCurrentTransactions(self.status.wallet.getTransfersByAddress(address)) diff --git a/src/app/wallet/views/transaction_list.nim b/src/app/wallet/views/transaction_list.nim new file mode 100644 index 0000000000..780727cd45 --- /dev/null +++ b/src/app/wallet/views/transaction_list.nim @@ -0,0 +1,89 @@ +import NimQml +import tables +import ../../../status/wallet + +type + TransactionRoles {.pure.} = enum + Type = UserRole + 1, + Address = UserRole + 2, + BlockNumber = UserRole + 3, + BlockHash = UserRole + 4, + Timestamp = UserRole + 5, + GasPrice = UserRole + 6, + GasLimit = UserRole + 7, + GasUsed = UserRole + 8, + Nonce = UserRole + 9, + TxStatus = UserRole + 10, + Value = UserRole + 11, + From = UserRole + 12, + To = UserRole + 13 + +QtObject: + type TransactionList* = ref object of QAbstractListModel + transactions*: seq[Transaction] + + proc setup(self: TransactionList) = self.QAbstractListModel.setup + + proc delete(self: TransactionList) = + self.QAbstractListModel.delete + self.transactions = @[] + + proc newTransactionList*(): TransactionList = + new(result, delete) + result.transactions = @[] + result.setup + + method rowCount(self: TransactionList, index: QModelIndex = nil): int = + return self.transactions.len + + method data(self: TransactionList, index: QModelIndex, role: int): QVariant = + if not index.isValid: + return + if index.row < 0 or index.row >= self.transactions.len: + return + let transaction = self.transactions[index.row] + let transactionRole = role.TransactionRoles + case transactionRole: + of TransactionRoles.Type: result = newQVariant(transaction.typeValue) + of TransactionRoles.Address: result = newQVariant(transaction.address) + of TransactionRoles.BlockNumber: result = newQVariant(transaction.blockNumber) + of TransactionRoles.BlockHash: result = newQVariant(transaction.blockHash) + of TransactionRoles.Timestamp: result = newQVariant(transaction.timestamp) + of TransactionRoles.GasPrice: result = newQVariant(transaction.gasPrice) + of TransactionRoles.GasLimit: result = newQVariant(transaction.gasLimit) + of TransactionRoles.GasUsed: result = newQVariant(transaction.gasUsed) + of TransactionRoles.Nonce: result = newQVariant(transaction.nonce) + of TransactionRoles.TxStatus: result = newQVariant(transaction.txStatus) + of TransactionRoles.Value: result = newQVariant(transaction.value) + of TransactionRoles.From: result = newQVariant(transaction.fromAddress) + of TransactionRoles.To: result = newQVariant(transaction.to) + + method roleNames(self: TransactionList): Table[int, string] = + { TransactionRoles.Type.int:"typeValue", + TransactionRoles.Address.int:"address", + TransactionRoles.BlockNumber.int:"blockNumber", + TransactionRoles.BlockHash.int:"blockHash", + TransactionRoles.Timestamp.int:"timestamp", + TransactionRoles.GasPrice.int:"gasPrice", + TransactionRoles.GasLimit.int:"gasLimit", + TransactionRoles.GasUsed.int:"gasUsed", + TransactionRoles.Nonce.int:"nonce", + TransactionRoles.TxStatus.int:"txStatus", + TransactionRoles.Value.int:"value", + TransactionRoles.From.int:"fromAddress", + TransactionRoles.To.int:"to" }.toTable + + proc addTransactionToList*(self: TransactionList, transaction: Transaction) = + self.beginInsertRows(newQModelIndex(), self.transactions.len, self.transactions.len) + self.transactions.add(transaction) + self.endInsertRows() + + proc setNewData*(self: TransactionList, transactionList: seq[Transaction]) = + self.beginResetModel() + self.transactions = transactionList + self.endResetModel() + + proc forceUpdate*(self: TransactionList) = + self.beginResetModel() + self.endResetModel() + diff --git a/src/status/libstatus/core.nim b/src/status/libstatus/core.nim index 46a4e6e28f..f05d1a4d48 100644 --- a/src/status/libstatus/core.nim +++ b/src/status/libstatus/core.nim @@ -35,11 +35,20 @@ proc sendTransaction*(inputJSON: string, password: string): string = proc startMessenger*() = discard callPrivateRPC("startMessenger".prefix) -proc addPeer*(peer: string) = +proc addPeer*(peer: string) = discard callPrivateRPC("admin_addPeer", %* [peer]) -proc removePeer*(peer: string) = +proc removePeer*(peer: string) = discard callPrivateRPC("admin_removePeer", %* [peer]) -proc markTrustedPeer*(peer: string) = +proc markTrustedPeer*(peer: string) = discard callPrivateRPC("markTrustedPeer".prefix(false), %* [peer]) + +proc getContactByID*(id: string): string = + result = callPrivateRPC("getContactByID".prefix, %* [id]) + +proc getBlockByNumber*(blockNumber: string): string = + result = callPrivateRPC("eth_getBlockByNumber", %* [blockNumber, false]) + +proc getTransfersByAddress*(address: string, toBlock: string, limit: string): string = + result = callPrivateRPC("wallet_getTransfersByAddress", %* [address, toBlock, limit]) diff --git a/src/status/libstatus/types.nim b/src/status/libstatus/types.nim index bbf92aa960..1ae252f99d 100644 --- a/src/status/libstatus/types.nim +++ b/src/status/libstatus/types.nim @@ -75,3 +75,20 @@ type AccountArgs* = ref object of Args type StatusGoException* = object of Exception + +type + Transaction* = ref object + typeValue*: string + address*: string + blockNumber*: string + blockHash*: string + timestamp*: string + gasPrice*: string + gasLimit*: string + gasUsed*: string + nonce*: string + txStatus*: string + value*: string + fromAddress*: string + to*: string + diff --git a/src/status/libstatus/wallet.nim b/src/status/libstatus/wallet.nim index 5bd9faa9b9..3974798959 100644 --- a/src/status/libstatus/wallet.nim +++ b/src/status/libstatus/wallet.nim @@ -6,6 +6,7 @@ import strformat import stint import strutils, sequtils import chronicles +import types import ../wallet/account proc getWalletAccounts*(): seq[WalletAccount] = @@ -32,6 +33,36 @@ proc getWalletAccounts*(): seq[WalletAccount] = let msg = getCurrentExceptionMsg() error "Failed getting wallet accounts", msg +proc getTransfersByAddress*(address: string): seq[Transaction] = + try: + let response = status.getBlockByNumber("latest") + let latestBlock = parseJson(response)["result"] + + let transactionsResponse = status.getTransfersByAddress(address, latestBlock["number"].getStr, "0x14") + let transactions = parseJson(transactionsResponse)["result"] + var accountTransactions: seq[Transaction] = @[] + + for transaction in transactions: + accountTransactions.add(Transaction( + typeValue: transaction["type"].getStr, + address: transaction["address"].getStr, + blockNumber: transaction["blockNumber"].getStr, + timestamp: transaction["timestamp"].getStr, + gasPrice: transaction["gasPrice"].getStr, + gasLimit: transaction["gasLimit"].getStr, + gasUsed: transaction["gasUsed"].getStr, + nonce: transaction["nonce"].getStr, + txStatus: transaction["txStatus"].getStr, + value: transaction["value"].getStr, + fromAddress: transaction["from"].getStr, + to: transaction["to"].getStr + )) + result = accountTransactions + except: + let msg = getCurrentExceptionMsg() + error "Failed getting wallet account transactions", msg + + proc sendTransaction*(from_address: string, to: string, value: string, password: string): string = var args = %* { "value": fmt"0x{toHex(value)}", diff --git a/src/status/wallet.nim b/src/status/wallet.nim index 052b841d7b..c6e7db9c8b 100644 --- a/src/status/wallet.nim +++ b/src/status/wallet.nim @@ -4,10 +4,11 @@ import libstatus/tokens as status_tokens import libstatus/settings as status_settings import libstatus/wallet as status_wallet import libstatus/accounts/constants as constants -from libstatus/types import GeneratedAccount, DerivedAccount +from libstatus/types import GeneratedAccount, DerivedAccount, Transaction import wallet/balance_manager import wallet/account export account +export Transaction type WalletModel* = ref object events*: EventEmitter @@ -144,3 +145,6 @@ proc toggleAsset*(self: WalletModel, symbol: string, enable: bool, address: stri account.assetList = self.generateAccountConfiguredAssets(account.address) updateBalance(account, self.getDefaultCurrency()) self.events.emit("assetChanged", Args()) + +proc getTransfersByAddress*(self: WalletModel, address: string): seq[Transaction] = + result = status_wallet.getTransfersByAddress(address) diff --git a/ui/app/AppLayouts/Wallet/HistoryTab.qml b/ui/app/AppLayouts/Wallet/HistoryTab.qml index a115f6bfa8..a7ba690c2d 100644 --- a/ui/app/AppLayouts/Wallet/HistoryTab.qml +++ b/ui/app/AppLayouts/Wallet/HistoryTab.qml @@ -1,8 +1,118 @@ import QtQuick 2.3 +import "../../../imports" Item { - Text { - id: name3 - text: "HISTORY" + Component { + id: transactionListItem + + Item { + anchors.right: parent.right + anchors.left: parent.left + height: 64 + + Item { + + Rectangle { + id: assetIcon + color: "gray" + width: 40 + height: 40 + anchors.left: parent.left + anchors.top: parent.top + anchors.topMargin: 12 + radius: 50 + } + + Text { + id: transferIcon + anchors.topMargin: 25 + anchors.top: parent.top + anchors.left: assetIcon.right + anchors.leftMargin: 22 + height: 15 + width: 15 + color: to != walletModel.currentAccount.address ? "#4360DF" : "green" + text: to != walletModel.currentAccount.address ? "↑" : "↓" + } + + Text { + id: transactionValue + anchors.left: transferIcon.right + anchors.leftMargin: Theme.smallPadding + anchors.top: parent.top + anchors.topMargin: Theme.bigPadding + font.pixelSize: 15 + text: value + " TOKEN" + } + } + + Item { + anchors.right: timeInfo.left + anchors.top: parent.top + anchors.topMargin: Theme.bigPadding + width: children[0].width + children[1].width + + Text { + text: to != walletModel.currentAccount.address ? "To " : "From " + anchors.right: addressValue.left + color: Theme.darkGrey + anchors.top: parent.top + font.pixelSize: 15 + font.strikeout: false + } + + Text { + id: addressValue + text: to + width: 100 + elide: Text.ElideMiddle + anchors.right: parent.right + anchors.top: parent.top + font.pixelSize: 15 + } + } + + Item { + id: timeInfo + anchors.right: parent.right + anchors.top: parent.top + anchors.topMargin: Theme.bigPadding + width: children[0].width + children[1].width + children[2].width + + Text { + text: "• " + font.weight: Font.Bold + anchors.right: timeIndicator.left + color: Theme.darkGrey + anchors.top: parent.top + font.pixelSize: 15 + } + + Text { + id: timeIndicator + text: "At " + anchors.right: timeValue.left + color: Theme.darkGrey + anchors.top: parent.top + font.pixelSize: 15 + font.strikeout: false + } + + Text { + id: timeValue + text: timestamp + anchors.right: parent.right + anchors.top: parent.top + font.pixelSize: 15 + } + } + } + } + + ListView { + anchors.topMargin: 20 + anchors.fill: parent + model: walletModel.transactions + delegate: transactionListItem } } diff --git a/ui/app/AppLayouts/Wallet/WalletLayout.qml b/ui/app/AppLayouts/Wallet/WalletLayout.qml index 4b73e67112..e55c3bc8ad 100644 --- a/ui/app/AppLayouts/Wallet/WalletLayout.qml +++ b/ui/app/AppLayouts/Wallet/WalletLayout.qml @@ -81,6 +81,9 @@ SplitView { anchors.left: collectiblesBtn.right anchors.leftMargin: 32 btnText: "History" + onClicked: { + walletModel.loadTransactionsForAccount(walletModel.currentAccount.address) + } } }