feat: populate token details from contract address

This commit is contained in:
Richard Ramos 2020-11-02 12:46:04 -04:00 committed by Iuri Matias
parent bc1525f513
commit bba08d87b8
3 changed files with 102 additions and 5 deletions

View File

@ -1,7 +1,7 @@
import NimQml, tables import NimQml, tables, json
import ../../../status/libstatus/tokens import ../../../status/libstatus/[tokens, settings, utils, eth/contracts]
import ../../../status/libstatus/eth/contracts
from web3/conversions import `$` from web3/conversions import `$`
import ../../../status/threads
type type
TokenRoles {.pure.} = enum TokenRoles {.pure.} = enum
@ -81,3 +81,21 @@ QtObject:
TokenRoles.Decimals.int:"decimals", TokenRoles.Decimals.int:"decimals",
TokenRoles.IsCustom.int:"isCustom"}.toTable TokenRoles.IsCustom.int:"isCustom"}.toTable
# Resolving a ENS name
proc getTokenDetails*(self: TokenList, address: string) {.slot.} =
spawnAndSend(self, "tokenDetailsResolved") do:
let tkn = newErc20Contract("", getCurrentNetwork(), address.parseAddress, "", 18, false)
let decimals = tkn.tokenDecimals()
$ (%* {
"address": address,
"name": tkn.tokenName(),
"symbol": tkn.tokenSymbol(),
"decimals": (if decimals == 0: "" else: $decimals)
})
proc tokenDetailsWereResolved*(self: TokenList, tokenDetails: string) {.signal.}
proc tokenDetailsResolved(self: TokenList, tokenDetails: string) {.slot.} =
self.tokenDetailsWereResolved(tokenDetails)

View File

@ -1,4 +1,4 @@
import json, chronicles, strformat, stint, strutils, sequtils import json, chronicles, strformat, stint, strutils, sequtils, tables
import core, wallet import core, wallet
import ./eth/contracts import ./eth/contracts
import web3/[ethtypes, conversions] import web3/[ethtypes, conversions]
@ -131,3 +131,37 @@ proc getSNTAddress*(): string =
proc getSNTBalance*(account: string): string = proc getSNTBalance*(account: string): string =
let snt = contracts.getSntContract() let snt = contracts.getSntContract()
result = getTokenBalance($snt.address, account) result = getTokenBalance($snt.address, account)
proc getTokenString*(contract: Contract, methodName: string): string =
let payload = %* [{
"to": $contract.address,
"data": contract.methods[methodName].encodeAbi()
}, "latest"]
let responseStr = callPrivateRPC("eth_call", payload)
let response = Json.decode(responseStr, RpcResponse)
if not response.error.isNil:
raise newException(RpcException, "Error getting token string - " & methodName & ": " & response.error.message)
if response.result == "0x":
return ""
let size = fromHex(Stuint[256], response.result[66..129]).toInt
result = response.result[130..129+size*2].parseHexStr
proc tokenName*(contract: Contract): string = getTokenString(contract, "name")
proc tokenSymbol*(contract: Contract): string = getTokenString(contract, "symbol")
proc tokenDecimals*(contract: Contract): int =
let payload = %* [{
"to": $contract.address,
"data": contract.methods["decimals"].encodeAbi()
}, "latest"]
let responseStr = callPrivateRPC("eth_call", payload)
let response = Json.decode(responseStr, RpcResponse)
if not response.error.isNil:
raise newException(RpcException, "Error getting token decimals: " & response.error.message)
if response.result == "0x":
return 0
result = parseHexInt(response.result)

View File

@ -9,6 +9,7 @@ ModalPopup {
property bool editable: true property bool editable: true
property int marginBetweenInputs: 35 property int marginBetweenInputs: 35
property string validationError: ""
title: editable ? title: editable ?
//% "Add custom token" //% "Add custom token"
@ -39,13 +40,57 @@ ModalPopup {
open(); open();
} }
function validate() {
if (addressInput.text !== "" && !Utils.isAddress(addressInput.text)) {
validationError = qsTr("This needs to be a valid address");
}
return validationError === ""
}
property var getTokenDetails: Backpressure.debounce(popup, 500, function (tokenAddress){
walletModel.customTokenList.getTokenDetails(tokenAddress)
});
function onKeyReleased(){
validationError = "";
if (!validate() || addressInput.text === "") {
return;
}
Qt.callLater(getTokenDetails, addressInput.text)
}
Item {
Connections {
target: walletModel.customTokenList
onTokenDetailsWereResolved: {
const jsonObj = JSON.parse(tokenDetails)
if(jsonObj.address === ""){
validationError = qsTr("Invalid ERC20 address")
return;
}
if(addressInput.text.toLowerCase() === jsonObj.address.toLowerCase()){
symbolInput.text = jsonObj.symbol;
decimalsInput.text = jsonObj.decimals;
nameInput.text = jsonObj.name;
}
}
}
}
Input { Input {
id: addressInput id: addressInput
readOnly: !editable readOnly: !editable
textField.maximumLength: 42
//% "Enter contract address..." //% "Enter contract address..."
placeholderText: qsTrId("enter-contract-address...") placeholderText: qsTrId("enter-contract-address...")
//% "Contract address" //% "Contract address"
label: qsTrId("contract-address") label: qsTrId("contract-address")
validationError: popup.validationError
Keys.onReleased: onKeyReleased()
} }
Input { Input {
@ -98,7 +143,7 @@ ModalPopup {
//% "Add" //% "Add"
label: qsTrId("add") label: qsTrId("add")
disabled: addressInput.text === "" || nameInput.text === "" || symbolInput.text === "" || decimalsInput.text === "" disabled: validationError !== "" && addressInput.text === "" || nameInput.text === "" || symbolInput.text === "" || decimalsInput.text === ""
onClicked : { onClicked : {
const error = walletModel.addCustomToken(addressInput.text, nameInput.text, symbolInput.text, decimalsInput.text); const error = walletModel.addCustomToken(addressInput.text, nameInput.text, symbolInput.text, decimalsInput.text);