feat: make token send and eth send work

This commit is contained in:
Jonathan Rainville 2020-07-01 10:04:45 -04:00 committed by Iuri Matias
parent 19f8f8e457
commit 81e7dffaa2
8 changed files with 78 additions and 27 deletions

View File

@ -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

View File

@ -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)

View File

@ -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'"

View File

@ -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:

View File

@ -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"]

View File

@ -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

View File

@ -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

View File

@ -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 = ""