2021-09-11 21:50:36 +00:00
|
|
|
# used to be statusgo_backend, should be merged with tokens
|
2021-09-11 12:27:07 +00:00
|
|
|
import
|
|
|
|
json, chronicles, strformat, stint, strutils, sequtils, tables, atomics
|
|
|
|
|
|
|
|
import
|
|
|
|
web3/[ethtypes, conversions], json_serialization
|
|
|
|
|
|
|
|
import
|
2021-09-22 17:49:45 +00:00
|
|
|
../statusgo_backend/[core, wallet, settings],
|
|
|
|
../statusgo_backend/tokens as statusgo_backend_tokens,
|
|
|
|
../types/[setting, network, rpc_response],
|
|
|
|
./contracts
|
|
|
|
from ../utils import parseAddress
|
2021-09-11 12:27:07 +00:00
|
|
|
|
|
|
|
var
|
|
|
|
customTokens {.threadvar.}: seq[Erc20Contract]
|
|
|
|
|
2021-09-22 17:49:45 +00:00
|
|
|
proc visibleTokensSNTDefault(network: Network): JsonNode =
|
|
|
|
let symbol = network.sntSymbol()
|
2021-09-11 12:27:07 +00:00
|
|
|
let response = getSetting[string](Setting.VisibleTokens, "{}").parseJSON
|
|
|
|
|
2021-09-22 17:49:45 +00:00
|
|
|
if not response.hasKey($network.chainId):
|
2021-09-11 12:27:07 +00:00
|
|
|
# Set STT/SNT visible by default
|
2021-09-22 17:49:45 +00:00
|
|
|
response[$network.chainId] = %* [symbol]
|
2021-09-11 12:27:07 +00:00
|
|
|
|
|
|
|
return response
|
|
|
|
|
2021-09-22 17:49:45 +00:00
|
|
|
proc convertStringSeqToERC20ContractSeq*(network: Network, stringSeq: seq[string]): seq[Erc20Contract] =
|
2021-09-11 12:27:07 +00:00
|
|
|
result = @[]
|
|
|
|
for v in stringSeq:
|
2021-09-22 17:49:45 +00:00
|
|
|
let t = findErc20Contract(network.chainId, v)
|
2021-09-11 12:27:07 +00:00
|
|
|
if t != nil: result.add t
|
2021-09-22 17:49:45 +00:00
|
|
|
let ct = customTokens.findBySymbol(v)
|
2021-09-11 12:27:07 +00:00
|
|
|
if ct != nil: result.add ct
|
|
|
|
|
2021-09-22 17:49:45 +00:00
|
|
|
proc toggleAsset*(network: Network, symbol: string): seq[Erc20Contract] =
|
|
|
|
let visibleTokens = visibleTokensSNTDefault(network)
|
|
|
|
var visibleTokenList = visibleTokens[$network.chainId].to(seq[string])
|
2021-09-11 12:27:07 +00:00
|
|
|
let symbolIdx = visibleTokenList.find(symbol)
|
|
|
|
if symbolIdx > -1:
|
|
|
|
visibleTokenList.del(symbolIdx)
|
|
|
|
else:
|
|
|
|
visibleTokenList.add symbol
|
2021-09-22 17:49:45 +00:00
|
|
|
visibleTokens[$network.chainId] = newJArray()
|
|
|
|
visibleTokens[$network.chainId] = %* visibleTokenList
|
|
|
|
let saved = saveSetting(Setting.VisibleTokens, $visibleTokens)
|
2021-09-11 12:27:07 +00:00
|
|
|
|
2021-09-22 17:49:45 +00:00
|
|
|
convertStringSeqToERC20ContractSeq(network, visibleTokenList)
|
2021-09-11 12:27:07 +00:00
|
|
|
|
2021-09-22 17:49:45 +00:00
|
|
|
proc hideAsset*(network: Network, symbol: string) =
|
|
|
|
let visibleTokens = visibleTokensSNTDefault(network)
|
|
|
|
var visibleTokenList = visibleTokens[$network.chainId].to(seq[string])
|
2021-09-11 12:27:07 +00:00
|
|
|
var symbolIdx = visibleTokenList.find(symbol)
|
|
|
|
if symbolIdx > -1:
|
|
|
|
visibleTokenList.del(symbolIdx)
|
2021-09-22 17:49:45 +00:00
|
|
|
visibleTokens[$network.chainId] = newJArray()
|
|
|
|
visibleTokens[$network.chainId] = %* visibleTokenList
|
2021-09-11 12:27:07 +00:00
|
|
|
discard saveSetting(Setting.VisibleTokens, $visibleTokens)
|
|
|
|
|
2021-09-22 17:49:45 +00:00
|
|
|
proc getVisibleTokens*(network: Network): seq[Erc20Contract] =
|
|
|
|
let visibleTokens = visibleTokensSNTDefault(network)
|
|
|
|
var visibleTokenList = visibleTokens[$network.chainId].to(seq[string])
|
2021-09-11 21:50:36 +00:00
|
|
|
let customTokens = statusgo_backend_tokens.getCustomTokens()
|
2021-09-11 12:27:07 +00:00
|
|
|
|
2021-09-22 17:49:45 +00:00
|
|
|
result = convertStringSeqToERC20ContractSeq(network, visibleTokenList)
|
2021-09-11 12:27:07 +00:00
|
|
|
|
2021-09-22 17:49:45 +00:00
|
|
|
proc getToken*(network: Network, tokenAddress: string): Erc20Contract =
|
|
|
|
allErc20ContractsByChainId(network.chainId).concat(statusgo_backend_tokens.getCustomTokens()).findByAddress(tokenAddress.parseAddress)
|
2021-09-11 12:27:07 +00:00
|
|
|
|
2021-09-22 17:49:45 +00:00
|
|
|
proc getTokenBalance*(network: Network, tokenAddress: string, account: string): string =
|
2021-09-11 12:27:07 +00:00
|
|
|
var postfixedAccount: string = account
|
|
|
|
postfixedAccount.removePrefix("0x")
|
|
|
|
let payload = %* [{
|
|
|
|
"to": tokenAddress, "from": account, "data": fmt"0x70a08231000000000000000000000000{postfixedAccount}"
|
|
|
|
}, "latest"]
|
|
|
|
let response = callPrivateRPC("eth_call", payload)
|
|
|
|
let balance = response.parseJson["result"].getStr
|
|
|
|
|
|
|
|
var decimals = 18
|
|
|
|
let address = parseAddress(tokenAddress)
|
2021-09-22 17:49:45 +00:00
|
|
|
let t = findErc20Contract(network.chainId, address)
|
|
|
|
let ct = statusgo_backend_tokens.getCustomTokens().findByAddress(address)
|
2021-09-11 12:27:07 +00:00
|
|
|
if t != nil:
|
|
|
|
decimals = t.decimals
|
|
|
|
elif ct != nil:
|
|
|
|
decimals = ct.decimals
|
|
|
|
|
|
|
|
result = $hex2Token(balance, decimals)
|
|
|
|
|
2021-09-22 17:49:45 +00:00
|
|
|
proc getSNTAddress*(network: Network): string =
|
|
|
|
let contract = findErc20Contract(network.chainId, network.sntSymbol)
|
|
|
|
return $contract.address
|
2021-09-11 12:27:07 +00:00
|
|
|
|
2021-09-22 17:49:45 +00:00
|
|
|
proc getSNTBalance*(network: Network, account: string): string =
|
|
|
|
result = getTokenBalance(network, getSNTAddress(network), account)
|
2021-09-11 12:27:07 +00:00
|
|
|
|
|
|
|
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]).truncate(int)
|
|
|
|
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)
|