diff --git a/imports/startup/client/functions.js b/imports/startup/client/functions.js
index d9feb76c..aee605f8 100644
--- a/imports/startup/client/functions.js
+++ b/imports/startup/client/functions.js
@@ -1,9 +1,11 @@
/* eslint no-console:0 */
/* eslint no-global-assign: 0 */
+/* eslint max-len: 0 */
+/* eslint no-unused-vars: 0 */
/* global QRLLIB, XMSS_OBJECT, LocalStore, QrlLedger, isElectrified, selectedNetwork,loadAddressTransactions, getTokenBalances, updateBalanceField, refreshTransferPage */
/* global pkRawToB32Address, hexOrB32, rawToHexOrB32, anyAddressToRawAddress, stringToBytes, binaryToBytes, bytesToString, bytesToHex, hexToBytes, toBigendianUint64BytesUnsigned, numberToString, decimalToBinary */
/* global getMnemonicOfFirstAddress, getXMSSDetails, isWalletFileDeprecated, waitForQRLLIB, addressForAPI, binaryToQrlAddress, toUint8Vector, concatenateTypedArrays, getQrlProtoShasum */
-/* global resetWalletStatus, passwordPolicyValid, countDecimals, supportedBrowser, wrapMeteorCall, getBalance, otsIndexUsed, ledgerHasNoTokenSupport, resetLocalStorageState, nodeReturnedValidResponse */
+/* global resetWalletStatus, passwordPolicyValid, countDecimals, supportedBrowser, wrapMeteorCall, getBalance, otsIndexUsed, ledgerHasNoTokenSupport, resetLocalStorageState, nodeReturnedValidResponse, TransportStatusError */
/* global POLL_TXN_RATE, POLL_MAX_CHECKS, DEFAULT_NETWORKS, findNetworkData, SHOR_PER_QUANTA, WALLET_VERSION, QRLPROTO_SHA256, */
import aes256 from 'aes256'
@@ -12,41 +14,41 @@ import helpers from '@theqrl/explorer-helpers'
import 'babel-polyfill'
import Qrl from '@theqrl/hw-app-qrl'
-import TransportWebUSB from "@ledgerhq/hw-transport-webusb";
+import TransportWebUSB from '@ledgerhq/hw-transport-webusb'
bech32 = require('bech32') // eslint-disable-line
export function ledgerReturnedError(e) {
- let r = false;
+ let r = false
try {
if (e instanceof DOMException) {
// DOMException will be thrown if WebUSB device is unplugged during Ledger UI event
- r = true;
+ r = true
}
- } catch (e) {
- r = false;
+ } catch (err) {
+ r = false
}
try {
if (e.name === 'TransportStatusError' || e instanceof TransportStatusError || e.name === 'TransportOpenUserCancelled') {
- r = true;
+ r = true
}
- } catch (e) {
- r = false;
+ } catch (err) {
+ r = false
}
- return r;
+ return r
}
export async function createTransport() {
- var transport = null;
- transport = await TransportWebUSB.create();
- console.log('USING WEBUSB');
- var qrl = await new Qrl(transport);
+ let transport = null
+ transport = await TransportWebUSB.create()
+ console.log('USING WEBUSB')
+ const qrl = await new Qrl(transport)
return qrl
}
// Client side function to detmine if running within Electron
-export function isElectrified () {
+export function isElectrified() {
const userAgent = navigator.userAgent.toLowerCase()
if (userAgent.indexOf(' electron/') > -1) {
return true
@@ -483,7 +485,7 @@ getBalance = (getAddress, callBack) => {
// prefer to rely on state tracked in ledger device
console.log('-- Getting QRL Ledger Nano App State --')
if (isElectrified()) {
- Meteor.call('ledgerGetState', [], (err, data) => {
+ Meteor.call('ledgerGetState', [], (gsErr, data) => {
console.log('> Got Ledger Nano State from USB')
Session.set('otsKeyEstimate', data.xmss_index)
// Get remaining OTS Keys
@@ -541,14 +543,49 @@ loadAddressTransactions = (a, p) => {
Session.set('loadingTransactions', true)
wrapMeteorCall('getTransactionsByAddress', request, (err, res) => {
- // console.log('err:', err)
+ if (err) { console.log('err:', err) }
// console.log('res:', res)
if (err) {
Session.set('addressTransactions', { error: err })
Session.set('errorLoadingTransactions', true)
} else {
Session.set('active', p)
- Session.set('addressTransactions', res.transactions_detail)
+
+ const transactions = []
+ const thisAddress = a
+ _.each(res.transactions_detail, (transaction) => {
+ const y = transaction
+ // Update timestamp from unix epoch to human readable time/date.
+ if (moment.unix(transaction.timestamp).isValid()) {
+ y.timestamp = moment.unix(transaction.timestamp).format('HH:mm D MMM YYYY')
+ } else {
+ y.timestamp = 'Unconfirmed Tx'
+ }
+ // Set total received amount if sent to this address
+ let thisReceivedAmount = 0
+ let totalSent = 0
+ if (y.tx.transactionType === 'transfer') {
+ _.each(y.tx.transfer.addrs_to, (output, index) => {
+ totalSent += parseFloat(y.tx.transfer.amounts[index] / SHOR_PER_QUANTA)
+ if (output === thisAddress) {
+ thisReceivedAmount += parseFloat(y.tx.transfer.amounts[index] / SHOR_PER_QUANTA)
+ }
+ })
+ }
+ if (y.tx.transactionType === 'transfer_token') {
+ // FIXME: sort token decimals here
+ _.each(y.tx.transfer_token.addrs_to, (output, index) => {
+ totalSent += parseFloat(y.tx.transfer_token.amounts[index])
+ if (output === thisAddress) {
+ thisReceivedAmount += parseFloat(y.tx.transfer_token.amounts[index])
+ }
+ })
+ }
+ y.thisReceivedAmount = numberToString(thisReceivedAmount)
+ y.totalTransferred = totalSent
+ transactions.push(y)
+ Session.set('addressTransactions', transactions)
+ })
Session.set('loadingTransactions', false)
Session.set('errorLoadingTransactions', false)
$('#noTransactionsFound').show()
@@ -556,72 +593,58 @@ loadAddressTransactions = (a, p) => {
})
}
-getTokenBalances = (getAddress, callback) => {
+const getTokenBalances = (getAddress, callback) => {
const request = {
- address: addressForAPI(getAddress),
+ address: Buffer.from(getAddress.substring(1), 'hex'),
network: selectedNetwork(),
}
-
- wrapMeteorCall('getAddressState', request, (err, res) => {
+ const tokensHeld = []
+ Meteor.call('getFullAddressState', request, (err, res) => {
if (err) {
- console.log('err: ', err)
- Session.set('transferFromBalance', 0)
- Session.set('transferFromTokenState', [])
- Session.set('address', 'Error')
- Session.set('otsKeyEstimate', 0)
- Session.set('otsKeysRemaining', 0)
+ // TODO - Error handling
} else {
- if (res.state.address !== '') { // eslint-disable-line
- const tokensHeld = []
-
- // Now for each res.state.token we find, go discover token name and symbol
- for (let i in res.state.tokens) { // eslint-disable-line
- const tokenHash = i
- const tokenBalance = res.state.tokens[i]
+ // Now for each res.state.token we find, go discover token name and symbol
+ // eslint-disable-next-line
+ if (res.state.address !== '') {
+ Object.keys(res.state.tokens).forEach((key) => {
+ const tokenHash = key
+ const tokenBalance = res.state.tokens[key]
const thisToken = {}
- const txnRequest = {
- query: tokenHash,
+ const req = {
+ query: Buffer.from(tokenHash, 'hex'),
network: selectedNetwork(),
}
- wrapMeteorCall('getTxnHash', txnRequest, (err, res) => { // eslint-disable-line
+ Meteor.call('getObject', req, (objErr, objRes) => {
if (err) {
- console.log('err:', err)
- Session.set('tokensHeld', [])
+ // TODO - Error handling here
+ console.log('err:', objErr)
} else {
// Check if this is a token hash.
- if (res.transaction.tx.transactionType !== 'token') { // eslint-disable-line
- console.log('err: ', err)
- Session.set('tokensHeld', [])
+ // eslint-disable-next-line
+ if (objRes.transaction.tx.transactionType !== 'token') {
+ // TODO - Error handling here
} else {
- const tokenDetails = res.transaction.tx.token
+ const tokenDetails = objRes.transaction.tx.token
thisToken.hash = tokenHash
thisToken.name = bytesToString(tokenDetails.name)
- thisToken.symbol = bytesToString(tokenDetails.symbol)
- thisToken.balance = tokenBalance / Math.pow(10, tokenDetails.decimals) // eslint-disable-line
+ thisToken.symbol = bytesToString(tokenDetails.symbol) // eslint-disable-next-line
+ thisToken.balance = tokenBalance / Math.pow(10, tokenDetails.decimals)
thisToken.decimals = tokenDetails.decimals
-
tokensHeld.push(thisToken)
Session.set('tokensHeld', tokensHeld)
}
}
})
- }
- callback()
-
- // When done hide loading section
- Session.set('errorLoadingTransactions', false)
- $('#loading').hide()
- } else {
- // Wallet not found, put together an empty response
- callback()
+ })
}
}
})
+ $('#tokenBalancesLoading').hide()
}
updateBalanceField = () => {
@@ -632,7 +655,9 @@ updateBalanceField = () => {
if (selectedType === 'quanta') {
Session.set('balanceAmount', Session.get('transferFromBalance'))
Session.set('balanceSymbol', 'Quanta')
+ $('#showMessageField').show()
} else {
+ $('#showMessageField').hide()
// First extract the token Hash
const tokenHash = selectedType.split('-')[1]
@@ -658,7 +683,16 @@ refreshTransferPage = (callback) => {
waitForQRLLIB(function () {
// Set transfer from address
Session.set('transferFromAddress', getXMSSDetails().address)
+ // Get Tokens and Balances
+ getTokenBalances(getXMSSDetails().address, function () {
+ // Update balance field
+ updateBalanceField()
+
+ $('#tokenBalancesLoading').hide()
+ // Render dropdown
+ $('.ui.dropdown').dropdown()
+ })
// Get address balance
getBalance(getXMSSDetails().address, function () {
// Load Wallet Transactions
@@ -678,17 +712,6 @@ refreshTransferPage = (callback) => {
loadAddressTransactions(getXMSSDetails().address, 1)
callback()
})
-
- // Get Tokens and Balances
- getTokenBalances(getXMSSDetails().address, function () {
- // Update balance field
- updateBalanceField()
-
- $('#tokenBalancesLoading').hide()
-
- // Render dropdown
- $('.ui.dropdown').dropdown()
- })
})
}
diff --git a/imports/startup/server/index.js b/imports/startup/server/index.js
index 20567480..4dc9e1cf 100644
--- a/imports/startup/server/index.js
+++ b/imports/startup/server/index.js
@@ -347,6 +347,23 @@ const getStats = (request, callback) => {
}
}
+const getObject = (request, callback) => {
+ try {
+ qrlApi('GetObject', request, (error, response) => {
+ if (error) {
+ const myError = errorCallback(error, 'Cannot access API/GetObject', '**ERROR/GetObject**')
+ callback(myError, null)
+ } else {
+ // console.log(response)
+ callback(null, response)
+ }
+ })
+ } catch (error) {
+ const myError = errorCallback(error, 'Cannot access API/GetObject', '**ERROR/GetObject**')
+ callback(myError, null)
+ }
+}
+
const helpersaddressTransactions = (response) => {
const output = []
console.log(response)
@@ -355,11 +372,23 @@ const helpersaddressTransactions = (response) => {
if (tx.tx.transfer) {
const hexlified = []
_.each(tx.tx.transfer.addrs_to, (txOutput) => {
- console.log('formatting: ', txOutput)
hexlified.push(`Q${Buffer.from(txOutput).toString('hex')}`)
})
txEdited.tx.transfer.addrs_to = hexlified
}
+ if (tx.tx.token) {
+ txEdited.tx.token.name = Buffer.from(tx.tx.token.name).toString()
+ txEdited.tx.token.symbol = Buffer.from(tx.tx.token.symbol).toString()
+ txEdited.tx.token.owner = `Q${Buffer.from(tx.tx.token.owner).toString('hex')}`
+ }
+ if (tx.tx.transfer_token) {
+ const hexlified = []
+ txEdited.tx.transfer_token.token_txhash = Buffer.from(tx.tx.transfer_token.token_txhash).toString('hex')
+ _.each(tx.tx.transfer_token.addrs_to, (txOutput) => {
+ hexlified.push(`Q${Buffer.from(txOutput).toString('hex')}`)
+ })
+ txEdited.tx.transfer_token.addrs_to = hexlified
+ }
if (tx.tx.coinbase) {
if (tx.tx.coinbase.addr_to) {
txEdited.tx.coinbase.addr_to = `Q${Buffer.from(txEdited.tx.coinbase.addr_to).toString('hex')}`
@@ -403,6 +432,23 @@ const getTransactionsByAddress = (request, callback) => {
}
}
+const getTokensByAddress = (request, callback) => {
+ try {
+ qrlApi('GetTokensByAddress', request, (error, response) => {
+ if (error) {
+ const myError = errorCallback(error, 'Cannot access API/GetTokensByAddress', '**ERROR/GetTokensByAddress**')
+ callback(myError, null)
+ } else {
+ // console.log(response)
+ callback(null, response)
+ }
+ })
+ } catch (error) {
+ const myError = errorCallback(error, 'Cannot access API/GetTokensByAddress', '**ERROR/GetTokensByAddress**')
+ callback(myError, null)
+ }
+}
+
const getMultiSigAddressesByAddress = (request, callback) => {
try {
qrlApi('GetMultiSigAddressesByAddress', request, (error, response) => {
@@ -451,6 +497,26 @@ const getOTS = (request, callback) => {
}
}
+const getFullAddressState = (request, callback) => {
+ try {
+ qrlApi('GetAddressState', request, (error, response) => {
+ if (error) {
+ const myError = errorCallback(error, 'Cannot access API/GetOptimizedAddressState', '**ERROR/getAddressState** ')
+ callback(myError, null)
+ } else {
+ if (response.state.address) {
+ response.state.address = `Q${Buffer.from(response.state.address).toString('hex')}`
+ }
+
+ callback(null, response)
+ }
+ })
+ } catch (error) {
+ const myError = errorCallback(error, 'Cannot access API/GetAddressState', '**ERROR/GetAddressState**')
+ callback(myError, null)
+ }
+}
+
// Function to call getAddressState API
const getAddressState = (request, callback) => {
try {
@@ -518,7 +584,7 @@ const getAddressState = (request, callback) => {
if (response.state.address) {
response.state.address = `Q${Buffer.from(response.state.address).toString('hex')}`
}
-
+ console.table(response)
callback(null, response)
}
})
@@ -1700,12 +1766,24 @@ Meteor.methods({
const response = Meteor.wrapAsync(getHeight)(request)
return response
},
+ getObject(request) {
+ check(request, Object)
+ this.unblock()
+ const response = Meteor.wrapAsync(getObject)(request)
+ return response
+ },
getAddressState(request) {
this.unblock()
check(request, Object)
const response = Meteor.wrapAsync(getAddressState)(request)
return response
},
+ getFullAddressState(request) {
+ check(request, Object)
+ this.unblock()
+ const response = Meteor.wrapAsync(getFullAddressState)(request)
+ return response
+ },
getMultiSigAddressState(request) {
this.unblock()
check(request, Object)
@@ -1718,6 +1796,12 @@ Meteor.methods({
const response = Meteor.wrapAsync(getTransactionsByAddress)(request)
return helpersaddressTransactions(response)
},
+ getTokensByAddress(request) {
+ check(request, Object)
+ this.unblock()
+ const response = Meteor.wrapAsync(getTokensByAddress)(request)
+ return response
+ },
getMultiSigAddressesByAddress(request) {
check(request, Object)
this.unblock()
diff --git a/imports/ui/layouts/body/body.js b/imports/ui/layouts/body/body.js
index fc9587c3..bf1ccc08 100644
--- a/imports/ui/layouts/body/body.js
+++ b/imports/ui/layouts/body/body.js
@@ -298,7 +298,10 @@ Template.appBody.helpers({
return false
},
balanceAmount() {
- return Session.get('balanceAmount')
+ if (Session.get('balanceAmount')) {
+ return Session.get('balanceAmount')
+ }
+ return Session.get('transferFromBalance')
},
otsKeysRemaining() {
return Session.get('otsKeysRemaining')
diff --git a/imports/ui/pages/transfer/transfer.html b/imports/ui/pages/transfer/transfer.html
index ffa8a9a8..9940b6c0 100644
--- a/imports/ui/pages/transfer/transfer.html
+++ b/imports/ui/pages/transfer/transfer.html
@@ -903,7 +903,7 @@