feat: eip1559 (#12)

This commit is contained in:
RichΛrd 2021-09-10 13:27:49 -04:00 committed by GitHub
parent efe2790db6
commit 219238a952
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 182 additions and 70 deletions

View File

@ -246,7 +246,7 @@ proc registerUsernameEstimateGas*(username: string, address: string, pubKey: str
if success:
result = fromHex[int](response)
proc registerUsername*(username, pubKey, address, gas, gasPrice, password: string, success: var bool): string =
proc registerUsername*(username, pubKey, address, gas, gasPrice: string, isEIP1559Enabled: bool, maxPriorityFeePerGas: string, maxFeePerGas: string, password: string, success: var bool): string =
let
label = fromHex(FixedBytes[32], label(username))
coordinates = extractCoordinates(pubkey)
@ -261,7 +261,7 @@ proc registerUsername*(username, pubKey, address, gas, gasPrice, password: stri
registerAbiEncoded = ensUsernamesContract.methods["register"].encodeAbi(register)
approveAndCallObj = ApproveAndCall[132](to: ensUsernamesContract.address, value: price, data: DynamicBytes[132].fromHex(registerAbiEncoded))
var tx = transactions.buildTokenTransaction(parseAddress(address), sntContract.address, gas, gasPrice)
var tx = transactions.buildTokenTransaction(parseAddress(address), sntContract.address, gas, gasPrice, isEIP1559Enabled, maxPriorityFeePerGas, maxFeePerGas)
result = sntContract.methods["approveAndCall"].send(tx, approveAndCallObj, password, success)
if success:
@ -288,7 +288,7 @@ proc setPubKeyEstimateGas*(username: string, address: string, pubKey: string, su
except RpcException as e:
raise
proc setPubKey*(username, pubKey, address, gas, gasPrice, password: string, success: var bool): string =
proc setPubKey*(username, pubKey, address, gas, gasPrice: string, isEIP1559Enabled: bool, maxPriorityFeePerGas: string, maxFeePerGas: string, password: string, success: var bool): string =
var hash = namehash(username)
hash.removePrefix("0x")
@ -300,7 +300,7 @@ proc setPubKey*(username, pubKey, address, gas, gasPrice, password: string, succ
setPubkey = SetPubkey(label: label, x: x, y: y)
resolverAddress = resolver(hash)
var tx = transactions.buildTokenTransaction(parseAddress(address), parseAddress(resolverAddress), gas, gasPrice)
var tx = transactions.buildTokenTransaction(parseAddress(address), parseAddress(resolverAddress), gas, gasPrice, isEIP1559Enabled, maxPriorityFeePerGas, maxFeePerGas)
try:
result = resolverContract.methods["setPubkey"].send(tx, setPubkey, password, success)

View File

@ -4,6 +4,8 @@ import
import
web3/[conversions, ethtypes], stint
import ../types/transaction
# TODO: make this public in nim-web3 lib
template stripLeadingZeros*(value: string): string =
var cidx = 0
@ -12,16 +14,20 @@ template stripLeadingZeros*(value: string): string =
cidx.inc
value[cidx .. ^1]
# TODO: update this in nim-web3
proc `%`*(x: EthSend): JsonNode =
proc `%`*(x: TransactionData): JsonNode =
result = newJobject()
result["from"] = %x.source
result["type"] = %x.txType
if x.to.isSome:
result["to"] = %x.to.unsafeGet
if x.gas.isSome:
result["gas"] = %x.gas.unsafeGet
if x.gasPrice.isSome:
result["gasPrice"] = %("0x" & x.gasPrice.unsafeGet.toHex.stripLeadingZeros)
if x.maxFeePerGas.isSome:
result["maxFeePerGas"] = %("0x" & x.maxFeePerGas.unsafeGet.toHex)
if x.maxPriorityFeePerGas.isSome:
result["maxPriorityFeePerGas"] = %("0x" & x.maxPriorityFeePerGas.unsafeGet.toHex)
if x.value.isSome:
result["value"] = %("0x" & x.value.unsafeGet.toHex)
result["data"] = %x.data

View File

@ -2,9 +2,9 @@ import
web3/ethtypes
import
transactions, ../../types/[rpc_response]
transactions, ../../types/[rpc_response, transaction]
proc sendTransaction*(tx: var EthSend, password: string, success: var bool): string =
proc sendTransaction*(tx: var TransactionData, password: string, success: var bool): string =
success = true
try:
let response = transactions.sendTransaction(tx, password)
@ -13,7 +13,7 @@ proc sendTransaction*(tx: var EthSend, password: string, success: var bool): str
success = false
result = e.msg
proc estimateGas*(tx: var EthSend, success: var bool): string =
proc estimateGas*(tx: var TransactionData, success: var bool): string =
success = true
try:
let response = transactions.estimateGas(tx)

View File

@ -5,7 +5,7 @@ import
nimcrypto, web3/[encoding, ethtypes]
import
../../types/[rpc_response], ../coder, eth, transactions
../../types/[rpc_response, transaction], ../coder, eth, transactions
export sendTransaction
@ -38,7 +38,7 @@ proc encodeAbi*(self: Method, obj: object = RootObj()): string =
result &= encoded.data
result &= data
proc estimateGas*(self: Method, tx: var EthSend, methodDescriptor: object, success: var bool): string =
proc estimateGas*(self: Method, tx: var TransactionData, methodDescriptor: object, success: var bool): string =
success = true
tx.data = self.encodeAbi(methodDescriptor)
try:
@ -48,11 +48,11 @@ proc estimateGas*(self: Method, tx: var EthSend, methodDescriptor: object, succe
success = false
result = e.msg
proc send*(self: Method, tx: var EthSend, methodDescriptor: object, password: string, success: var bool): string =
proc send*(self: Method, tx: var TransactionData, methodDescriptor: object, password: string, success: var bool): string =
tx.data = self.encodeAbi(methodDescriptor)
result = eth.sendTransaction(tx, password, success)
proc call*[T](self: Method, tx: var EthSend, methodDescriptor: object, success: var bool): T =
proc call*[T](self: Method, tx: var TransactionData, methodDescriptor: object, success: var bool): T =
success = true
tx.data = self.encodeAbi(methodDescriptor)
let response: RpcResponse

View File

@ -5,9 +5,9 @@ import
json_serialization, chronicles, web3/ethtypes
import
../core, ../../types/[rpc_response], ../conversions
../core, ../../types/[rpc_response, transaction], ../conversions
proc estimateGas*(tx: EthSend): RpcResponse =
proc estimateGas*(tx: TransactionData): RpcResponse =
let response = core.callPrivateRPC("eth_estimateGas", %*[%tx])
result = Json.decode(response, RpcResponse)
if not result.error.isNil:
@ -15,7 +15,7 @@ proc estimateGas*(tx: EthSend): RpcResponse =
trace "Gas estimated succesfully", estimate=result.result
proc sendTransaction*(tx: EthSend, password: string): RpcResponse =
proc sendTransaction*(tx: TransactionData, password: string): RpcResponse =
let responseStr = core.sendTransaction($(%tx), password)
result = Json.decode(responseStr, RpcResponse)
if not result.error.isNil:
@ -23,7 +23,7 @@ proc sendTransaction*(tx: EthSend, password: string): RpcResponse =
trace "Transaction sent succesfully", hash=result.result
proc call*(tx: EthSend): RpcResponse =
proc call*(tx: TransactionData): RpcResponse =
let responseStr = core.callPrivateRPC("eth_call", %*[%tx, "latest"])
result = Json.decode(responseStr, RpcResponse)
if not result.error.isNil:

View File

@ -145,3 +145,19 @@ proc fetchCryptoServices*(success: var bool): string =
success = false
error "Error getting crypto services: ", msg = e.msg
result = ""
proc maxPriorityFeePerGas*(): string =
let payload = %* []
result = callPrivateRPC("eth_maxPriorityFeePerGas", payload)
proc suggestFees*(): string =
let payload = %* []
result = callPrivateRPC("wallet_suggestFees", payload)
proc feeHistory*(n: int): string =
let payload = %* [n, "latest", nil]
result = callPrivateRPC("eth_feeHistory", payload)
proc getGasPrice*(): string =
let payload = %* []
result = callPrivateRPC("eth_gasPrice", payload)

View File

@ -56,11 +56,13 @@ const ACC_METHODS = toHashSet(["eth_accounts", "eth_coinbase"])
type ProviderModel* = ref object
events*: EventEmitter
permissions*: PermissionsModel
wallet*: WalletModel
proc newProviderModel*(events: EventEmitter, permissions: PermissionsModel): ProviderModel =
proc newProviderModel*(events: EventEmitter, permissions: PermissionsModel, wallet: WalletModel): ProviderModel =
result = ProviderModel()
result.events = events
result.permissions = permissions
result.wallet = wallet
proc requestType(message: string): RequestTypes =
let data = message.parseJson
@ -114,6 +116,8 @@ proc process(self: ProviderModel, data: Web3SendAsyncReadOnly): string =
let password = request["password"].getStr()
let selectedGasLimit = request["selectedGasLimit"].getStr()
let selectedGasPrice = request["selectedGasPrice"].getStr()
let selectedTipLimit = request{"selectedTipLimit"}.getStr()
let selectedOverallLimit = request{"selectedOverallLimit"}.getStr()
let txData = if (request["params"][0].hasKey("data") and request["params"][0]["data"].kind != JNull):
request["params"][0]["data"].getStr()
else:
@ -124,8 +128,10 @@ proc process(self: ProviderModel, data: Web3SendAsyncReadOnly): string =
var response = ""
var validInput: bool = true
let eip1559Enabled = self.wallet.isEIP1559Enabled()
try:
validateTransactionInput(fromAddress, to, "", value, selectedGasLimit, selectedGasPrice, txData, "dummy")
validateTransactionInput(fromAddress, to, "", value, selectedGasLimit, selectedGasPrice, txData, eip1559Enabled, selectedTipLimit, selectedOverallLimit, "dummy")
except Exception as e:
validInput = false
success = false
@ -133,7 +139,7 @@ proc process(self: ProviderModel, data: Web3SendAsyncReadOnly): string =
if validInput:
# TODO make this async
response = wallet.sendTransaction(fromAddress, to, value, selectedGasLimit, selectedGasPrice, password, success, txData)
response = wallet.sendTransaction(fromAddress, to, value, selectedGasLimit, selectedGasPrice, eip1559Enabled, selectedTipLimit, selectedOverallLimit, password, success, txData)
errorMessage = if not success:
if response == "":
"web3-response-error"

View File

@ -8,6 +8,7 @@ type WalletSignal* = ref object of Signal
eventType*: string
blockNumber*: int
accounts*: seq[string]
baseFeePerGas*: string
# newTransactions*: ???
erc20*: bool
@ -18,6 +19,7 @@ proc fromEvent*(T: type WalletSignal, jsonSignal: JsonNode): WalletSignal =
if jsonSignal["event"].kind != JNull:
result.eventType = jsonSignal["event"]["type"].getStr
result.blockNumber = jsonSignal["event"]{"blockNumber"}.getInt
result.baseFeePerGas = jsonSignal["event"]{"baseFeePerGas"}.getStr
result.erc20 = jsonSignal["event"]{"erc20"}.getBool
result.accounts = @[]
if jsonSignal["event"]["accounts"].kind != JNull:

View File

@ -50,7 +50,7 @@ proc newStatusInstance*(fleetConfig: string): Status =
result.mailservers = mailservers.newMailserversModel(result.events)
result.browser = browser.newBrowserModel(result.events)
result.tokens = tokens.newTokensModel(result.events)
result.provider = provider.newProviderModel(result.events, result.permissions)
result.provider = provider.newProviderModel(result.events, result.permissions, result.wallet)
result.osnotifications = newOsNotifications(result.events)
proc initNode*(self: Status, statusGoDir, keystoreDir: string) =

View File

@ -43,14 +43,14 @@ proc init*(self: StickersModel) =
var evArgs = StickerArgs(e)
self.addStickerToRecent(evArgs.sticker, evArgs.save)
proc buildTransaction(packId: Uint256, address: Address, price: Uint256, approveAndCall: var ApproveAndCall[100], sntContract: var Erc20Contract, gas = "", gasPrice = ""): EthSend =
proc buildTransaction(packId: Uint256, address: Address, price: Uint256, approveAndCall: var ApproveAndCall[100], sntContract: var Erc20Contract, gas = "", gasPrice = "", isEIP1559Enabled = false, maxPriorityFeePerGas = "", maxFeePerGas = ""): TransactionData =
sntContract = status_contracts.getSntContract()
let
stickerMktContract = status_contracts.getContract("sticker-market")
buyToken = BuyToken(packId: packId, address: address, price: price)
buyTxAbiEncoded = stickerMktContract.methods["buyToken"].encodeAbi(buyToken)
approveAndCall = ApproveAndCall[100](to: stickerMktContract.address, value: price, data: DynamicBytes[100].fromHex(buyTxAbiEncoded))
transactions.buildTokenTransaction(address, sntContract.address, gas, gasPrice)
transactions.buildTokenTransaction(address, sntContract.address, gas, gasPrice, isEIP1559Enabled, maxPriorityFeePerGas, maxFeePerGas)
proc estimateGas*(packId: int, address: string, price: string, success: var bool): int =
var
@ -68,7 +68,7 @@ proc estimateGas*(packId: int, address: string, price: string, success: var bool
if success:
result = fromHex[int](response)
proc buyPack*(self: StickersModel, packId: int, address, price, gas, gasPrice, password: string, success: var bool): string =
proc buyPack*(self: StickersModel, packId: int, address, price, gas, gasPrice: string, isEIP1559Enabled: bool, maxPriorityFeePerGas: string, maxFeePerGas: string, password: string, success: var bool): string =
var
sntContract: Erc20Contract
approveAndCall: ApproveAndCall[100]
@ -79,7 +79,10 @@ proc buyPack*(self: StickersModel, packId: int, address, price, gas, gasPrice, p
approveAndCall,
sntContract,
gas,
gasPrice
gasPrice,
isEIP1559Enabled,
maxPriorityFeePerGas,
maxFeePerGas
)
result = sntContract.methods["approveAndCall"].send(tx, approveAndCall, password, success)

View File

@ -2,19 +2,25 @@ import
options, strutils
import
stint, web3/ethtypes
stint, web3/ethtypes, types/transaction
from utils as status_utils import toUInt64, gwei2Wei, parseAddress
proc buildTransaction*(source: Address, value: Uint256, gas = "", gasPrice = "", data = ""): EthSend =
result = EthSend(
proc buildTransaction*(source: Address, value: Uint256, gas = "", gasPrice = "", isEIP1559Enabled = false, maxPriorityFeePerGas = "", maxFeePerGas = "", data = ""): TransactionData =
result = TransactionData(
source: source,
value: value.some,
gas: (if gas.isEmptyOrWhitespace: Quantity.none else: Quantity(cast[uint64](parseFloat(gas).toUInt64)).some),
gasPrice: (if gasPrice.isEmptyOrWhitespace: int.none else: gwei2Wei(parseFloat(gasPrice)).truncate(int).some),
data: data
)
if isEIP1559Enabled:
result.txType = "0x02"
result.maxPriorityFeePerGas = if maxFeePerGas.isEmptyOrWhitespace: Uint256.none else: gwei2Wei(parseFloat(maxPriorityFeePerGas)).some
result.maxFeePerGas = (if maxFeePerGas.isEmptyOrWhitespace: Uint256.none else: gwei2Wei(parseFloat(maxFeePerGas)).some)
else:
result.txType = "0x00"
proc buildTokenTransaction*(source, contractAddress: Address, gas = "", gasPrice = ""): EthSend =
result = buildTransaction(source, 0.u256, gas, gasPrice)
proc buildTokenTransaction*(source, contractAddress: Address, gas = "", gasPrice = "", isEIP1559Enabled = false, maxPriorityFeePerGas = "", maxFeePerGas = ""): TransactionData =
result = buildTransaction(source, 0.u256, gas, gasPrice, isEIP1559Enabled, maxPriorityFeePerGas, maxFeePerGas)
result.to = contractAddress.some

View File

@ -1,7 +1,7 @@
{.used.}
import strutils
import web3/ethtypes, options, stint
include pending_transaction_type
type
@ -22,6 +22,19 @@ type
fromAddress*: string
to*: string
type
TransactionData* = object
source*: Address # the address the transaction is send from.
to*: Option[Address] # (optional when creating new contract) the address the transaction is directed to.
gas*: Option[Quantity] # (optional, default: 90000) integer of the gas provided for the transaction execution. It will return unused gas.
gasPrice*: Option[int] # (optional, default: To-Be-Determined) integer of the gasPrice used for each paid gas.
maxPriorityFeePerGas*: Option[Uint256]
maxFeePerGas*: Option[Uint256]
value*: Option[Uint256] # (optional) integer of the value sent with this transaction.
data*: string # the compiled code of a contract OR the hash of the invoked method signature and encoded parameters. For details see Ethereum Contract ABI.
nonce*: Option[Nonce] # (optional) integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce
txType*: string
proc cmpTransactions*(x, y: Transaction): int =
# Sort proc to compare transactions from a single account.
# Compares first by block number, then by nonce

View File

@ -88,6 +88,8 @@ proc wei2Eth*(input: string, decimals: int): string =
error "Error parsing this wei value", input, msg=e.msg
result = "0"
proc wei2Gwei*(input: string): string =
result = wei2Eth(input, 9)
proc first*(jArray: JsonNode, fieldName, id: string): JsonNode =
if jArray == nil:
@ -139,13 +141,19 @@ proc isAddress*(strAddress: string): bool =
return false
return true
proc validateTransactionInput*(from_addr, to_addr, assetAddress, value, gas, gasPrice, data, uuid: string) =
proc validateTransactionInput*(from_addr, to_addr, assetAddress, value, gas, gasPrice, data: string, isEIP1599Enabled: bool, maxPriorityFeePerGas, maxFeePerGas, uuid: string) =
if not isAddress(from_addr): raise newException(ValueError, "from_addr is not a valid ETH address")
if not isAddress(to_addr): raise newException(ValueError, "to_addr is not a valid ETH address")
if parseFloat(value) < 0: raise newException(ValueError, "value should be a number >= 0")
if parseInt(gas) <= 0: raise newException(ValueError, "gas should be a number > 0")
if isEIP1599Enabled:
if gasPrice != "" and (maxPriorityFeePerGas != "" or maxFeePerGas != ""):
raise newException(ValueError, "gasPrice can't be used with maxPriorityFeePerGas and maxFeePerGas")
if gasPrice == "":
if parseFloat(maxPriorityFeePerGas) <= 0: raise newException(ValueError, "maxPriorityFeePerGas should be a number > 0")
if parseFloat(maxFeePerGas) <= 0: raise newException(ValueError, "maxFeePerGas should be a number > 0")
else:
if parseFloat(gasPrice) <= 0: raise newException(ValueError, "gasPrice should be a number > 0")
if uuid.isEmptyOrWhitespace(): raise newException(ValueError, "uuid is required")
if assetAddress != "": # If a token is being used

View File

@ -1,6 +1,6 @@
import json, strformat, strutils, chronicles, sequtils, sugar, httpclient, tables, net
import json_serialization, stint
from web3/ethtypes import Address, EthSend, Quantity
import json_serialization, stint, stew/byteutils, algorithm
from web3/ethtypes import Address, Quantity
from web3/conversions import `$`
from libstatus/core import getBlockByNumber
import libstatus/accounts as status_accounts
@ -10,7 +10,7 @@ import libstatus/wallet as status_wallet
import libstatus/accounts/constants as constants
import libstatus/eth/[eth, contracts]
from libstatus/core import getBlockByNumber
from utils as libstatus_utils import eth2Wei, gwei2Wei, first, toUInt64, parseAddress
from utils as libstatus_utils import eth2Wei, gwei2Wei, wei2Gwei, first, toUInt64, parseAddress
import wallet/[balance_manager, collectibles]
import wallet/account as wallet_account
import transactions
@ -38,6 +38,8 @@ type WalletModel* = ref object
defaultCurrency*: string
tokens*: seq[Erc20Contract]
totalBalance*: float
eip1559Enabled*: bool
latestBaseFee*: string
proc getDefaultCurrency*(self: WalletModel): string
proc calculateTotalFiatBalance*(self: WalletModel)
@ -49,6 +51,7 @@ proc newWalletModel*(events: EventEmitter): WalletModel =
result.events = events
result.defaultCurrency = ""
result.totalBalance = 0.0
result.eip1559Enabled = false
proc initEvents*(self: WalletModel) =
self.events.on("currencyChanged") do(e: Args):
@ -64,12 +67,12 @@ proc initEvents*(self: WalletModel) =
proc delete*(self: WalletModel) =
discard
proc buildTokenTransaction(source, to, assetAddress: Address, value: float, transfer: var Transfer, contract: var Erc20Contract, gas = "", gasPrice = ""): EthSend =
proc buildTokenTransaction(source, to, assetAddress: Address, value: float, transfer: var Transfer, contract: var Erc20Contract, gas = "", gasPrice = "", isEIP1559Enabled: bool = false, maxPriorityFeePerGas = "", maxFeePerGas = ""): TransactionData =
contract = getErc20Contract(assetAddress)
if contract == nil:
raise newException(ValueError, fmt"Could not find ERC-20 contract with address '{assetAddress}' for the current network")
transfer = Transfer(to: to, value: eth2Wei(value, contract.decimals))
transactions.buildTokenTransaction(source, assetAddress, gas, gasPrice)
transactions.buildTokenTransaction(source, assetAddress, gas, gasPrice, isEIP1559Enabled, maxPriorityFeePerGas, maxFeePerGas)
proc getKnownTokenContract*(self: WalletModel, address: Address): Erc20Contract =
getErc20Contracts().concat(getCustomTokens()).getErc20ContractByAddress(address)
@ -99,15 +102,17 @@ proc confirmTransactionStatus(self: WalletModel, pendingTransactions: JsonNode,
)
self.events.emit(parseEnum[PendingTransactionType](trx["type"].getStr).confirmed, ev)
proc getLatestBlockNumber*(self: WalletModel): int =
proc getLatestBlock*(): tuple[blockNumber: int, baseFee: string] =
let response = getBlockByNumber("latest").parseJson()
if not response.hasKey("result"):
return -1
if response.hasKey("result"):
let blockNumber = parseInt($fromHex(Stuint[256], response["result"]["number"].getStr))
let baseFee = $fromHex(Stuint[256], response["result"]{"baseFeePerGas"}.getStr)
return (blockNumber, baseFee)
return (-1, "")
return parseInt($fromHex(Stuint[256], response["result"]["number"].getStr))
proc getLatestBlockNumber*(self: WalletModel): int = getLatestBlock()[0]
proc checkPendingTransactions*(self: WalletModel) =
let latestBlockNumber = self.getLatestBlockNumber()
proc checkPendingTransactions*(self: WalletModel, latestBlockNumber: int) =
if latestBlockNumber == -1:
return
@ -133,10 +138,10 @@ proc estimateTokenGas*(self: WalletModel, source, to, assetAddress, value: strin
result = contract.methods["transfer"].estimateGas(tx, transfer, success)
proc sendTransaction*(source, to, value, gas, gasPrice, password: string, success: var bool, data = ""): string =
proc sendTransaction*(source, to, value, gas, gasPrice: string, isEIP1559Enabled: bool, maxPriorityFeePerGas, maxFeePerGas, password: string, success: var bool, data = ""): string =
var tx = transactions.buildTransaction(
parseAddress(source),
eth2Wei(parseFloat(value), 18), gas, gasPrice, data
eth2Wei(parseFloat(value), 18), gas, gasPrice, isEIP1559Enabled, maxPriorityFeePerGas, maxFeePerGas, data
)
if to != "":
@ -146,7 +151,7 @@ proc sendTransaction*(source, to, value, gas, gasPrice, password: string, succes
if success:
trackPendingTransaction(result, $source, $to, PendingTransactionType.WalletTransfer, "")
proc sendTokenTransaction*(source, to, assetAddress, value, gas, gasPrice, password: string, success: var bool): string =
proc sendTokenTransaction*(source, to, assetAddress, value, gas, gasPrice: string, isEIP1559Enabled: bool, maxPriorityFeePerGas, maxFeePerGas, password: string, success: var bool): string =
var
transfer: Transfer
contract: Erc20Contract
@ -158,7 +163,8 @@ proc sendTokenTransaction*(source, to, assetAddress, value, gas, gasPrice, passw
transfer,
contract,
gas,
gasPrice
gasPrice,
isEIP1559Enabled, maxPriorityFeePerGas, maxFeePerGas
)
result = contract.methods["transfer"].send(tx, transfer, password, success)
@ -217,6 +223,37 @@ proc newAccount*(self: WalletModel, walletType: string, derivationPath: string,
updateBalance(account, self.getDefaultCurrency())
account
proc maxPriorityFeePerGas*(self: WalletModel):string =
let response = status_wallet.maxPriorityFeePerGas().parseJson()
if response.hasKey("result"):
return $fromHex(Stuint[256], response["result"].getStr)
else:
error "Error obtaining max priority fee per gas", error=response
raise newException(StatusGoException, "Error obtaining max priority fee per gas")
proc suggestFees*(self: WalletModel):JsonNode =
let response = status_wallet.suggestFees().parseJson()
if response.hasKey("result"):
return response["result"].getElems()[0]
else:
error "Error obtaining suggested fees", error=response
raise newException(StatusGoException, "Error obtaining suggested fees")
proc cmpUint256(x, y: Uint256): int =
if x > y: 1
elif x == y: 0
else: -1
proc feeHistory*(self: WalletModel, n:int):seq[Uint256] =
let response = status_wallet.feeHistory(101).parseJson()
if response.hasKey("result"):
for it in response["result"]["baseFeePerGas"]:
result.add(fromHex(Stuint[256], it.getStr))
result.sort(cmpUint256)
else:
error "Error obtaining fee history", error=response
raise newException(StatusGoException, "Error obtaining fee history")
proc initAccounts*(self: WalletModel) =
self.tokens = status_tokens.getVisibleTokens()
let accounts = status_wallet.getWalletAccounts()
@ -354,23 +391,6 @@ proc getTransfersByAddress*(self: WalletModel, address: string, toBlock: Uint256
proc validateMnemonic*(self: WalletModel, mnemonic: string): string =
result = status_wallet.validateMnemonic(mnemonic).parseJSON()["error"].getStr
proc getGasPricePredictions*(): GasPricePrediction =
if status_settings.getCurrentNetwork() != NetworkType.Mainnet:
# TODO: what about other chains like xdai?
return GasPricePrediction(safeLow: 1.0, standard: 2.0, fast: 3.0, fastest: 4.0)
let secureSSLContext = newContext()
let client = newHttpClient(sslContext = secureSSLContext)
try:
let url: string = fmt"https://etherchain.org/api/gasPriceOracle"
client.headers = newHttpHeaders({ "Content-Type": "application/json" })
let response = client.request(url)
result = Json.decode(response.body, GasPricePrediction)
except Exception as e:
echo "error getting gas price predictions"
echo e.msg
finally:
client.close()
proc checkRecentHistory*(self: WalletModel, addresses: seq[string]): string =
result = status_wallet.checkRecentHistory(addresses)
@ -406,3 +426,35 @@ proc getOpenseaCollections*(address: string): string =
proc getOpenseaAssets*(address: string, collectionSlug: string, limit: int): string =
result = status_wallet.getOpenseaAssets(address, collectionSlug, limit)
proc getGasPrice*(self: WalletModel): string =
let response = status_wallet.getGasPrice().parseJson
if response.hasKey("result"):
return $fromHex(Stuint[256], response["result"].getStr)
else:
error "Error obtaining max priority fee per gas", error=response
raise newException(StatusGoException, "Error obtaining gas price")
proc setLatestBaseFee*(self: WalletModel, latestBaseFee: string) =
self.latestBaseFee = latestBaseFee
proc getLatestBaseFee*(self: WalletModel): string =
result = self.latestBaseFee
proc isEIP1559Enabled*(self: WalletModel, blockNumber: int):bool =
let networkId = status_settings.getCurrentNetworkDetails().config.networkId
let activationBlock = case status_settings.getCurrentNetworkDetails().config.networkId:
of 3: 10499401 # Ropsten
of 4: 8897988 # Rinkeby
of 5: 5062605 # Goerli
of 1: 12965000 # Mainnet
else: -1
if activationBlock > -1 and blockNumber >= activationBlock:
result = true
else:
result = false
self.eip1559Enabled = result
proc isEIP1559Enabled*(self: WalletModel): bool =
result = self.eip1559Enabled