@ -4,11 +4,33 @@ var EthJSBlock = require('ethereumjs-block')
var ethJSUtil = require ( 'ethereumjs-util' )
var BN = ethJSUtil . BN
var executionContext = require ( '../../execution-context' )
var modalDialog = require ( '../ui/modaldialog' )
var yo = require ( 'yo-yo' )
var typeConversion = require ( '../../lib/typeConversion' )
var csjs = require ( 'csjs-inject' )
var remixLib = require ( 'remix-lib' )
var styleGuide = remixLib . ui . styleGuide
var styles = styleGuide ( )
var css = csjs `
. txInfoBox {
$ { styles . rightPanel . compileTab . box _CompileContainer } ; // add askToConfirmTXContainer to Remix and then replace this styling
}
. wrapword {
white - space : pre - wrap ; /* Since CSS 2.1 */
white - space : - moz - pre - wrap ; /* Mozilla, since 1999 */
white - space : - pre - wrap ; /* Opera 4-6 */
white - space : - o - pre - wrap ; /* Opera 7 */
word - wrap : break - word ; /* Internet Explorer 5.5+ */
}
`
function TxRunner ( vmaccounts , opts ) {
this . personalMode = opts . personalMode
this . blockNumber = 0
this . runAsync = true
this . config = opts . config
this . detectNetwork = opts . detectNetwork
if ( executionContext . isVM ( ) ) {
this . blockNumber = 1150000 // The VM is running in Homestead mode, which started at this block.
this . runAsync = false // We have to run like this cause the VM Event Manager does not support running multiple txs at the same time.
@ -23,8 +45,23 @@ TxRunner.prototype.rawRun = function (args, cb) {
}
TxRunner . prototype . execute = function ( args , callback ) {
var self = this
function execute ( gasPrice ) {
if ( gasPrice ) tx . gasPrice = executionContext . web3 ( ) . toHex ( gasPrice )
var sendTransaction = self . personalMode ? executionContext . web3 ( ) . personal . sendTransaction : executionContext . web3 ( ) . eth . sendTransaction
try {
sendTransaction ( tx , function ( err , resp ) {
if ( err ) {
return callback ( err , resp )
}
tryTillResponse ( resp , callback )
} )
} catch ( e ) {
return callback ( ` Send transaction failed: ${ e . message } . if you use an injected provider, please check it is properly unlocked. ` )
}
}
var self = this
var from = args . from
var to = args . to
var data = args . data
@ -42,6 +79,7 @@ TxRunner.prototype.execute = function (args, callback) {
data : data ,
value : value
}
if ( args . useCall ) {
tx . gas = gasLimit
executionContext . web3 ( ) . eth . call ( tx , function ( error , result ) {
@ -59,7 +97,7 @@ TxRunner.prototype.execute = function (args, callback) {
// NOTE: estimateGas very likely will return a large limit if execution of the code failed
// we want to be able to run the code in order to debug and find the cause for the failure
var warnEstimation = ' An important gas estimation might also be the sign of a problem in the contract code. Please check loops and be sure you did not sent value to a non payable function (that\ 's also the reason of strong gas estimation).'
var warnEstimation = " An important gas estimation might also be the sign of a problem in the contract code. Please check loops and be sure you did not sent value to a non payable function (that's also the reason of strong gas estimation)."
if ( gasEstimation > gasLimit ) {
return callback ( 'Gas required exceeds limit: ' + gasLimit + '. ' + warnEstimation )
}
@ -68,17 +106,37 @@ TxRunner.prototype.execute = function (args, callback) {
}
tx . gas = gasEstimation
var sendTransaction = self . personalMode ? executionContext . web3 ( ) . personal . sendTransaction : executionContext . web3 ( ) . eth . sendTransaction
try {
sendTransaction ( tx , function ( err , resp ) {
if ( ! self . config . ge tUnpe rsistedPropert y( 'doNotShowTransactionConfirmationAgain' ) ) {
self . detectNetwork ( ( err , network ) => {
if ( err ) {
return callback ( err , resp )
console . log ( err )
} else {
if ( network . name === 'Main' ) {
var content = confirmDialog ( tx , gasEstimation , self )
modalDialog ( 'Confirm transaction' , content ,
{ label : 'Confirm' ,
fn : ( ) => {
self . config . setUnpersistedProperty ( 'doNotShowTransactionConfirmationAgain' , content . querySelector ( 'input#confirmsetting' ) . checked )
if ( ! content . gasPriceStatus ) {
callback ( 'Given gas grice is not correct' )
} else {
var gasPrice = executionContext . web3 ( ) . toWei ( content . querySelector ( '#gasprice' ) . value , 'gwei' )
execute ( gasPrice )
}
} } , {
label : 'Cancel' ,
fn : ( ) => {
return callback ( 'Transaction canceled by user.' )
}
} )
} else {
execute ( )
}
}
tryTillResponse ( resp , callback )
} )
} catch ( e ) {
return callback ( ` Send transaction failed: ${ e . message } . if you use an injected provider, please check it is properly unlocked. ` )
} else {
execute ( )
}
} )
}
@ -164,4 +222,57 @@ function run (self, tx, stamp, callback) {
}
}
function confirmDialog ( tx , gasEstimation , self ) {
var amount = executionContext . web3 ( ) . fromWei ( typeConversion . toInt ( tx . value ) , 'ether' )
var input = yo ` <input id='confirmsetting' type="checkbox"> `
var el = yo `
< div >
< div > You are creating a transaction on the main network . Click confirm if you are sure to continue . < / d i v >
< div class = $ { css . txInfoBox } >
< div > From : $ { tx . from } < / d i v >
< div > To : $ { tx . to ? tx . to : '(Contract Creation)' } < / d i v >
< div > Amount : $ { amount } Ether < / d i v >
< div > Gas estimation : $ { gasEstimation } < / d i v >
< div > Gas limit : $ { tx . gas } < / d i v >
< div > Gas price : < input id = 'gasprice' oninput = $ { gasPriceChanged } / > Gwei < / d i v >
< div > Max transaction fee : < span id = 'txfee' > < / s p a n > < / d i v >
< div > Data : < / d i v >
< pre class = $ { css . wrapword } > $ { tx . data } < / p r e >
< / d i v >
< div class = $ { css . checkbox } >
$ { input }
< i class = "fa fa-exclamation-triangle" aria - hidden = "true" > < / i > D o n o t a s k f o r c o n f i r m a t i o n a g a i n . ( t h e s e t t i n g w i l l n o t b e p e r s i s t e d f o r t h e n e x t p a g e r e l o a d )
< / d i v >
< / d i v >
`
var warnMessage = ' Please fix this issue before sending any transaction. '
function gasPriceChanged ( ) {
try {
var gasPrice = el . querySelector ( '#gasprice' ) . value
var fee = executionContext . web3 ( ) . toBigNumber ( tx . gas ) . mul ( executionContext . web3 ( ) . toBigNumber ( executionContext . web3 ( ) . toWei ( gasPrice . toString ( 10 ) , 'gwei' ) ) )
el . querySelector ( '#txfee' ) . innerHTML = ' ' + executionContext . web3 ( ) . fromWei ( fee . toString ( 10 ) , 'ether' ) + ' Ether'
el . gasPriceStatus = true
} catch ( e ) {
el . querySelector ( '#txfee' ) . innerHTML = warnMessage + e . message
el . gasPriceStatus = false
}
}
executionContext . web3 ( ) . eth . getGasPrice ( ( error , gasPrice ) => {
if ( error ) {
el . querySelector ( '#txfee' ) . innerHTML = 'Unable to retrieve the current network gas price.' + warnMessage + error
} else {
try {
el . querySelector ( '#gasprice' ) . value = executionContext . web3 ( ) . fromWei ( gasPrice . toString ( 10 ) , 'gwei' )
gasPriceChanged ( )
} catch ( e ) {
el . querySelector ( '#txfee' ) . innerHTML = warnMessage + e . message
el . gasPriceStatus = false
}
}
} )
return el
}
module . exports = TxRunner