feat: make token send and eth send work
This commit is contained in:
parent
19f8f8e457
commit
81e7dffaa2
|
@ -157,8 +157,8 @@ QtObject:
|
||||||
read = getAccountList
|
read = getAccountList
|
||||||
notify = accountListChanged
|
notify = accountListChanged
|
||||||
|
|
||||||
proc onSendTransaction*(self: WalletView, from_value: string, to: string, value: string, password: string): string {.slot.} =
|
proc onSendTransaction*(self: WalletView, from_value: string, to: string, assetAddress: string, value: string, password: string): string {.slot.} =
|
||||||
result = self.status.wallet.sendTransaction(from_value, to, value, password)
|
return self.status.wallet.sendTransaction(from_value, to, assetAddress, value, password)
|
||||||
|
|
||||||
proc getDefaultAccount*(self: WalletView): string {.slot.} =
|
proc getDefaultAccount*(self: WalletView): string {.slot.} =
|
||||||
self.currentAccount.address
|
self.currentAccount.address
|
||||||
|
|
|
@ -7,6 +7,7 @@ type
|
||||||
Symbol = UserRole + 2,
|
Symbol = UserRole + 2,
|
||||||
Value = UserRole + 3,
|
Value = UserRole + 3,
|
||||||
FiatValue = UserRole + 4
|
FiatValue = UserRole + 4
|
||||||
|
Address = UserRole + 5
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
type AssetList* = ref object of QAbstractListModel
|
type AssetList* = ref object of QAbstractListModel
|
||||||
|
@ -32,6 +33,7 @@ QtObject:
|
||||||
of "symbol": result = asset.symbol
|
of "symbol": result = asset.symbol
|
||||||
of "value": result = asset.value
|
of "value": result = asset.value
|
||||||
of "fiatValue": result = asset.fiatValue
|
of "fiatValue": result = asset.fiatValue
|
||||||
|
of "address": result = asset.address
|
||||||
|
|
||||||
method rowCount(self: AssetList, index: QModelIndex = nil): int =
|
method rowCount(self: AssetList, index: QModelIndex = nil): int =
|
||||||
return self.assets.len
|
return self.assets.len
|
||||||
|
@ -48,12 +50,14 @@ QtObject:
|
||||||
of AssetRoles.Symbol: result = newQVariant(asset.symbol)
|
of AssetRoles.Symbol: result = newQVariant(asset.symbol)
|
||||||
of AssetRoles.Value: result = newQVariant(asset.value)
|
of AssetRoles.Value: result = newQVariant(asset.value)
|
||||||
of AssetRoles.FiatValue: result = newQVariant(asset.fiatValue)
|
of AssetRoles.FiatValue: result = newQVariant(asset.fiatValue)
|
||||||
|
of AssetRoles.Address: result = newQVariant(asset.address)
|
||||||
|
|
||||||
method roleNames(self: AssetList): Table[int, string] =
|
method roleNames(self: AssetList): Table[int, string] =
|
||||||
{ AssetRoles.Name.int:"name",
|
{ AssetRoles.Name.int:"name",
|
||||||
AssetRoles.Symbol.int:"symbol",
|
AssetRoles.Symbol.int:"symbol",
|
||||||
AssetRoles.Value.int:"value",
|
AssetRoles.Value.int:"value",
|
||||||
AssetRoles.FiatValue.int:"fiatValue" }.toTable
|
AssetRoles.FiatValue.int:"fiatValue",
|
||||||
|
AssetRoles.Address.int:"address" }.toTable
|
||||||
|
|
||||||
proc addAssetToList*(self: AssetList, asset: Asset) =
|
proc addAssetToList*(self: AssetList, asset: Asset) =
|
||||||
self.beginInsertRows(newQModelIndex(), self.assets.len, self.assets.len)
|
self.beginInsertRows(newQModelIndex(), self.assets.len, self.assets.len)
|
||||||
|
|
|
@ -5,6 +5,8 @@ const SEED* = "seed"
|
||||||
const KEY* = "key"
|
const KEY* = "key"
|
||||||
const WATCH* = "watch"
|
const WATCH* = "watch"
|
||||||
|
|
||||||
|
const ZERO_ADDRESS* = "0x0000000000000000000000000000000000000000"
|
||||||
|
|
||||||
const PATH_WALLET_ROOT* = "m/44'/60'/0'/0"
|
const PATH_WALLET_ROOT* = "m/44'/60'/0'/0"
|
||||||
# EIP1581 Root Key, the extended key from which any whisper key/encryption key can be derived
|
# EIP1581 Root Key, the extended key from which any whisper key/encryption key can be derived
|
||||||
const PATH_EIP_1581* = "m/43'/60'/1581'"
|
const PATH_EIP_1581* = "m/43'/60'/1581'"
|
||||||
|
|
|
@ -7,10 +7,10 @@ type
|
||||||
Mainnet,
|
Mainnet,
|
||||||
Testnet
|
Testnet
|
||||||
|
|
||||||
type Method = object
|
type Method* = object
|
||||||
name: string
|
name*: string
|
||||||
signature: string
|
signature*: string
|
||||||
noPadding: bool
|
noPadding*: bool
|
||||||
|
|
||||||
type Contract* = ref object
|
type Contract* = ref object
|
||||||
name*: string
|
name*: string
|
||||||
|
@ -21,7 +21,8 @@ type Contract* = ref object
|
||||||
let CONTRACTS: seq[Contract] = @[
|
let CONTRACTS: seq[Contract] = @[
|
||||||
Contract(name: "snt", network: Network.Mainnet, address: parseAddress("0x744d70fdbe2ba4cf95131626614a1763df805b9e"),
|
Contract(name: "snt", network: Network.Mainnet, address: parseAddress("0x744d70fdbe2ba4cf95131626614a1763df805b9e"),
|
||||||
methods: [
|
methods: [
|
||||||
("approveAndCall", Method(signature: "approveAndCall(address,uint256,bytes)"))
|
("approveAndCall", Method(signature: "approveAndCall(address,uint256,bytes)")),
|
||||||
|
("transfer", Method(signature: "transfer(address,uint256)"))
|
||||||
].toTable
|
].toTable
|
||||||
),
|
),
|
||||||
Contract(name: "snt", network: Network.Testnet, address: parseAddress("0xc55cf4b03948d7ebc8b9e8bad92643703811d162")),
|
Contract(name: "snt", network: Network.Testnet, address: parseAddress("0xc55cf4b03948d7ebc8b9e8bad92643703811d162")),
|
||||||
|
@ -77,6 +78,8 @@ proc encodeParam[T](value: T): string =
|
||||||
result = toHex(value, 64)
|
result = toHex(value, 64)
|
||||||
elif T is EthAddress:
|
elif T is EthAddress:
|
||||||
result = value.toHex()
|
result = value.toHex()
|
||||||
|
else:
|
||||||
|
result = align(value, 64, '0')
|
||||||
|
|
||||||
macro encodeAbi*(self: Method, params: varargs[untyped]): untyped =
|
macro encodeAbi*(self: Method, params: varargs[untyped]): untyped =
|
||||||
result = quote do:
|
result = quote do:
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import json, json, strformat, stint, strutils, chronicles
|
import json, httpclient, json, strformat, stint, strutils, sequtils, chronicles, parseutils, tables
|
||||||
import libstatus, core, types
|
import libstatus, core, types
|
||||||
import ../wallet/account
|
import ../wallet/account
|
||||||
|
from ./accounts/constants import ZERO_ADDRESS
|
||||||
|
import ./contracts as contractMethods
|
||||||
|
from eth/common/utils import parseAddress
|
||||||
|
|
||||||
proc getWalletAccounts*(): seq[WalletAccount] =
|
proc getWalletAccounts*(): seq[WalletAccount] =
|
||||||
try:
|
try:
|
||||||
|
@ -26,17 +29,17 @@ 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] =
|
proc getTransfersByAddress*(address: string): seq[types.Transaction] =
|
||||||
try:
|
try:
|
||||||
let response = getBlockByNumber("latest")
|
let response = getBlockByNumber("latest")
|
||||||
let latestBlock = parseJson(response)["result"]
|
let latestBlock = parseJson(response)["result"]
|
||||||
|
|
||||||
let transactionsResponse = getTransfersByAddress(address, latestBlock["number"].getStr, "0x14")
|
let transactionsResponse = getTransfersByAddress(address, latestBlock["number"].getStr, "0x14")
|
||||||
let transactions = parseJson(transactionsResponse)["result"]
|
let transactions = parseJson(transactionsResponse)["result"]
|
||||||
var accountTransactions: seq[Transaction] = @[]
|
var accountTransactions: seq[types.Transaction] = @[]
|
||||||
|
|
||||||
for transaction in transactions:
|
for transaction in transactions:
|
||||||
accountTransactions.add(Transaction(
|
accountTransactions.add(types.Transaction(
|
||||||
typeValue: transaction["type"].getStr,
|
typeValue: transaction["type"].getStr,
|
||||||
address: transaction["address"].getStr,
|
address: transaction["address"].getStr,
|
||||||
contract: transaction["contract"].getStr,
|
contract: transaction["contract"].getStr,
|
||||||
|
@ -58,14 +61,42 @@ proc getTransfersByAddress*(address: string): seq[Transaction] =
|
||||||
error "Failed getting wallet account transactions", msg
|
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, assetAddress: string, value: string, password: string): string =
|
||||||
var args = %* {
|
try:
|
||||||
"value": fmt"0x{toHex(value)}",
|
var args: JsonNode
|
||||||
"from": from_address,
|
if (assetAddress == ZERO_ADDRESS or assetAddress == ""):
|
||||||
"to": to
|
var weiValue = value.parseFloat() * float(1000000000000000000)
|
||||||
}
|
var stringValue = fmt"{weiValue:<.0f}"
|
||||||
var response = sendTransaction($args, password)
|
stringValue.removeSuffix('.')
|
||||||
result = response
|
var hexValue = parseBiggestInt(stringValue).toHex()
|
||||||
|
hexValue.removePrefix('0')
|
||||||
|
args = %* {
|
||||||
|
"value": fmt"0x{hexValue}",
|
||||||
|
"from": from_address,
|
||||||
|
"to": to
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
var bigIntValue = u256(value)
|
||||||
|
# TODO get decimals from the token
|
||||||
|
bigIntValue = bigIntValue * u256(1000000000000000000)
|
||||||
|
# Just using mainnet SNT to get the method ABI
|
||||||
|
let contract = getContract(Network.Mainnet, "snt")
|
||||||
|
let transferEncoded = contract.methods["transfer"].encodeAbi(parseAddress(to), bigIntValue.toHex())
|
||||||
|
|
||||||
|
args = %* {
|
||||||
|
"from": from_address,
|
||||||
|
"to": assetAddress,
|
||||||
|
"data": transferEncoded
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = sendTransaction($args, password)
|
||||||
|
let parsedResponse = parseJson(response)
|
||||||
|
|
||||||
|
result = parsedResponse["result"].getStr
|
||||||
|
trace "Transaction sent succesfully", hash=result
|
||||||
|
except Exception as e:
|
||||||
|
error "Error submitting transaction", msg=e.msg
|
||||||
|
result = e.msg
|
||||||
|
|
||||||
proc getBalance*(address: string): string =
|
proc getBalance*(address: string): string =
|
||||||
let payload = %* [address, "latest"]
|
let payload = %* [address, "latest"]
|
||||||
|
|
|
@ -44,8 +44,8 @@ proc initEvents*(self: WalletModel) =
|
||||||
proc delete*(self: WalletModel) =
|
proc delete*(self: WalletModel) =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
proc sendTransaction*(self: WalletModel, from_value: string, to: string, value: string, password: string): string =
|
proc sendTransaction*(self: WalletModel, from_value: string, to: string, assetAddress: string, value: string, password: string): string =
|
||||||
status_wallet.sendTransaction(from_value, to, value, password)
|
status_wallet.sendTransaction(from_value, to, assetAddress, value, password)
|
||||||
|
|
||||||
proc getDefaultCurrency*(self: WalletModel): string =
|
proc getDefaultCurrency*(self: WalletModel): string =
|
||||||
# TODO: this should come from a model? It is going to be used too in the
|
# TODO: this should come from a model? It is going to be used too in the
|
||||||
|
|
|
@ -15,7 +15,6 @@ ModalPopup {
|
||||||
onOpened: {
|
onOpened: {
|
||||||
sendModalContent.amountInput.text = ""
|
sendModalContent.amountInput.text = ""
|
||||||
sendModalContent.amountInput.forceActiveFocus(Qt.MouseFocusReason)
|
sendModalContent.amountInput.forceActiveFocus(Qt.MouseFocusReason)
|
||||||
sendModalContent.defaultAccount = walletModel.getDefaultAccount()
|
|
||||||
const accounts = walletModel.accounts
|
const accounts = walletModel.accounts
|
||||||
const numAccounts = accounts.rowCount()
|
const numAccounts = accounts.rowCount()
|
||||||
const accountsData = []
|
const accountsData = []
|
||||||
|
@ -35,7 +34,8 @@ ModalPopup {
|
||||||
assetsData.push({
|
assetsData.push({
|
||||||
name: assets.rowData(f, 'name'),
|
name: assets.rowData(f, 'name'),
|
||||||
symbol: assets.rowData(f, 'symbol'),
|
symbol: assets.rowData(f, 'symbol'),
|
||||||
value: assets.rowData(f, 'value')
|
value: assets.rowData(f, 'value'),
|
||||||
|
address: assets.rowData(f, 'address')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
sendModalContent.assets = assetsData
|
sendModalContent.assets = assetsData
|
||||||
|
|
|
@ -7,7 +7,7 @@ Item {
|
||||||
property alias amountInput: txtAmount
|
property alias amountInput: txtAmount
|
||||||
property var accounts: []
|
property var accounts: []
|
||||||
property var assets: []
|
property var assets: []
|
||||||
property string defaultAccount: "0x1234"
|
property string defaultAccount: "0x8558BFe81d00333379Af1Cd4c07F3dc50081FEC4"
|
||||||
|
|
||||||
property int selectedAccountIndex: 0
|
property int selectedAccountIndex: 0
|
||||||
property string selectedAccountAddress: accounts && accounts.length ? accounts[selectedAccountIndex].address : ""
|
property string selectedAccountAddress: accounts && accounts.length ? accounts[selectedAccountIndex].address : ""
|
||||||
|
@ -16,6 +16,7 @@ Item {
|
||||||
|
|
||||||
property int selectedAssetIndex: 0
|
property int selectedAssetIndex: 0
|
||||||
property string selectedAssetName: assets && assets.length ? assets[selectedAssetIndex].name : ""
|
property string selectedAssetName: assets && assets.length ? assets[selectedAssetIndex].name : ""
|
||||||
|
property string selectedAssetAddress: assets && assets.length ? assets[selectedAssetIndex].address : ""
|
||||||
property string selectedAssetSymbol: assets && assets.length ? assets[selectedAssetIndex].symbol : ""
|
property string selectedAssetSymbol: assets && assets.length ? assets[selectedAssetIndex].symbol : ""
|
||||||
property string selectedAccountValue: assets && assets.length ? assets[selectedAssetIndex].value : ""
|
property string selectedAccountValue: assets && assets.length ? assets[selectedAssetIndex].value : ""
|
||||||
|
|
||||||
|
@ -27,12 +28,22 @@ Item {
|
||||||
if (!validate()) {
|
if (!validate()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Convert to Wei
|
||||||
|
// TODO use the decimal value fo the token, it's not always 18
|
||||||
|
// TODO add big number support
|
||||||
|
// const weiValue = parseFloat(txtAmount.text, 10) * 1000000000000000000
|
||||||
|
|
||||||
|
console.log('SENDING', selectedAccountAddress,
|
||||||
|
txtTo.text,
|
||||||
|
selectedAssetAddress,
|
||||||
|
txtAmount.text,
|
||||||
|
txtPassword.text)
|
||||||
let result = walletModel.onSendTransaction(selectedAccountAddress,
|
let result = walletModel.onSendTransaction(selectedAccountAddress,
|
||||||
txtTo.text,
|
txtTo.text,
|
||||||
|
selectedAssetAddress,
|
||||||
txtAmount.text,
|
txtAmount.text,
|
||||||
txtPassword.text)
|
txtPassword.text)
|
||||||
console.log(result)
|
console.log('hash', result)
|
||||||
}
|
}
|
||||||
|
|
||||||
function validate() {
|
function validate() {
|
||||||
|
@ -56,7 +67,7 @@ Item {
|
||||||
amountValidationError = qsTr("You need to enter an amount")
|
amountValidationError = qsTr("You need to enter an amount")
|
||||||
} else if (isNaN(txtAmount.text)) {
|
} else if (isNaN(txtAmount.text)) {
|
||||||
amountValidationError = qsTr("This needs to be a number")
|
amountValidationError = qsTr("This needs to be a number")
|
||||||
} else if (parseInt(txtAmount.text, 10) > parseInt(selectedAccountValue, 10)) {
|
} else if (parseFloat(txtAmount.text) > parseFloat(selectedAccountValue)) {
|
||||||
amountValidationError = qsTr("Amount needs to be lower than your balance (%1)").arg(selectedAccountValue)
|
amountValidationError = qsTr("Amount needs to be lower than your balance (%1)").arg(selectedAccountValue)
|
||||||
} else {
|
} else {
|
||||||
amountValidationError = ""
|
amountValidationError = ""
|
||||||
|
|
Loading…
Reference in New Issue