feat(wallet): Introduce simple account transaction list
There's still some things that needs to be done (possibly in future commits): [ ] Asset icons need to be determined so they can be displayed along the transaction [ ] Transaction values need to be converted to decimal values [ ] Date-time formatting [ ] Grouping of transactions by days
This commit is contained in:
parent
116b04a9ef
commit
0f7e08075b
|
@ -5,6 +5,7 @@ import strutils
|
||||||
import views/asset_list
|
import views/asset_list
|
||||||
import views/account_list
|
import views/account_list
|
||||||
import views/account_item
|
import views/account_item
|
||||||
|
import views/transaction_list
|
||||||
import ../../status/wallet
|
import ../../status/wallet
|
||||||
import ../../status/status
|
import ../../status/status
|
||||||
import chronicles
|
import chronicles
|
||||||
|
@ -15,6 +16,7 @@ QtObject:
|
||||||
accounts*: AccountList
|
accounts*: AccountList
|
||||||
currentAssetList*: AssetList
|
currentAssetList*: AssetList
|
||||||
currentAccount: AccountItemView
|
currentAccount: AccountItemView
|
||||||
|
currentTransactions: TransactionList
|
||||||
status: Status
|
status: Status
|
||||||
totalFiatBalance: string
|
totalFiatBalance: string
|
||||||
|
|
||||||
|
@ -30,6 +32,7 @@ QtObject:
|
||||||
result.accounts = newAccountList()
|
result.accounts = newAccountList()
|
||||||
result.currentAccount = newAccountItemView()
|
result.currentAccount = newAccountItemView()
|
||||||
result.currentAssetList = newAssetList()
|
result.currentAssetList = newAssetList()
|
||||||
|
result.currentTransactions = newTransactionList()
|
||||||
result.totalFiatBalance = ""
|
result.totalFiatBalance = ""
|
||||||
result.setup
|
result.setup
|
||||||
|
|
||||||
|
@ -68,6 +71,20 @@ QtObject:
|
||||||
write = setCurrentAssetList
|
write = setCurrentAssetList
|
||||||
notify = currentAssetListChanged
|
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 totalFiatBalanceChanged*(self: WalletView) {.signal.}
|
||||||
|
|
||||||
proc getTotalFiatBalance(self: WalletView): string {.slot.} =
|
proc getTotalFiatBalance(self: WalletView): string {.slot.} =
|
||||||
|
@ -163,3 +180,6 @@ QtObject:
|
||||||
|
|
||||||
proc addCustomToken*(self: WalletView, address: string, name: string, symbol: string, decimals: string) {.slot.} =
|
proc addCustomToken*(self: WalletView, address: string, name: string, symbol: string, decimals: string) {.slot.} =
|
||||||
self.status.wallet.toggleAsset(symbol, true, address, name, parseInt(decimals), "")
|
self.status.wallet.toggleAsset(symbol, true, address, name, parseInt(decimals), "")
|
||||||
|
|
||||||
|
proc loadTransactionsForAccount*(self: WalletView, address: string) {.slot.} =
|
||||||
|
self.setCurrentTransactions(self.status.wallet.getTransfersByAddress(address))
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -35,11 +35,20 @@ proc sendTransaction*(inputJSON: string, password: string): string =
|
||||||
proc startMessenger*() =
|
proc startMessenger*() =
|
||||||
discard callPrivateRPC("startMessenger".prefix)
|
discard callPrivateRPC("startMessenger".prefix)
|
||||||
|
|
||||||
proc addPeer*(peer: string) =
|
proc addPeer*(peer: string) =
|
||||||
discard callPrivateRPC("admin_addPeer", %* [peer])
|
discard callPrivateRPC("admin_addPeer", %* [peer])
|
||||||
|
|
||||||
proc removePeer*(peer: string) =
|
proc removePeer*(peer: string) =
|
||||||
discard callPrivateRPC("admin_removePeer", %* [peer])
|
discard callPrivateRPC("admin_removePeer", %* [peer])
|
||||||
|
|
||||||
proc markTrustedPeer*(peer: string) =
|
proc markTrustedPeer*(peer: string) =
|
||||||
discard callPrivateRPC("markTrustedPeer".prefix(false), %* [peer])
|
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])
|
||||||
|
|
|
@ -75,3 +75,20 @@ type AccountArgs* = ref object of Args
|
||||||
|
|
||||||
type
|
type
|
||||||
StatusGoException* = object of Exception
|
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
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import strformat
|
||||||
import stint
|
import stint
|
||||||
import strutils, sequtils
|
import strutils, sequtils
|
||||||
import chronicles
|
import chronicles
|
||||||
|
import types
|
||||||
import ../wallet/account
|
import ../wallet/account
|
||||||
|
|
||||||
proc getWalletAccounts*(): seq[WalletAccount] =
|
proc getWalletAccounts*(): seq[WalletAccount] =
|
||||||
|
@ -32,6 +33,36 @@ proc getWalletAccounts*(): seq[WalletAccount] =
|
||||||
let msg = getCurrentExceptionMsg()
|
let msg = getCurrentExceptionMsg()
|
||||||
error "Failed getting wallet accounts", msg
|
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 =
|
proc sendTransaction*(from_address: string, to: string, value: string, password: string): string =
|
||||||
var args = %* {
|
var args = %* {
|
||||||
"value": fmt"0x{toHex(value)}",
|
"value": fmt"0x{toHex(value)}",
|
||||||
|
|
|
@ -4,10 +4,11 @@ import libstatus/tokens as status_tokens
|
||||||
import libstatus/settings as status_settings
|
import libstatus/settings as status_settings
|
||||||
import libstatus/wallet as status_wallet
|
import libstatus/wallet as status_wallet
|
||||||
import libstatus/accounts/constants as constants
|
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/balance_manager
|
||||||
import wallet/account
|
import wallet/account
|
||||||
export account
|
export account
|
||||||
|
export Transaction
|
||||||
|
|
||||||
type WalletModel* = ref object
|
type WalletModel* = ref object
|
||||||
events*: EventEmitter
|
events*: EventEmitter
|
||||||
|
@ -144,3 +145,6 @@ proc toggleAsset*(self: WalletModel, symbol: string, enable: bool, address: stri
|
||||||
account.assetList = self.generateAccountConfiguredAssets(account.address)
|
account.assetList = self.generateAccountConfiguredAssets(account.address)
|
||||||
updateBalance(account, self.getDefaultCurrency())
|
updateBalance(account, self.getDefaultCurrency())
|
||||||
self.events.emit("assetChanged", Args())
|
self.events.emit("assetChanged", Args())
|
||||||
|
|
||||||
|
proc getTransfersByAddress*(self: WalletModel, address: string): seq[Transaction] =
|
||||||
|
result = status_wallet.getTransfersByAddress(address)
|
||||||
|
|
|
@ -1,8 +1,118 @@
|
||||||
import QtQuick 2.3
|
import QtQuick 2.3
|
||||||
|
import "../../../imports"
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
Text {
|
Component {
|
||||||
id: name3
|
id: transactionListItem
|
||||||
text: "HISTORY"
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,6 +81,9 @@ SplitView {
|
||||||
anchors.left: collectiblesBtn.right
|
anchors.left: collectiblesBtn.right
|
||||||
anchors.leftMargin: 32
|
anchors.leftMargin: 32
|
||||||
btnText: "History"
|
btnText: "History"
|
||||||
|
onClicked: {
|
||||||
|
walletModel.loadTransactionsForAccount(walletModel.currentAccount.address)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue