UNPKG

rue-mist-interface

Version:

Mist interface application

420 lines (351 loc) 15.1 kB
/** Template Controllers @module Templates */ var setWindowSize = function (template) { Tracker.afterFlush(function () { ipc.send('backendAction_setWindowSize', 580, template.$('.popup-windows .inner-container').height() + 240); }); }; var defaultEstimateGas = 50000000; /** The sendTransaction confirmation popup window template @class [template] popupWindows_sendTransactionConfirmation @constructor */ /** Takes a 4-byte function signature and does a best-effort conversion to a human readable text signature. @method (lookupFunctionSignature) */ var lookupFunctionSignature = function (data, remoteLookup) { return new Q(function (resolve, reject) { if (data && data.length > 8) { var bytesSignature = (data.substr(0, 2) === '0x') ? data.substr(0, 10) : '0x' + data.substr(0, 8); if (remoteLookup) { https.get('https://www.4byte.directory/api/v1/signatures/?hex_signature=' + bytesSignature, function (response) { var body = ''; response.on('data', function (chunk) { body += chunk; }); response.on('end', function () { var responseData = JSON.parse(body); if (responseData.results.length) { resolve(responseData.results[0].text_signature); } else { resolve(bytesSignature); } }); }).on('error', function (error) { console.warn('Error querying Function Signature Registry.', err); reject(bytesSignature); }); } else if (_.first(window.SIGNATURES[bytesSignature])) { resolve(_.first(window.SIGNATURES[bytesSignature])); } else { reject(bytesSignature); } } else { reject(undefined); } }); }; var localSignatureLookup = function (data) { return lookupFunctionSignature(data, false); }; var remoteSignatureLookup = function (data) { return lookupFunctionSignature(data, true); }; var signatureLookupCallback = function (textSignature) { // Clean version of function signature. Striping params TemplateVar.set(template, 'executionFunction', textSignature.replace(/\(.+$/g, '')); TemplateVar.set(template, 'hasSignature', true); var params = textSignature.match(/\((.+)\)/i); if (params) { console.log('params sent', params); TemplateVar.set(template, 'executionFunctionParamTypes', params); ipc.send('backendAction_decodeFunctionSignature', textSignature, data.data); } }; Template['popupWindows_sendTransactionConfirmation'].onCreated(function () { var template = this; ipc.on('uiAction_decodedFunctionSignatures', function (event, params) { console.log('params returned', params); TemplateVar.set(template, 'params', params); }); // check reactively if provided gas is enough this.autorun(function () { if (TemplateVar.get('estimatedGas') > Number(TemplateVar.get('providedGas'))) { TemplateVar.set('gasError', 'notEnoughGas'); } else if (TemplateVar.get('estimatedGas') > 4000000) { TemplateVar.set('gasError', 'overBlockGasLimit'); } else { TemplateVar.set('gasError', null); } }); // check inital data and gas estimates this.autorun(function () { TemplateVar.set(template, 'displayDecodedParams', true); var data = Session.get('data'); if (data) { // set window size setWindowSize(template); // set provided gas to templateVar TemplateVar.set('providedGas', data.gas || 0); TemplateVar.set('initialProvidedGas', data.gas || 0); // add gasPrice if not set if (!data.gasPrice) { web3.eth.getGasPrice(function (e, res) { if (!e) { data.gasPrice = '0x' + res.toString(16); Session.set('data', data); } }); } // check if to is a contract if (data.to) { web3.eth.getCode(data.to, function (e, res) { if (!e && res && res.length > 2) { TemplateVar.set(template, 'toIsContract', true); setWindowSize(template); } }); if (data.data) { localSignatureLookup(data.data).then(function (textSignature) { // Clean version of function signature. Striping params TemplateVar.set(template, 'executionFunction', textSignature.replace(/\(.+$/g, '')); TemplateVar.set(template, 'hasSignature', true); var params = textSignature.match(/\((.+)\)/i); if (params) { TemplateVar.set(template, 'executionFunctionParamTypes', params); ipc.send('backendAction_decodeFunctionSignature', textSignature, data.data); } }).catch(function (bytesSignature) { TemplateVar.set(template, 'executionFunction', bytesSignature); TemplateVar.set(template, 'hasSignature', false); }); } } if (data.from) { web3.eth.getCode(data.from, function (e, res) { if (!e && res && res.length > 2) { TemplateVar.set(template, 'fromIsContract', true); } }); } // estimate gas usage var estimateData = _.clone(data); estimateData.gas = defaultEstimateGas; web3.eth.estimateGas(estimateData, function (e, res) { console.log('Estimated gas: ', res, e); if (!e && res) { // set the gas to the estimation, if not provided or lower Tracker.nonreactive(function () { var gas = Number(TemplateVar.get(template, 'providedGas')); if (res === defaultEstimateGas) { return TemplateVar.set(template, 'estimatedGas', 'invalid'); } TemplateVar.set(template, 'estimatedGas', res); if (!gas && res) { TemplateVar.set(template, 'providedGas', res + 100000); TemplateVar.set(template, 'initialProvidedGas', res + 100000); } }); } }); } }); }); Template['popupWindows_sendTransactionConfirmation'].onRendered(function () { var template = this; Meteor.setTimeout(function () { template.$('input[type="password"]').focus(); }, 200); }); Template['popupWindows_sendTransactionConfirmation'].helpers({ /** Returns the total amount @method (totalAmount) */ 'totalAmount': function () { var amount = EthTools.formatBalance(this.value, '0,0.00[0000000000000000]', 'rue'); var dotPos = (~amount.indexOf('.')) ? amount.indexOf('.') + 3 : amount.indexOf(',') + 3; return amount ? amount.substr(0, dotPos) + '<small style="font-size: 0.5em;">' + amount.substr(dotPos) + '</small>' : '0'; }, /** Calculates the fee used for this transaction in ether @method (estimatedFee) */ 'estimatedFee': function () { var gas = TemplateVar.get('estimatedGas'); if (gas && this.gasPrice) { return EthTools.formatBalance(new BigNumber(gas, 10).times(new BigNumber(this.gasPrice, 10)), '0,0.0[0000000] unit', 'rue'); } }, /** Calculates the provided gas amount in ether @method (providedGas) */ 'providedGas': function () { var gas = TemplateVar.get('providedGas'); if (gas && this.gasPrice) { return EthTools.formatBalance(new BigNumber(gas, 10).times(new BigNumber(this.gasPrice, 10)), '0,0.0[0000000]', 'rue'); } }, /** Shortens the address to 0xffff...ffff @method (shortenAddress) */ 'shortenAddress': function (address) { if (_.isString(address)) { return address.substr(0, 6) + '...' + address.substr(-4); } }, /** Formats the data so that all zeros are wrapped in span.zero @method (formattedData) */ 'formattedData': function () { return (TemplateVar.get('toIsContract')) ? this.data.replace(/([0]{2,})/g, '<span class="zero">$1</span>').replace(/(0x[a-f0-9]{8})/i, '<span class="function">$1</span>') : this.data.replace(/([0]{2,})/g, '<span class="zero">$1</span>'); }, 'params': function () { return TemplateVar.get('params'); }, /** Formats parameters @method (showFormattedParams) */ 'showFormattedParams': function () { return TemplateVar.get('params') && TemplateVar.get('displayDecodedParams'); }, /** Checks if transaction will be invalid @method (transactionInvalid) */ 'transactionInvalid': function () { return TemplateVar.get('estimatedGas') === 'invalid' || TemplateVar.get('estimatedGas') === 0 || typeof TemplateVar.get('estimatedGas') === 'undefined'; } }); Template['popupWindows_sendTransactionConfirmation'].events({ /** Gets the new provided gas in ether amount and calculates the resulting providedGas @event change .provided-gas, input .provided-gas */ 'change .provided-gas, input .provided-gas': function (e, template) { var gas = template.$('.provided-gas').text().replace(/[, ]+/g, '');// template.$('.provided-gas').text(); TemplateVar.set('providedGas', gas); }, /** Increase the estimated gas @event click .not-enough-gas */ 'click .not-enough-gas': function () { var gas = Number(TemplateVar.get('estimatedGas')) + 100000; TemplateVar.set('initialProvidedGas', gas); TemplateVar.set('providedGas', gas); }, /** Cancel the transaction confirmation and close the popup @event click .cancel */ 'click .cancel': function () { ipc.send('backendAction_unlockedAccountAndSentTransaction', 'Transaction not confirmed'); ipc.send('backendAction_closePopupWindow'); }, /** Confirm the transaction @event submit form */ 'submit form': function (e, template) { e.preventDefault(); var data = Session.get('data'), pw = template.find('input[type="password"]').value, gas = web3.fromDecimal(TemplateVar.get('providedGas')); // check if account is about to send to itself if (data.to && data.from === data.to.toLowerCase()) { GlobalNotification.warning({ content: TAPi18n.__('mist.popupWindows.sendTransactionConfirmation.errors.sameAccount'), duration: 5 }); return false; } console.log('Choosen Gas: ', gas, TemplateVar.get('providedGas')); if (!gas || !_.isFinite(gas)) { return; } else { data.gas = gas; } TemplateVar.set('unlocking', true); // unlock and send transaction! web3.personal.sendTransaction(data, pw || '', function (e, res) { pw = null; TemplateVar.set(template, 'unlocking', false); if (!e && res) { ipc.send('backendAction_unlockedAccountAndSentTransaction', null, res); } else { Tracker.afterFlush(function () { template.find('input[type="password"]').value = ''; template.$('input[type="password"]').focus(); }); if (e.message.indexOf('Unable to connect to socket: timeout') !== -1) { GlobalNotification.warning({ content: TAPi18n.__('mist.popupWindows.sendTransactionConfirmation.errors.connectionTimeout'), duration: 5 }); } else if (e.message.indexOf('could not decrypt key with given passphrase') !== -1) { GlobalNotification.warning({ content: TAPi18n.__('mist.popupWindows.sendTransactionConfirmation.errors.wrongPassword'), duration: 3 }); } else if (e.message.indexOf('multiple keys match address') !== -1) { GlobalNotification.warning({ content: TAPi18n.__('mist.popupWindows.sendTransactionConfirmation.errors.multipleKeysMatchAddress'), duration: 10 }); } else if (e.message.indexOf('Insufficient funds for gas * price + value') !== -1) { GlobalNotification.warning({ content: TAPi18n.__('mist.popupWindows.sendTransactionConfirmation.errors.insufficientFundsForGas'), duration: 5 }); } else { GlobalNotification.warning({ content: e.message, duration: 5 }); } } }); }, 'click .data .toggle-panel': function () { TemplateVar.set('displayDecodedParams', true); }, 'click .parameters .toggle-panel': function () { TemplateVar.set('displayDecodedParams', false); }, 'click .lookup-function-signature': function (e, template) { var data = Session.get('data'); TemplateVar.set('lookingUpFunctionSignature', true); remoteSignatureLookup(data.data).then(function (textSignature) { TemplateVar.set(template, 'lookingUpFunctionSignature', false); // Clean version of function signature. Striping params TemplateVar.set(template, 'executionFunction', textSignature.replace(/\(.+$/g, '')); TemplateVar.set(template, 'hasSignature', true); var params = textSignature.match(/\((.+)\)/i); if (params) { console.log('params:', params); TemplateVar.set(template, 'executionFunctionParamTypes', params); ipc.send('backendAction_decodeFunctionSignature', textSignature, data.data); } }).catch(function (bytesSignature) { TemplateVar.set(template, 'lookingUpFunctionSignature', false); TemplateVar.set(template, 'executionFunction', bytesSignature); TemplateVar.set(template, 'hasSignature', false); }); } });