get token balance

get token balance

fix token balance call

Fix assets on load

add token list

display images

cleanup

cleanup

cleanup

clean up
This commit is contained in:
Iuri Matias 2020-06-08 09:55:18 -04:00
parent 761be22bfa
commit 826c0ed46d
12 changed files with 1496 additions and 140 deletions

View File

@ -9,6 +9,7 @@ type
Value = UserRole + 3,
FiatValue = UserRole + 4,
Image = UserRole + 5
HasIcon = UserRole + 6
QtObject:
type AssetList* = ref object of QAbstractListModel
@ -41,13 +42,15 @@ QtObject:
of AssetRoles.Value: result = newQVariant(asset.value)
of AssetRoles.FiatValue: result = newQVariant(asset.fiatValue)
of AssetRoles.Image: result = newQVariant(asset.image)
of AssetRoles.HasIcon: result = newQVariant(asset.hasIcon)
method roleNames(self: AssetList): Table[int, string] =
{ AssetRoles.Name.int:"name",
AssetRoles.Symbol.int:"symbol",
AssetRoles.Value.int:"value",
AssetRoles.FiatValue.int:"fiatValue",
AssetRoles.Image.int:"image" }.toTable
AssetRoles.Image.int:"image",
AssetRoles.Image.int:"hasIcon" }.toTable
proc addAssetToList*(self: AssetList, asset: Asset) =
self.beginInsertRows(newQModelIndex(), self.assets.len, self.assets.len)

View File

@ -183,29 +183,32 @@ proc MultiAccountImportPrivateKey*(privateKey: string): GeneratedAccount =
result = Json.decode(importResult, GeneratedAccount)
proc saveAccount*(account: GeneratedAccount, password: string, color: string, accountType: string, isADerivedAccount = true): DerivedAccount =
# Only store derived accounts. Private key accounts are not multiaccounts
if (isADerivedAccount):
discard storeDerivedAccounts(account, password)
try:
# Only store derived accounts. Private key accounts are not multiaccounts
if (isADerivedAccount):
discard storeDerivedAccounts(account, password)
var address = account.derived.defaultWallet.address
var publicKey = account.derived.defaultWallet.publicKey
var address = account.derived.defaultWallet.address
var publicKey = account.derived.defaultWallet.publicKey
if (address == ""):
address = account.address
publicKey = account.publicKey
if (address == ""):
address = account.address
publicKey = account.publicKey
discard callPrivateRPC("accounts_saveAccounts", %* [
[{
"color": color,
"name": account.name,
"address": address,
"public-key": publicKey,
"type": accountType,
"path": "m/44'/60'/0'/0/1"
}]
])
discard callPrivateRPC("accounts_saveAccounts", %* [
[{
"color": color,
"name": account.name,
"address": address,
"public-key": publicKey,
"type": accountType,
"path": "m/44'/60'/0'/0/1"
}]
])
result = DerivedAccount(address: address, publicKey: publicKey)
result = DerivedAccount(address: address, publicKey: publicKey)
except:
error "Error storing the new account. Bad password?"
proc deriveAccounts*(accountId: string): MultiAccounts =
let deriveJson = %* {

View File

@ -1,6 +1,10 @@
import core as status
import json
import chronicles
import strformat
import stint
import strutils
import wallet
logScope:
topics = "wallet"
@ -12,13 +16,13 @@ proc getCustomTokens*(): JsonNode =
return %* []
return response["result"]
proc addCustomToken*(address: string, name: string, symbol: string, decimals: int, color: string): string =
proc addCustomToken*(address: string, name: string, symbol: string, decimals: int, color: string) =
let payload = %* [{"address": address, "name": name, "symbol": symbol, "decimals": decimals, "color": color}]
status.callPrivateRPC("wallet_addCustomToken", payload)
discard status.callPrivateRPC("wallet_addCustomToken", payload)
proc removeCustomToken*(address: string): string =
proc removeCustomToken*(address: string) =
let payload = %* [address]
status.callPrivateRPC("wallet_deleteCustomToken", payload)
discard status.callPrivateRPC("wallet_deleteCustomToken", payload)
proc getTokensBalances*(accounts: openArray[string], tokens: openArray[string]): JsonNode =
let payload = %* [accounts, tokens]
@ -26,3 +30,20 @@ proc getTokensBalances*(accounts: openArray[string], tokens: openArray[string]):
if response["result"].kind == JNull:
return %* {}
response["result"]
proc getTokenBalance*(tokenAddress: string, account: string): string =
var postfixedAccount: string = account
postfixedAccount.removePrefix("0x")
let payload = %* [{
"to": tokenAddress, "from": account, "data": fmt"0x70a08231000000000000000000000000{postfixedAccount}"
}, "latest"]
var response = status.callPrivateRPC("eth_call", payload)
var balance = response.parseJson["result"].getStr
result = $hex2Eth(balance)
proc addOrRemoveToken*(enable: bool, address: string, name: string, symbol: string, decimals: int, color: string): JsonNode =
if enable:
addCustomToken(address, name, symbol, decimals, color)
else:
removeCustomToken(address)
getCustomTokens()

View File

@ -34,7 +34,6 @@ proc getWalletAccounts*(): seq[WalletAccount] =
let msg = getCurrentExceptionMsg()
error "Failed getting wallet accounts", msg
proc sendTransaction*(from_address: string, to: string, value: string, password: string): string =
var args = %* {
"value": fmt"0x{toHex(value)}",
@ -44,17 +43,6 @@ proc sendTransaction*(from_address: string, to: string, value: string, password:
var response = status.sendTransaction($args, password)
result = response
proc getPrice*(crypto: string, fiat: string): string =
var url: string = fmt"https://min-api.cryptocompare.com/data/price?fsym={crypto}&tsyms={fiat}"
let client = newHttpClient()
client.headers = newHttpHeaders({ "Content-Type": "application/json" })
try:
let response = client.request(url)
result = $parseJson(response.body)[fiat.toUpper]
except:
echo "error getting price"
proc getBalance*(address: string): string =
let payload = %* [address, "latest"]
parseJson(status.callPrivateRPC("eth_getBalance", payload))["result"].str

View File

@ -1,28 +1,14 @@
import eventemitter
import json
import strformat
import strutils
import libstatus/wallet as status_wallet
import libstatus/settings as status_settings
import eventemitter, json, strformat, strutils, tables, chronicles, sequtils
import libstatus/accounts as status_accounts
import libstatus/accounts/constants as constants
import libstatus/types
import chronicles
import libstatus/tokens as status_tokens
type CurrencyArgs* = ref object of Args
currency*: string
type Asset* = ref object
name*, symbol*, value*, fiatValue*, image*: string
type Account* = ref object
name*, address*, iconColor*, balance*: string
realFiatBalance*: float
assetList*: seq[Asset]
type AccountArgs* = ref object of Args
account*: Account
import libstatus/settings as status_settings
import libstatus/wallet as status_wallet
import libstatus/accounts/constants as constants
from libstatus/types import GeneratedAccount, DerivedAccount
import wallet/token_list
import wallet/balance_manager
import wallet/account
export account
type WalletModel* = ref object
events*: EventEmitter
@ -30,7 +16,6 @@ type WalletModel* = ref object
defaultCurrency*: string
tokens*: JsonNode
proc updateBalance*(self: Account)
proc getDefaultCurrency*(self: WalletModel): string
proc newWalletModel*(events: EventEmitter): WalletModel =
@ -44,7 +29,7 @@ proc initEvents*(self: WalletModel) =
self.events.on("currencyChanged") do(e: Args):
self.defaultCurrency = self.getDefaultCurrency()
for account in self.accounts:
account.updateBalance()
updateBalance(account, self.getDefaultCurrency())
self.events.emit("accountsUpdated", Args())
proc delete*(self: WalletModel) =
@ -53,80 +38,34 @@ proc delete*(self: WalletModel) =
proc sendTransaction*(self: WalletModel, from_value: string, to: string, value: string, password: string): string =
status_wallet.sendTransaction(from_value, to, value, password)
proc getEthBalance*(address: string): string =
var balance = status_wallet.getBalance(address)
echo(fmt"balance in hex: {balance}")
# 2. convert balance to eth
var eth_value = status_wallet.hex2Eth(balance)
echo(fmt"balance in eth: {eth_value}")
eth_value
proc getDefaultCurrency*(): string =
status_settings.getSettings().parseJSON()["result"]["currency"].getStr
proc getDefaultCurrency*(self: WalletModel): string =
getDefaultCurrency()
status_settings.getSettings().parseJSON()["result"]["currency"].getStr
proc setDefaultCurrency*(self: WalletModel, currency: string) =
discard status_settings.saveSettings("currency", currency)
self.events.emit("currencyChanged", CurrencyArgs(currency: currency))
proc getFiatValue*(eth_balance: string, symbol: string, fiat_symbol: string): float =
if eth_balance == "0.0": return 0.0
# 3. get usd price of 1 eth
var fiat_eth_price = status_wallet.getPrice("ETH", fiat_symbol)
echo(fmt"fiat_price: {fiat_eth_price}")
# 4. convert balance to usd
var fiat_balance = parseFloat(eth_balance) * parseFloat(fiat_eth_price)
echo(fmt"balance in usd: {fiat_balance}")
fiat_balance
proc hasAsset*(self: WalletModel, account: string, symbol: string): bool =
for token in self.tokens:
if symbol == token["symbol"].getStr:
return true
return false
proc updateBalance*(self: Account) =
let defaultCurrency = getDefaultCurrency()
const symbol = "ETH"
let eth_balance = getEthBalance(self.address)
let usd_balance = getFiatValue(eth_balance, symbol, defaultCurrency)
var totalAccountBalance = usd_balance
self.balance = fmt"{totalAccountBalance:.2f} {defaultCurrency}"
proc generateAccountConfiguredAssets*(self: WalletModel): seq[Asset] =
var assets: seq[Asset] = @[]
var symbol = "ETH"
var asset = Asset(name:"Ethereum", symbol: symbol, value: fmt"0.0", fiatValue: "$" & fmt"0.0", image: fmt"../../img/token-icons/{toLowerAscii(symbol)}.svg")
var asset = Asset(name:"Ethereum", symbol: "ETH", value: "0.0", fiatValue: "0.0", image: fmt"../../img/token-icons/eth.svg", hasIcon: true)
assets.add(asset)
for token in self.tokens:
var symbol = token["symbol"].getStr
var existingToken = Asset(name: token["name"].getStr, symbol: symbol, value: fmt"0.0", fiatValue: "$0.0", image: fmt"../../img/token-icons/{toLowerAscii(symbol)}.svg")
var existingToken = Asset(name: token["name"].getStr, symbol: symbol, value: fmt"0.0", fiatValue: "$0.0", image: fmt"../../img/token-icons/{toLowerAscii(symbol)}.svg", hasIcon: true)
assets.add(existingToken)
assets
proc newAccount*(self: WalletModel, name: string, address: string, iconColor: string, balance: string): Account =
var assets: seq[Asset] = self.generateAccountConfiguredAssets()
var account = Account(name: name, address: address, iconColor: iconColor, balance: fmt"{balance} {self.defaultCurrency}", assetList: assets, realFiatBalance: 0.0)
updateBalance(account, self.getDefaultCurrency())
account
proc initAccounts*(self: WalletModel) =
self.tokens = status_tokens.getCustomTokens()
let accounts = status_wallet.getWalletAccounts()
var totalAccountBalance: float = 0
const symbol = "ETH"
let defaultCurrency = getDefaultCurrency()
for account in accounts:
let address = account.address
let eth_balance = getEthBalance(address)
let usd_balance = getFiatValue(eth_balance, symbol, defaultCurrency)
totalAccountBalance = totalAccountBalance + usd_balance
var assets: seq[Asset] = self.generateAccountConfiguredAssets()
var account = Account(name: account.name, address: address, iconColor: account.color, balance: "", assetList: assets, realFiatBalance: totalAccountBalance)
account.updateBalance()
var account = self.newAccount(account.name, account.address, account.color, "")
self.accounts.add(account)
proc getTotalFiatBalance*(self: WalletModel): string =
@ -135,21 +74,8 @@ proc getTotalFiatBalance*(self: WalletModel): string =
proc addNewGeneratedAccount(self: WalletModel, generatedAccount: GeneratedAccount, password: string, accountName: string, color: string, accountType: string, isADerivedAccount = true) =
generatedAccount.name = accountName
var derivedAccount: DerivedAccount
try:
derivedAccount = status_accounts.saveAccount(generatedAccount, password, color, accountType, isADerivedAccount)
except:
error "Error storing the new account. Bad password?"
return
# TODO actually fetch the balance for accounts that are not generated
var symbol = "SNT"
var asset = Asset(name:"Status", symbol: symbol, value: fmt"0.0", fiatValue: "$" & fmt"0.0", image: fmt"../../img/token-icons/{toLowerAscii(symbol)}.svg")
var assets: seq[Asset] = self.generateAccountConfiguredAssets()
var account = Account(name: accountName, address: derivedAccount.address, iconColor: color, balance: fmt"0.00 {self.defaultCurrency}", assetList: assets, realFiatBalance: 0.0)
var derivedAccount: DerivedAccount = status_accounts.saveAccount(generatedAccount, password, color, accountType, isADerivedAccount)
var account = self.newAccount(accountName, derivedAccount.address, color, fmt"0.00 {self.defaultCurrency}")
self.accounts.add(account)
self.events.emit("newAccountAdded", AccountArgs(account: account))
@ -171,13 +97,12 @@ proc addWatchOnlyAccount*(self: WalletModel, address: string, accountName: strin
let account = GeneratedAccount(address: address)
self.addNewGeneratedAccount(account, "", accountName, color, constants.WATCH, false)
proc hasAsset*(self: WalletModel, account: string, symbol: string): bool =
self.tokens.anyIt(it["symbol"].getStr == symbol)
proc toggleAsset*(self: WalletModel, symbol: string, enable: bool, address: string, name: string, decimals: int, color: string) =
if enable:
discard status_tokens.addCustomToken(address, name, symbol, decimals, color)
else:
discard status_tokens.removeCustomToken(address)
self.tokens = status_tokens.getCustomTokens()
self.tokens = addOrRemoveToken(enable, address, name, symbol, decimals, color)
for account in self.accounts:
var assets: seq[Asset] = self.generateAccountConfiguredAssets()
account.assetList = assets
account.assetList = self.generateAccountConfiguredAssets()
updateBalance(account, self.getDefaultCurrency())
self.events.emit("assetChanged", Args())

View File

@ -0,0 +1,16 @@
import eventemitter
type CurrencyArgs* = ref object of Args
currency*: string
type Asset* = ref object
name*, symbol*, value*, fiatValue*, image*: string
hasIcon*: bool
type Account* = ref object
name*, address*, iconColor*, balance*: string
realFiatBalance*: float
assetList*: seq[Asset]
type AccountArgs* = ref object of Args
account*: Account

View File

@ -0,0 +1,67 @@
import tables, strformat, strutils, stint, httpclient, json
import ../libstatus/wallet as status_wallet
import ../libstatus/tokens as status_tokens
import account
import token_list
type BalanceManager* = ref object
pricePairs: Table[string, string]
tokenBalances: Table[string, string]
proc newBalanceManager*(): BalanceManager =
result = BalanceManager()
result.pricePairs = initTable[string, string]()
result.tokenBalances = initTable[string, string]()
var balanceManager = newBalanceManager()
proc getPrice(crypto: string, fiat: string): string =
try:
if balanceManager.pricePairs.hasKey(fiat):
return balanceManager.pricePairs[fiat]
var url: string = fmt"https://min-api.cryptocompare.com/data/price?fsym={crypto}&tsyms={fiat}"
echo url
let client = newHttpClient()
client.headers = newHttpHeaders({ "Content-Type": "application/json" })
let response = client.request(url)
echo $response.body
result = $parseJson(response.body)[fiat.toUpper]
balanceManager.pricePairs[fiat] = result
except Exception as e:
echo "error getting price"
echo e.msg
proc getEthBalance(address: string): string =
var balance = status_wallet.getBalance(address)
result = status_wallet.hex2Eth(balance)
balanceManager.tokenBalances["ETH"] = result
proc getBalance*(symbol: string, accountAddress: string): string =
if balanceManager.tokenBalances.hasKey(symbol):
return balanceManager.tokenBalances[symbol]
if symbol == "ETH":
return getEthBalance(accountAddress)
var token: AssetConfig = getTokenConfig(symbol)
result = $status_tokens.getTokenBalance(token.address, accountAddress)
balanceManager.tokenBalances[symbol] = result
proc getFiatValue*(crypto_balance: string, crypto_symbol: string, fiat_symbol: string): float =
if crypto_balance == "0.0": return 0.0
var fiat_crypto_price = getPrice(crypto_symbol, fiat_symbol)
parseFloat(crypto_balance) * parseFloat(fiat_crypto_price)
proc updateBalance*(asset: Asset, currency: string) =
var token_balance = getBalance(asset.symbol, "0xf977814e90da44bfa03b6295a0616a897441acec")
let fiat_balance = getFiatValue(token_balance, asset.symbol, currency)
asset.value = token_balance
asset.fiatValue = fmt"{fiat_Balance:.2f} {currency}"
proc updateBalance*(account: Account, currency: string) =
let eth_balance = getBalance("ETH", account.address)
let usd_balance = getFiatValue(eth_balance, "ETH", currency)
var totalAccountBalance = usd_balance
account.balance = fmt"{totalAccountBalance:.2f} {currency}"
for asset in account.assetList:
updateBalance(asset, currency)

File diff suppressed because it is too large Load Diff

View File

@ -17,7 +17,7 @@ Item {
id: assetInfoImage
width: 36
height: 36
source: image
source: hasIcon ? "../../img/tokens/" + symbol + ".png" : "../../img/tokens/0-native.png"
anchors.left: parent.left
anchors.leftMargin: 0
anchors.verticalCenter: parent.verticalCenter

BIN
ui/app/img/tokens/ETH.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 870 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB