+ initial import
This commit is contained in:
183
renderer/blockchain.js
Normal file
183
renderer/blockchain.js
Normal file
@@ -0,0 +1,183 @@
|
||||
// In renderer process (web page).
|
||||
const {ipcRenderer} = require('electron');
|
||||
|
||||
class Blockchain {
|
||||
constructor() {}
|
||||
|
||||
getBlock(blockToGet, includeData, clbError, clbSuccess) {
|
||||
web3Local.eth.getBlock(blockToGet, includeData, function(error, block) {
|
||||
if (error) {
|
||||
clbError(error);
|
||||
} else {
|
||||
clbSuccess(block);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getAccounts(clbError, clbSuccess) {
|
||||
web3Local.eth.getAccounts(function(err, res) {
|
||||
if (err) {
|
||||
clbError(err);
|
||||
} else {
|
||||
clbSuccess(res);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
isAddress(address) {
|
||||
return web3Local.utils.isAddress(address);
|
||||
}
|
||||
|
||||
getTranasctionFee(fromAddress, toAddress, value, clbError, clbSuccess) {
|
||||
web3Local.eth.getTransactionCount(fromAddress, function( error, result ) {
|
||||
if (error) {
|
||||
clbError(error);
|
||||
} else {
|
||||
var amountToSend = web3Local.utils.toWei(value, "ether"); //convert to wei value
|
||||
var RawTransaction = {
|
||||
from: fromAddress,
|
||||
to: toAddress,
|
||||
value: amountToSend,
|
||||
nonce: result
|
||||
};
|
||||
|
||||
web3Local.eth.estimateGas(RawTransaction, function( error, result ) {
|
||||
if (error) {
|
||||
clbError(error);
|
||||
} else {
|
||||
var usedGas = result;
|
||||
web3Local.eth.getGasPrice(function( error, result ) {
|
||||
if (error) {
|
||||
clbError(error);
|
||||
} else {
|
||||
clbSuccess(result * usedGas);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
prepareTransaction(password, fromAddress, toAddress, value, clbError, clbSuccess) {
|
||||
web3Local.eth.personal.unlockAccount(fromAddress, password, function( error, result ) {
|
||||
if (error) {
|
||||
clbError("Wrong password for the selected address!");
|
||||
} else
|
||||
{
|
||||
web3Local.eth.getTransactionCount(fromAddress, function( error, result ) {
|
||||
if (error) {
|
||||
clbError(error);
|
||||
} else {
|
||||
var amountToSend = web3Local.utils.toWei(value, "ether"); //convert to wei value
|
||||
var RawTransaction = {
|
||||
from: fromAddress,
|
||||
to: toAddress,
|
||||
value: amountToSend,
|
||||
nonce: result
|
||||
};
|
||||
|
||||
web3Local.eth.estimateGas(RawTransaction, function( error, result ) {
|
||||
if (error) {
|
||||
clbError(error);
|
||||
} else {
|
||||
RawTransaction.gas = result;
|
||||
web3Local.eth.getGasPrice(function( error, result ) {
|
||||
if (error) {
|
||||
clbError(error);
|
||||
} else {
|
||||
RawTransaction.gasPrice = result;
|
||||
web3Local.eth.signTransaction(RawTransaction, fromAddress, function( error, result ) {
|
||||
if (error) {
|
||||
clbError(error);
|
||||
} else {
|
||||
clbSuccess(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
sendTransaction(rawTransaction, clbError, clbSuccess) {
|
||||
web3Local.eth.sendSignedTransaction(rawTransaction, function( error, result ) {
|
||||
if (error) {
|
||||
clbError(error);
|
||||
} else {
|
||||
clbSuccess(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getAccountsData(clbError, clbSuccess) {
|
||||
var rendererData = {};
|
||||
rendererData.sumBalance = 0;
|
||||
rendererData.addressData = [];
|
||||
|
||||
var wallets = ipcRenderer.sendSync('getJSONFile', 'wallets.json');
|
||||
var counter = 0;
|
||||
|
||||
web3Local.eth.getAccounts(function(err, res) {
|
||||
if (err) {
|
||||
clbError(err);
|
||||
} else {
|
||||
for (var i = 0; i < res.length; i++) {
|
||||
var walletName = vsprintf("Account %d", [i + 1]);
|
||||
if (wallets) {
|
||||
walletName = wallets.names[res[i]] || walletName;
|
||||
}
|
||||
|
||||
var addressInfo = {};
|
||||
addressInfo.balance = 0;
|
||||
addressInfo.address = res[i];
|
||||
addressInfo.name = walletName;
|
||||
rendererData.addressData.push(addressInfo);
|
||||
}
|
||||
|
||||
if (rendererData.addressData.length > 0) {
|
||||
updateBalance(counter);
|
||||
} else {
|
||||
clbSuccess(rendererData);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function updateBalance(index)
|
||||
{
|
||||
web3Local.eth.getBalance(rendererData.addressData[index].address, function(error, balance) {
|
||||
rendererData.addressData[index].balance = parseFloat(web3Local.utils.fromWei(balance, 'ether')).toFixed(2);
|
||||
rendererData.sumBalance = rendererData.sumBalance + parseFloat(web3Local.utils.fromWei(balance, 'ether'));
|
||||
|
||||
if (counter < rendererData.addressData.length - 1) {
|
||||
counter++;
|
||||
updateBalance(counter);
|
||||
} else {
|
||||
rendererData.sumBalance = parseFloat(rendererData.sumBalance).toFixed(2);
|
||||
clbSuccess(rendererData);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
createNewAccount(password, clbError, clbSuccess) {
|
||||
web3Local.eth.personal.newAccount(password, function(error, account) {
|
||||
if (error) {
|
||||
clbError(error);
|
||||
} else {
|
||||
clbSuccess(account);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
closeConnection() {
|
||||
web3Local.currentProvider.connection.close();
|
||||
}
|
||||
}
|
||||
|
||||
// create new blockchain variable
|
||||
EthoBlockchain = new Blockchain();
|
||||
74
renderer/maingui.js
Normal file
74
renderer/maingui.js
Normal file
@@ -0,0 +1,74 @@
|
||||
// In renderer process (web page).
|
||||
const {ipcRenderer} = require('electron');
|
||||
|
||||
class MainGUI {
|
||||
constructor() {
|
||||
this.appState = "account";
|
||||
}
|
||||
|
||||
changeAppState(newState) {
|
||||
this.appState = newState;
|
||||
$(".sidebarIconWrapper").removeClass("iconSelected");
|
||||
|
||||
switch(this.appState) {
|
||||
case "account":
|
||||
$("#mainNavBtnWalletsWrapper").addClass("iconSelected");
|
||||
break;
|
||||
case "send":
|
||||
$("#mainNavBtnSendWrapper").addClass("iconSelected");
|
||||
break;
|
||||
case "transactions":
|
||||
$("#mainNavBtnTransactionsWrapper").addClass("iconSelected");
|
||||
break;
|
||||
case "settings":
|
||||
$("#mainNavBtnSettingsWrapper").addClass("iconSelected");
|
||||
break;
|
||||
default: // do nothing for now
|
||||
}
|
||||
}
|
||||
|
||||
getAppState() {
|
||||
return this.appState;
|
||||
}
|
||||
|
||||
showGeneralError(errorText) {
|
||||
$("#txtGeneralError").html(errorText);
|
||||
|
||||
// create and open the dialog
|
||||
$("#dlgGeneralError").iziModal();
|
||||
$('#dlgGeneralError').iziModal('open');
|
||||
|
||||
$("#btnGeneralErrorOK").click(function() {
|
||||
$('#dlgGeneralError').iziModal('close');
|
||||
});
|
||||
}
|
||||
|
||||
renderTemplate(template, data) {
|
||||
var template = Handlebars.compile(ipcRenderer.sendSync('getTemplateContent', template));
|
||||
|
||||
$("#mainContent").empty();
|
||||
$("#mainContent").html(template(data));
|
||||
}
|
||||
}
|
||||
|
||||
$("#mainNavBtnTransactions").click(function() {
|
||||
EthoMainGUI.changeAppState("transactions");
|
||||
EthoTransactions.renderTransactions();
|
||||
});
|
||||
|
||||
$("#mainNavBtnSend").click(function() {
|
||||
EthoMainGUI.changeAppState("send");
|
||||
EthoSend.renderSendState();
|
||||
});
|
||||
|
||||
$("#mainNavBtnWallets").click(function() {
|
||||
EthoMainGUI.changeAppState("account");
|
||||
EthoWallets.renderWalletsState();
|
||||
});
|
||||
|
||||
$("#mainNavBtnSettings").click(function() {
|
||||
EthoMainGUI.changeAppState("settings");
|
||||
EthoSettings.renderSettingsState();
|
||||
});
|
||||
|
||||
EthoMainGUI = new MainGUI();
|
||||
174
renderer/send.js
Normal file
174
renderer/send.js
Normal file
@@ -0,0 +1,174 @@
|
||||
// In renderer process (web page).
|
||||
const {ipcRenderer} = require('electron');
|
||||
|
||||
class SendTransaction {
|
||||
constructor() {}
|
||||
|
||||
renderSendState() {
|
||||
EthoBlockchain.getAccountsData(
|
||||
function(error) {
|
||||
EthoMainGUI.showGeneralError(error);
|
||||
},
|
||||
function(data) {
|
||||
EthoMainGUI.renderTemplate("send.html", data);
|
||||
$(document).trigger("render_send");
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
validateSendForm() {
|
||||
if (EthoMainGUI.getAppState() == "send") {
|
||||
if (!$("#sendFromAddress").val()) {
|
||||
EthoMainGUI.showGeneralError("Sender address must be specified!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!EthoBlockchain.isAddress($("#sendFromAddress").val())) {
|
||||
EthoMainGUI.showGeneralError("Sender address must be a valid address!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$("#sendToAddress").val()) {
|
||||
EthoMainGUI.showGeneralError("Recipient address must be specified!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!EthoBlockchain.isAddress($("#sendToAddress").val())) {
|
||||
EthoMainGUI.showGeneralError("Recipient address must be a valid address!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Number($("#sendAmmount").val()) <= 0) {
|
||||
EthoMainGUI.showGeneralError("Send ammount must be greater then zero!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
resetSendForm() {
|
||||
if (EthoMainGUI.getAppState() == "send") {
|
||||
$("#sendFromAddress").val("");
|
||||
$("#sendToAddress").val("");
|
||||
$("#sendAmmount").val(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$(document).on("render_send", function() {
|
||||
$('select').formSelect( {classes: "fromAddressSelect"});
|
||||
|
||||
$("#sendFromAddress").on("change", function() {
|
||||
web3Local.eth.getBalance(this.value, function(error, balance) {
|
||||
$("#sendMaxAmmount").html(parseFloat(web3Local.utils.fromWei(balance, 'ether')));
|
||||
});
|
||||
|
||||
/*
|
||||
// list all transactions for this address
|
||||
if (this.value) {
|
||||
$("#cardTransactionsForAddress").css("display", "block");
|
||||
|
||||
setTimeout(() => {
|
||||
// render the transactions
|
||||
$('#tableTransactionsForAddress').DataTable({
|
||||
"paging": false,
|
||||
"scrollY": "calc(100vh - 115px)",
|
||||
"responsive": true,
|
||||
"processing": true,
|
||||
"order": [[ 0, "desc" ]],
|
||||
"data": ipcRenderer.sendSync('getTransactions', this.value),
|
||||
"columnDefs": [
|
||||
{
|
||||
"className": "transactionsBlockNum",
|
||||
"targets": 0
|
||||
},
|
||||
{
|
||||
"targets": 1,
|
||||
"render": function ( data, type, row ) {
|
||||
return moment(data).format("MMM Do YYYY");
|
||||
}
|
||||
},
|
||||
{
|
||||
"targets": 4,
|
||||
"render": function ( data, type, row ) {
|
||||
return parseFloat(web3Local.utils.fromWei(EthoUtils.toFixed(parseFloat(data)).toString(), 'ether')).toFixed(2);
|
||||
}
|
||||
}
|
||||
],
|
||||
"drawCallback": function( settings ) {
|
||||
$("#loadingTransactionsOverlay").css("display", "none");
|
||||
}
|
||||
});
|
||||
}, 200);
|
||||
} else {
|
||||
$("#cardTransactionsForAddress").css("display", "none");
|
||||
}
|
||||
*/
|
||||
});
|
||||
|
||||
$("#btnSendAll").off('click').on('click', function() {
|
||||
$("#sendAmmount").focus();
|
||||
$("#sendAmmount").val($("#sendMaxAmmount").html());
|
||||
});
|
||||
|
||||
$("#btnSendTransaction").off('click').on('click', function() {
|
||||
if (EthoSend.validateSendForm()) {
|
||||
EthoBlockchain.getTranasctionFee($("#sendFromAddress").val(), $("#sendToAddress").val(), $("#sendAmmount").val(),
|
||||
function(error) {
|
||||
EthoMainGUI.showGeneralError(error);
|
||||
},
|
||||
function(data) {
|
||||
$("#dlgSendWalletPassword").iziModal();
|
||||
$("#walletPassword").val("");
|
||||
$("#fromAddressInfo").html($("#sendFromAddress").val());
|
||||
$("#toAddressInfo").html($("#sendToAddress").val());
|
||||
$("#valueToSendInfo").html($("#sendAmmount").val());
|
||||
$("#feeToPayInfo").html(parseFloat(web3Local.utils.fromWei(data.toString(), 'ether')));
|
||||
$('#dlgSendWalletPassword').iziModal('open');
|
||||
|
||||
function doSendTransaction() {
|
||||
$('#dlgSendWalletPassword').iziModal('close');
|
||||
|
||||
EthoBlockchain.prepareTransaction(
|
||||
$("#walletPassword").val(),
|
||||
$("#sendFromAddress").val(),
|
||||
$("#sendToAddress").val(),
|
||||
$("#sendAmmount").val(),
|
||||
function(error) {
|
||||
EthoMainGUI.showGeneralError(error);
|
||||
},
|
||||
function(data) {
|
||||
EthoBlockchain.sendTransaction(data.raw,
|
||||
function(error) {
|
||||
EthoMainGUI.showGeneralError(error);
|
||||
},
|
||||
function(data) {
|
||||
EthoSend.resetSendForm();
|
||||
// use the transaction hash
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$("#btnSendWalletPasswordConfirm").off('click').on('click', function() {
|
||||
doSendTransaction();
|
||||
});
|
||||
|
||||
$("#dlgSendWalletPassword").off('keypress').on('keypress', function(e) {
|
||||
if(e.which == 13) {
|
||||
doSendTransaction();
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// create new account variable
|
||||
EthoSend = new SendTransaction();
|
||||
28
renderer/settings.js
Normal file
28
renderer/settings.js
Normal file
@@ -0,0 +1,28 @@
|
||||
// In renderer process (web page).
|
||||
const {ipcRenderer} = require('electron');
|
||||
|
||||
class Settings {
|
||||
constructor() {}
|
||||
|
||||
renderSettingsState() {
|
||||
EthoMainGUI.renderTemplate("settings.html", {});
|
||||
$(document).trigger("render_settings");
|
||||
}
|
||||
}
|
||||
|
||||
$(document).on("render_settings", function() {
|
||||
$("#btnSettingsCleanTransactions").off('click').on('click', function() {
|
||||
EthoMainGUI.showGeneralError("Not implemented yet!");
|
||||
});
|
||||
|
||||
$("#btnSettingsCleanWallets").off('click').on('click', function() {
|
||||
EthoMainGUI.showGeneralError("Not implemented yet!");
|
||||
});
|
||||
|
||||
$("#btnSettingsCleanBlockchain").off('click').on('click', function() {
|
||||
EthoMainGUI.showGeneralError("Not implemented yet!");
|
||||
});
|
||||
});
|
||||
|
||||
// create new account variable
|
||||
EthoSettings = new Settings();
|
||||
109
renderer/syncing.js
Normal file
109
renderer/syncing.js
Normal file
@@ -0,0 +1,109 @@
|
||||
// In renderer process (web page).
|
||||
const {ipcRenderer} = require('electron');
|
||||
|
||||
// Set the provider you want from Web3.providers
|
||||
SyncProgress = new ProgressBar.Line('#syncProgress',
|
||||
{
|
||||
strokeWidth: 6,
|
||||
easing: 'easeInOut',
|
||||
duration: 1400,
|
||||
color: "#7A1336",
|
||||
trailColor: '#eee',
|
||||
trailWidth: 1,
|
||||
text: {
|
||||
style: {
|
||||
color: '#bbb',
|
||||
position: "absolute",
|
||||
left: "50%",
|
||||
top: "-1px",
|
||||
transform: "translateX(-50%)",
|
||||
fontSize: "0.9em",
|
||||
LineHeight: "24px",
|
||||
padding: 0
|
||||
},
|
||||
autoStyleContainer: false
|
||||
},
|
||||
from: {color: '#FFEA82'},
|
||||
to: {color: '#ED6A5A'}
|
||||
});
|
||||
|
||||
// set initial value for the progress text
|
||||
SyncProgress.setText("initializing, please wait...");
|
||||
|
||||
var peerCountInterval = setInterval(function()
|
||||
{
|
||||
web3Local.eth.net.getPeerCount(function(error, count) {
|
||||
$("#peerCount").html(vsprintf("Peer Count: %d", [count]));
|
||||
});
|
||||
}, 5000);
|
||||
|
||||
function StartSyncProcess() {
|
||||
var alreadyCatchedUp = false;
|
||||
|
||||
function keepTheNodeInSync(interval) {
|
||||
var nodeSyncInterval = setInterval(function()
|
||||
{
|
||||
web3Local.eth.isSyncing(function(error, sync)
|
||||
{
|
||||
if(!error) {
|
||||
if(sync == true) {
|
||||
console.log("start the sync");
|
||||
} else if(sync) {
|
||||
SyncProgress.animate(sync.currentBlock / sync.highestBlock);
|
||||
SyncProgress.setText(vsprintf('%d/%d (%d%%)', [sync.currentBlock, sync.highestBlock, Math.round(sync.currentBlock / sync.highestBlock * 100)]));
|
||||
} else {
|
||||
web3Local.eth.getBlock("latest", function(error, localBlock) {
|
||||
if (localBlock.number > 0) {
|
||||
web3Remote.eth.getBlock("latest", function(error, remoteBlock) {
|
||||
if (!EthoTransactions.getIsSyncing()) {
|
||||
SyncProgress.animate(localBlock.number / remoteBlock.number);
|
||||
SyncProgress.setText(vsprintf('%d/%d (%d%%)', [localBlock.number, remoteBlock.number, Math.round(localBlock.number / remoteBlock.number * 100)]));
|
||||
}
|
||||
|
||||
if (remoteBlock.number == localBlock.number) {
|
||||
if (alreadyCatchedUp == false)
|
||||
{
|
||||
// clear the repeat interval and render wallets
|
||||
$(document).trigger("onNewAccountTransaction");
|
||||
clearInterval(nodeSyncInterval);
|
||||
alreadyCatchedUp = true;
|
||||
|
||||
// sync all the transactions to the current block
|
||||
EthoTransactions.syncTransactionsForAllAddresses(localBlock.number);
|
||||
$(document).trigger("onSyncInterval");
|
||||
|
||||
// restart with less intensity
|
||||
keepTheNodeInSync(10000);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}, interval);
|
||||
}
|
||||
|
||||
// initial fast syncing
|
||||
keepTheNodeInSync(2000);
|
||||
}
|
||||
|
||||
var InitWeb3 = setInterval(function()
|
||||
{
|
||||
try {
|
||||
web3Local = new Web3(new Web3.providers.WebsocketProvider('ws://localhost:8546'));
|
||||
web3Remote = new Web3(new Web3.providers.HttpProvider("https://rpc.ether1.org"));
|
||||
|
||||
web3Local.eth.net.isListening(function(error, success) {
|
||||
if (!error) {
|
||||
$(document).trigger("onGethReady");
|
||||
clearInterval(InitWeb3);
|
||||
StartSyncProcess();
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
}, 2000);
|
||||
188
renderer/transactions.js
Normal file
188
renderer/transactions.js
Normal file
@@ -0,0 +1,188 @@
|
||||
// In renderer process (web page).
|
||||
const {ipcRenderer} = require('electron');
|
||||
|
||||
class Transactions {
|
||||
constructor() {
|
||||
this.isSyncing = false;
|
||||
}
|
||||
|
||||
setIsSyncing(value) {
|
||||
this.isSyncing = value;
|
||||
}
|
||||
|
||||
getIsSyncing() {
|
||||
return this.isSyncing;
|
||||
}
|
||||
|
||||
syncTransactionsForSingleAddress(addressList, counters, lastBlock, counter) {
|
||||
if (counter < addressList.length - 1) {
|
||||
SyncProgress.setText(vsprintf("Syncing address transactions %d/%d, please wait...", [counter, addressList.length]));
|
||||
|
||||
var startBlock = parseInt(counters.transactions) || 0;
|
||||
var params = vsprintf('?address=%s&fromBlock=%d&toBlock=%d', [addressList[counter], startBlock, lastBlock]);
|
||||
|
||||
$.getJSON("https://richlist.ether1.org/transactions_list.php" + params, function( result ) {
|
||||
result.data.forEach(element => {
|
||||
var Transaction = {
|
||||
block: element.block,
|
||||
fromaddr: element.fromaddr,
|
||||
timestamp: element.timestamp,
|
||||
toaddr: element.toaddr,
|
||||
value: element.value
|
||||
}
|
||||
ipcRenderer.send('storeTransaction', Transaction);
|
||||
});
|
||||
|
||||
// update the counter and store it back to file system
|
||||
counters.transactions = lastBlock;
|
||||
ipcRenderer.sendSync('setJSONFile',
|
||||
{
|
||||
file: 'counters.json',
|
||||
data: counters
|
||||
});
|
||||
|
||||
// call the transaction sync for the next address
|
||||
EthoTransactions.syncTransactionsForSingleAddress(addressList, counters, lastBlock, counter + 1);
|
||||
});
|
||||
} else {
|
||||
SyncProgress.setText("Syncing transactions is complete.");
|
||||
EthoTransactions.setIsSyncing(false);
|
||||
}
|
||||
}
|
||||
|
||||
syncTransactionsForAllAddresses(lastBlock) {
|
||||
var counters = ipcRenderer.sendSync('getJSONFile', 'counters.json');
|
||||
var counter = 0;
|
||||
|
||||
if (counters == null) {
|
||||
counters = {};
|
||||
}
|
||||
|
||||
EthoBlockchain.getAccounts(
|
||||
function(error) {
|
||||
EthoMainGUI.showGeneralError(error);
|
||||
},
|
||||
function(data) {
|
||||
EthoTransactions.setIsSyncing(true);
|
||||
EthoTransactions.syncTransactionsForSingleAddress(data, counters, lastBlock, counter);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
renderTransactions() {
|
||||
EthoMainGUI.renderTemplate("transactions.html", {});
|
||||
$(document).trigger("render_transactions");
|
||||
|
||||
// show the loading overlay for transactions
|
||||
$("#loadingTransactionsOverlay").css("display", "block");
|
||||
|
||||
setTimeout(() => {
|
||||
// render the transactions
|
||||
$('#tableTransactionsForAll').DataTable({
|
||||
"paging": false,
|
||||
"scrollY": "calc(100vh - 115px)",
|
||||
"responsive": true,
|
||||
"processing": true,
|
||||
"order": [[ 0, "desc" ]],
|
||||
"data": ipcRenderer.sendSync('getTransactions'),
|
||||
"columnDefs": [
|
||||
{
|
||||
"className": "transactionsBlockNum",
|
||||
"targets": 0
|
||||
},
|
||||
{
|
||||
"targets": 1,
|
||||
"render": function ( data, type, row ) {
|
||||
return moment(data).format("MMM Do YYYY");
|
||||
}
|
||||
},
|
||||
{
|
||||
"targets": 4,
|
||||
"render": function ( data, type, row ) {
|
||||
return parseFloat(web3Local.utils.fromWei(EthoUtils.toFixed(parseFloat(data)).toString(), 'ether')).toFixed(2);
|
||||
}
|
||||
}
|
||||
],
|
||||
"drawCallback": function( settings ) {
|
||||
$("#loadingTransactionsOverlay").css("display", "none");
|
||||
}
|
||||
});
|
||||
}, 200);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// event that tells us that geth is ready and up
|
||||
$(document).on("onSyncInterval", function() {
|
||||
var counters = ipcRenderer.sendSync('getJSONFile', 'counters.json');
|
||||
|
||||
if (counters == null) {
|
||||
counters = {};
|
||||
}
|
||||
|
||||
function doSyncRemainingBlocks() {
|
||||
EthoBlockchain.getBlock("latest", false,
|
||||
function(error) {
|
||||
EthoMainGUI.showGeneralError(error);
|
||||
},
|
||||
function(block) {
|
||||
var lastBlock = counters.transactions || 0;
|
||||
|
||||
if (lastBlock < block.number) {
|
||||
function getNextBlockTransactions(blockNumber, maxBlock) {
|
||||
EthoBlockchain.getBlock(blockNumber, true,
|
||||
function(error) {
|
||||
EthoMainGUI.showGeneralError(error);
|
||||
},
|
||||
function(data) {
|
||||
if (blockNumber < maxBlock) {
|
||||
if (data.transactions) {
|
||||
data.transactions.forEach(element => {
|
||||
if ((EthoWallets.getAddressExists(element.from)) || (EthoWallets.getAddressExists(element.to))) {
|
||||
var Transaction = {
|
||||
block: element.blockNumber.toString(),
|
||||
fromaddr: element.from.toLowerCase(),
|
||||
timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
|
||||
toaddr: element.to.toLowerCase(),
|
||||
value: Number(element.value).toExponential(5).toString().replace('+','')
|
||||
}
|
||||
|
||||
// store transaction and notify about new transactions
|
||||
ipcRenderer.send('storeTransaction', Transaction);
|
||||
$(document).trigger("onNewAccountTransaction");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// call the next iteration for the next block
|
||||
getNextBlockTransactions(blockNumber + 1 , maxBlock)
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// call initial call of function
|
||||
getNextBlockTransactions(lastBlock, block.number);
|
||||
} else {
|
||||
counters.transactions = block.number;
|
||||
ipcRenderer.sendSync('setJSONFile',
|
||||
{
|
||||
file: 'counters.json',
|
||||
data: counters
|
||||
});
|
||||
|
||||
setTimeout(function() {
|
||||
doSyncRemainingBlocks();
|
||||
}, 10000);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// do the initial sync
|
||||
doSyncRemainingBlocks();
|
||||
});
|
||||
|
||||
|
||||
// create new transactions variable
|
||||
EthoTransactions = new Transactions();
|
||||
23
renderer/utils.js
Normal file
23
renderer/utils.js
Normal file
@@ -0,0 +1,23 @@
|
||||
class Utils {
|
||||
constructor() {}
|
||||
|
||||
toFixed(x) {
|
||||
if (Math.abs(x) < 1.0) {
|
||||
var e = parseInt(x.toString().split('e-')[1]);
|
||||
if (e) {
|
||||
x *= Math.pow(10,e-1);
|
||||
x = '0.' + (new Array(e)).join('0') + x.toString().substring(2);
|
||||
}
|
||||
} else {
|
||||
var e = parseInt(x.toString().split('+')[1]);
|
||||
if (e > 20) {
|
||||
e -= 20;
|
||||
x /= Math.pow(10,e);
|
||||
x += (new Array(e+1)).join('0');
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
EthoUtils = new Utils();
|
||||
158
renderer/wallets.js
Normal file
158
renderer/wallets.js
Normal file
@@ -0,0 +1,158 @@
|
||||
// In renderer process (web page).
|
||||
const {ipcRenderer} = require('electron');
|
||||
|
||||
class Wallets {
|
||||
constructor() {
|
||||
this.addressList = [];
|
||||
}
|
||||
|
||||
getAddressList() {
|
||||
return this.addressList;
|
||||
}
|
||||
|
||||
clearAddressList() {
|
||||
this.addressList = [];
|
||||
}
|
||||
|
||||
getAddressExists(address) {
|
||||
return this.addressList.indexOf(address.toLowerCase()) > -1;
|
||||
}
|
||||
|
||||
addAddressToList(address) {
|
||||
this.addressList.push(address.toLowerCase());
|
||||
}
|
||||
|
||||
validateNewAccountForm() {
|
||||
if (EthoMainGUI.getAppState() == "account") {
|
||||
if (!$("#walletPasswordFirst").val()) {
|
||||
EthoMainGUI.showGeneralError("Password cannot be empty!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$("#walletPasswordSecond").val()) {
|
||||
EthoMainGUI.showGeneralError("Password cannot be empty!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($("#walletPasswordFirst").val() !== $("#walletPasswordSecond").val()) {
|
||||
EthoMainGUI.showGeneralError("Passwords do not match!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
renderWalletsState() {
|
||||
// clear the list of addresses
|
||||
EthoWallets.clearAddressList();
|
||||
|
||||
EthoBlockchain.getAccountsData(
|
||||
function(error) {
|
||||
EthoMainGUI.showGeneralError(error);
|
||||
},
|
||||
function(data) {
|
||||
data.addressData.forEach(element => {
|
||||
EthoWallets.addAddressToList(element.address);
|
||||
});
|
||||
|
||||
// render the wallets current state
|
||||
EthoMainGUI.renderTemplate("wallets.html", data);
|
||||
$(document).trigger("render_wallets");
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// the event to tell us that the wallets are rendered
|
||||
$(document).on("render_wallets", function() {
|
||||
$('#addressTable').floatThead();
|
||||
|
||||
$("#btnNewAddress").off('click').on('click', function() {
|
||||
$("#dlgCreateWalletPassword").iziModal();
|
||||
$("#walletPasswordFirst").val("");
|
||||
$("#walletPasswordSecond").val("");
|
||||
$('#dlgCreateWalletPassword').iziModal('open');
|
||||
|
||||
function doCreateNewWallet() {
|
||||
$('#dlgCreateWalletPassword').iziModal('close');
|
||||
|
||||
if (EthoWallets.validateNewAccountForm()) {
|
||||
EthoBlockchain.createNewAccount($("#walletPasswordFirst").val(),
|
||||
function(error) {
|
||||
EthoMainGUI.showGeneralError(error);
|
||||
},
|
||||
function(account) {
|
||||
EthoWallets.addAddressToList(account);
|
||||
EthoWallets.renderWalletsState();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$("#btnCreateWalletConfirm").off('click').on('click', function() {
|
||||
doCreateNewWallet();
|
||||
});
|
||||
|
||||
$("dlgCreateWalletPassword").off('keypress').on('keypress', function(e) {
|
||||
if(e.which == 13) {
|
||||
doCreateNewWallet();
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
$(".btnChangWalletName").off('click').on('click', function() {
|
||||
var walletAddress = $(this).attr('data-wallet');
|
||||
var walletName = $(this).attr('data-name');
|
||||
|
||||
$("#dlgChangeWalletName").iziModal();
|
||||
$("#inputWalletName").val(walletName);
|
||||
$('#dlgChangeWalletName').iziModal('open');
|
||||
|
||||
function doChangeWalletName() {
|
||||
var wallets = ipcRenderer.sendSync('getJSONFile', 'wallets.json');
|
||||
|
||||
if (!wallets) {
|
||||
wallets = { names: {} };
|
||||
}
|
||||
|
||||
// set the wallet name from the dialog box
|
||||
wallets.names[walletAddress] = $("#inputWalletName").val();
|
||||
ipcRenderer.sendSync('setJSONFile',
|
||||
{
|
||||
file: 'wallets.json',
|
||||
data: wallets
|
||||
});
|
||||
|
||||
$('#dlgChangeWalletName').iziModal('close');
|
||||
EthoWallets.renderWalletsState();
|
||||
}
|
||||
|
||||
$("#btnChangeWalletNameConfirm").off('click').on('click', function() {
|
||||
doChangeWalletName();
|
||||
});
|
||||
|
||||
$("#dlgChangeWalletName").off('keypress').on('keypress', function(e) {
|
||||
if(e.which == 13) {
|
||||
doChangeWalletName();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// event that tells us that geth is ready and up
|
||||
$(document).on("onGethReady", function() {
|
||||
EthoMainGUI.changeAppState("account");
|
||||
EthoWallets.renderWalletsState();
|
||||
});
|
||||
|
||||
$(document).on("onNewAccountTransaction", function() {
|
||||
if (EthoMainGUI.getAppState() == "account") {
|
||||
EthoWallets.renderWalletsState();
|
||||
}
|
||||
});
|
||||
|
||||
EthoWallets = new Wallets();
|
||||
Reference in New Issue
Block a user