@ -1,76 +1,116 @@
'use strict'
'use strict'
var $ = require ( 'jquery' )
var $ = require ( 'jquery' )
var yo = require ( 'yo-yo' )
var yo = require ( 'yo-yo' )
var helper = require ( '../../lib/helper.js' )
var remixLib = require ( 'remix-lib' )
var remixLib = require ( 'remix-lib' )
var ethJSUtil = require ( 'ethereumjs-util' )
var csjs = require ( 'csjs-inject' )
var txExecution = remixLib . execution . txExecution
var txExecution = remixLib . execution . txExecution
var txFormat = remixLib . execution . txFormat
var txFormat = remixLib . execution . txFormat
var txHelper = remixLib . execution . txHelper
var txHelper = remixLib . execution . txHelper
var EventManager = remixLib . EventManager
var helper = require ( '../../lib/helper.js' )
var executionContext = require ( '../../execution-context' )
var executionContext = require ( '../../execution-context' )
var modalDialogCustom = require ( '../ui/modal-dialog-custom' )
var modalDialogCustom = require ( '../ui/modal-dialog-custom' )
var copyToClipboard = require ( '../ui/copy-to-clipboard' )
var copyToClipboard = require ( '../ui/copy-to-clipboard' )
var Card = require ( '../ui/card' )
var Recorder = require ( '../../recorder' )
var Recorder = require ( '../../recorder' )
var EventManager = remixLib . EventManager
var addTooltip = require ( '../ui/tooltip' )
var addTooltip = require ( '../ui/tooltip' )
var ethJSUtil = require ( 'ethereumjs-util' )
var MultiParamManager = require ( '../../multiParamManager' )
var csjs = require ( 'csjs-inject' )
var css = require ( './styles/run-tab-styles' )
var css = require ( './styles/run-tab-styles' )
var MultiParamManager = require ( '../../multiParamManager' )
var instanceContainer = yo ` <div class=" ${ css . instanceContainer } "></div> `
var instanceContainerTitle = yo `
< div class = $ { css . instanceContainerTitle } > UDapps of deployed contracts < / d i v > `
var noInstancesText = yo `
< div class = "${css.noInstancesText}" > Currently you have no contract instances . < / d i v > `
var pendingTxsText = yo ` <span>0 pending transactions</span> `
function runTab ( appAPI = { } , appEvents = { } , opts = { } ) {
function runTab ( appAPI = { } , appEvents = { } , opts = { } ) {
var container = yo ` <div class=" ${ css . runTabView } " id="runTabView" ></div> `
/ * - - - - - - - - - - - - - - - - - - - - - - - - -
VARIABLES
-- -- -- -- -- -- -- -- -- -- -- -- -- - * /
var self = this
var event = new EventManager ( )
var event = new EventManager ( )
var clearInstanceElement = yo `
self . _view = { }
< i class = "${css.clearinstance} ${css.icon} fa fa-trash"
self . data = {
onclick = $ { ( ) => { event . trigger ( 'clearInstance' , [ ] ) } }
count : 0 ,
title = "Clear Instances List" aria - hidden = "true" >
text : ` All transactions (deployed contracts and function executions)
in this environment can be saved and replayed in
another environment . i . e . Transactions created in
Javascript VM can be replayed in the Ropsten network . `
}
self . _view . recorderCount = yo ` <span>0</span> `
self . _view . instanceContainer = yo ` <div class=" ${ css . instanceContainer } "></div> `
self . _view . clearInstanceElement = yo `
< i class = "${css.clearinstance} ${css.icon} fa fa-trash" onclick = $ { ( ) => clearInstanceList ( self ) }
title = "Clear instances list and reset recorder" aria - hidden = "true" >
< / i > `
< / i > `
self . _view . instanceContainerTitle = yo `
< div class = $ { css . instanceContainerTitle }
title = "Autogenerated generic user interfaces for interaction with deployed contracts" >
UI for Deployed Contracts
$ { self . _view . clearInstanceElement }
< / d i v > `
self . _view . noInstancesText = yo `
< div class = "${css.noInstancesText}" >
Currently you have no contract instances to interact with .
< / d i v > `
clearInstanceElement . addEventListener ( 'click' , ( ) => {
var container = yo ` <div class=" ${ css . runTabView } " id="runTabView" ></div> `
event . trigger ( 'clearInstance' , [ ] )
var recorderInterface = makeRecorder ( event , appAPI , appEvents , opts , self )
} )
var recorderInterface = makeRecorder ( event , appAPI , appEvents , opts )
self . _view . collapsedView = yo `
var pendingTxsContainer = yo `
< div class = $ { css . recorderCollapsedView } >
< div class = "${css.pendingTxsContainer}" >
< div class = $ { css . recorderCount } > $ { self . _view . recorderCount } < / d i v >
< div class = "${css.pendingTxsText}" >
< / d i v > `
$ { pendingTxsText }
< span class = "${css.transactionActions}" >
self . _view . expandedView = yo `
< div class = $ { css . recorderExpandedView } >
< div class = $ { css . recorderDescription } >
$ { self . data . text }
< / d i v >
< div class = "${css.transactionActions}" >
$ { recorderInterface . recordButton }
$ { recorderInterface . recordButton }
$ { recorderInterface . runButton }
$ { recorderInterface . runButton }
$ { clearInstanceElement }
< / d i v >
< / s p a n >
< / d i v >
< / d i v >
< / d i v > `
< / d i v > `
self . recorderOpts = {
title : 'Events recorded:' ,
collapsedView : self . _view . collapsedView
}
var recorderCard = new Card ( { } , { } , self . recorderOpts )
recorderCard . event . register ( 'expandCollapseCard' , ( arrow , body , status ) => {
body . innerHTML = ''
status . innerHTML = ''
if ( arrow === 'up' ) {
status . appendChild ( self . _view . collapsedView )
body . appendChild ( self . _view . expandedView )
} else if ( arrow === 'down' ) {
status . appendChild ( self . _view . collapsedView )
}
} )
/ * - - - - - - - - - - - - - - - - - - - - - - - - -
MAIN HTML ELEMENT
-- -- -- -- -- -- -- -- -- -- -- -- -- - * /
var el = yo `
var el = yo `
< div >
< div >
$ { settings ( container , appAPI , appEvents , opts ) }
$ { settings ( container , appAPI , appEvents , opts ) }
$ { contractDropdown ( event , appAPI , appEvents , opts , instanceContainer ) }
$ { contractDropdown ( event , appAPI , appEvents , opts , self ) }
$ { pendingTxsContainer }
$ { recorderCard . render ( ) }
$ { instanceContainer }
$ { self . _view . instanceContainer }
< / d i v >
< / d i v >
`
`
container . appendChild ( el )
container . appendChild ( el )
// PENDING transactions
/ * - - - - - - - - - - - - - - - - - - - - - - - - -
function updatePendingTxs ( container , appAPI ) {
HELPER FUNCTIONS
var pendingCount = Object . keys ( opts . udapp . pendingTransactions ( ) ) . length
-- -- -- -- -- -- -- -- -- -- -- -- -- - * /
pendingTxsText . innerText = pendingCount + ' pending transactions'
}
// DROPDOWN
// DROPDOWN
var selectExEnv = el . querySelector ( '#selectExEnvOptions' )
var selectExEnv = el . querySelector ( '#selectExEnvOptions' )
function clearInstanceList ( self ) {
event . trigger ( 'clearInstance' , [ ] )
self . _view . recorderCount . innerText = 0
}
function setFinalContext ( ) {
function setFinalContext ( ) {
// set the final context. Cause it is possible that this is not the one we've originaly selected
// set the final context. Cause it is possible that this is not the one we've originaly selected
selectExEnv . value = executionContext . getProvider ( )
selectExEnv . value = executionContext . getProvider ( )
@ -95,20 +135,23 @@ function runTab (appAPI = {}, appEvents = {}, opts = {}) {
modalDialogCustom . alert ( alertMsg )
modalDialogCustom . alert ( alertMsg )
} , setFinalContext )
} , setFinalContext )
} )
} )
selectExEnv . value = executionContext . getProvider ( )
selectExEnv . value = executionContext . getProvider ( )
executionContext . event . register ( 'contextChanged' , ( context , silent ) => {
executionContext . event . register ( 'contextChanged' , ( context , silent ) => {
setFinalContext ( )
setFinalContext ( )
} )
} )
fillAccountsList ( appAPI , opts , el )
fillAccountsList ( appAPI , opts , el )
setInterval ( ( ) => {
setInterval ( ( ) => {
updateAccountBalances ( container , appAPI )
updateAccountBalances ( container , appAPI )
updatePendingTxs ( container , appAPI )
} , 10000 )
} , 10000 )
event . register ( 'clearInstance' , ( ) => {
event . register ( 'clearInstance' , ( ) => {
var instanceContainer = self . _view . instanceContainer
var instanceContainerTitle = self . _view . instanceContainerTitle
instanceContainer . innerHTML = '' // clear the instances list
instanceContainer . innerHTML = '' // clear the instances list
instanceContainer . appendChild ( instanceContainerTitle )
instanceContainer . appendChild ( instanceContainerTitle )
instanceContainer . appendChild ( noInstancesText )
instanceContainer . appendChild ( self . _view . noInstancesText )
} )
} )
return { render ( ) { return container } }
return { render ( ) { return container } }
}
}
@ -143,7 +186,7 @@ function updateAccountBalances (container, appAPI) {
/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
RECORDER
RECORDER
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- * /
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- * /
function makeRecorder ( events , appAPI , appEvents , opts ) {
function makeRecorder ( events , appAPI , appEvents , opts , self ) {
var recorder = new Recorder ( opts . compiler , {
var recorder = new Recorder ( opts . compiler , {
events : {
events : {
udapp : appEvents . udapp ,
udapp : appEvents . udapp ,
@ -152,23 +195,26 @@ function makeRecorder (events, appAPI, appEvents, opts) {
} ,
} ,
api : appAPI
api : appAPI
} )
} )
recorder . event . register ( 'newTxRecorded' , ( count ) => {
self . data . count = count
self . _view . recorderCount . innerText = count
} )
var css2 = csjs `
var css2 = csjs `
. container ,
. container { }
. runTxs ,
. runTxs { }
. recorder {
. recorder { }
}
`
`
var runButton = yo ` <i class="fa fa-play runtransaction ${ css2 . runTxs } ${ css . icon } " title="Run Transactions" aria-hidden="true"></i> `
var recordButton = yo `
var recordButton = yo `
< i class = "fa fa-floppy-o savetransaction ${css2.recorder} ${css.icon}"
< i class = "fa fa-floppy-o savetransaction ${css2.recorder} ${css.icon}"
onclick = $ { triggerRecordButton } title = "Save Transactions" aria - hidden = "true" >
onclick = $ { triggerRecordButton } title = "Save Transactions" aria - hidden = "true" >
< / i > `
< / i > `
var runButton = yo ` <i class="fa fa-play runtransaction ${ css2 . runTxs } ${ css . icon } " title="Run Transactions" aria-hidden="true"></i> `
function triggerRecordButton ( ) {
function triggerRecordButton ( ) {
var txJSON = JSON . stringify ( recorder . getAll ( ) , null , 2 )
var txJSON = JSON . stringify ( recorder . getAll ( ) , null , 2 )
var path = appAPI . currentPath ( )
var path = appAPI . currentPath ( )
modalDialogCustom . prompt ( null , 'save ran transactions to file (e.g. `scenario.json`). The file is going to be saved under ' + path , 'scenario.json' , input => {
modalDialogCustom . prompt ( null , 'Transactions will be saved in a file under ' + path , 'scenario.json' , input => {
var fileProvider = appAPI . fileProviderOf ( path )
var fileProvider = appAPI . fileProviderOf ( path )
if ( fileProvider ) {
if ( fileProvider ) {
var newFile = path + input
var newFile = path + input
@ -183,6 +229,7 @@ function makeRecorder (events, appAPI, appEvents, opts) {
}
}
} )
} )
}
}
runButton . onclick = ( ) => {
runButton . onclick = ( ) => {
var currentFile = appAPI . config . get ( 'currentFile' )
var currentFile = appAPI . config . get ( 'currentFile' )
appAPI . fileProviderOf ( currentFile ) . get ( currentFile , ( error , json ) => {
appAPI . fileProviderOf ( currentFile ) . get ( currentFile , ( error , json ) => {
@ -201,9 +248,10 @@ function makeRecorder (events, appAPI, appEvents, opts) {
return modalDialogCustom . alert ( 'Invalid Scenario File, please try again' )
return modalDialogCustom . alert ( 'Invalid Scenario File, please try again' )
}
}
if ( txArray . length ) {
if ( txArray . length ) {
var noInstancesText = self . _view . noInstancesText
if ( noInstancesText . parentNode ) { noInstancesText . parentNode . removeChild ( noInstancesText ) }
if ( noInstancesText . parentNode ) { noInstancesText . parentNode . removeChild ( noInstancesText ) }
recorder . run ( txArray , accounts , options , abis , linkReferences , opts . udapp , ( abi , address , contractName ) => {
recorder . run ( txArray , accounts , options , abis , linkReferences , ( abi , address , contractName ) => {
instanceContainer . appendChild ( opts . udappUI . renderInstanceFromABI ( abi , address , contractName ) )
self . _view . instanceContainer . appendChild ( opts . udappUI . renderInstanceFromABI ( abi , address , contractName ) )
} )
} )
}
}
} else {
} else {
@ -212,15 +260,18 @@ function makeRecorder (events, appAPI, appEvents, opts) {
}
}
} )
} )
}
}
return { recordButton , runButton }
return { recordButton , runButton }
}
}
/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CONTRACT ( deploy or access deployed )
CONTRACT ( deploy or access deployed )
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- * /
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- * /
function contractDropdown ( events , appAPI , appEvents , opts , instanceContainer ) {
function contractDropdown ( events , appAPI , appEvents , opts , self ) {
var instanceContainer = self . _view . instanceContainer
var instanceContainerTitle = self . _view . instanceContainerTitle
instanceContainer . appendChild ( instanceContainerTitle )
instanceContainer . appendChild ( instanceContainerTitle )
instanceContainer . appendChild ( noInstancesText )
instanceContainer . appendChild ( self . _view . noInstancesText )
var compFails = yo ` <i title="Contract compilation failed. Please check the compile tab for more information." class="fa fa-times-circle ${ css . errorIcon } " ></i> `
var compFails = yo ` <i title="Contract compilation failed. Please check the compile tab for more information." class="fa fa-times-circle ${ css . errorIcon } " ></i> `
appEvents . compiler . register ( 'compilationFinished' , function ( success , data , source ) {
appEvents . compiler . register ( 'compilationFinished' , function ( success , data , source ) {
getContractNames ( success , data )
getContractNames ( success , data )
@ -234,7 +285,6 @@ function contractDropdown (events, appAPI, appEvents, opts, instanceContainer) {
} )
} )
var atAddressButtonInput = yo ` <input class=" ${ css . input } ataddressinput" placeholder="Load contract from Address" title="atAddress" /> `
var atAddressButtonInput = yo ` <input class=" ${ css . input } ataddressinput" placeholder="Load contract from Address" title="atAddress" /> `
var selectContractNames = yo ` <select class=" ${ css . contractNames } " disabled></select> `
var selectContractNames = yo ` <select class=" ${ css . contractNames } " disabled></select> `
function getSelectedContract ( ) {
function getSelectedContract ( ) {
@ -248,6 +298,7 @@ function contractDropdown (events, appAPI, appEvents, opts, instanceContainer) {
return null
return null
}
}
appAPI . getSelectedContract = getSelectedContract
appAPI . getSelectedContract = getSelectedContract
var createPanel = yo ` <div class=" ${ css . button } "></div> `
var createPanel = yo ` <div class=" ${ css . button } "></div> `
var el = yo `
var el = yo `
@ -281,7 +332,7 @@ function contractDropdown (events, appAPI, appEvents, opts, instanceContainer) {
selectContractNames . addEventListener ( 'change' , setInputParamsPlaceHolder )
selectContractNames . addEventListener ( 'change' , setInputParamsPlaceHolder )
// ADD BUTTONS AT ADDRESS AND CREAT E
// DEPLOY INSTANC E
function createInstance ( args ) {
function createInstance ( args ) {
var selectedContract = getSelectedContract ( )
var selectedContract = getSelectedContract ( )
@ -304,7 +355,7 @@ function contractDropdown (events, appAPI, appEvents, opts, instanceContainer) {
return
return
}
}
}
}
if ( noInstancesText . parentNode ) { noInstancesText . parentNode . removeChild ( noInstancesText ) }
self . _view . noInstancesText . style . display = 'none'
var address = isVM ? txResult . result . createdAddress : txResult . result . contractAddress
var address = isVM ? txResult . result . createdAddress : txResult . result . contractAddress
instanceContainer . appendChild ( opts . udappUI . renderInstance ( selectedContract . contract . object , address , selectContractNames . value ) )
instanceContainer . appendChild ( opts . udappUI . renderInstance ( selectedContract . contract . object , address , selectContractNames . value ) )
} else {
} else {
@ -322,8 +373,9 @@ function contractDropdown (events, appAPI, appEvents, opts, instanceContainer) {
} )
} )
}
}
// ACCESS DEPLOYED INSTANCE
function loadFromAddress ( appAPI ) {
function loadFromAddress ( appAPI ) {
if ( noInstancesText . parentNode ) { noInstancesText . parentNode . removeChild ( noInstancesText ) }
self . _view . noInstancesText . style . display = 'none'
var contractNames = document . querySelector ( ` . ${ css . contractNames . classNames [ 0 ] } ` )
var contractNames = document . querySelector ( ` . ${ css . contractNames . classNames [ 0 ] } ` )
var address = atAddressButtonInput . value
var address = atAddressButtonInput . value
if ( ! ethJSUtil . isValidAddress ( address ) ) {
if ( ! ethJSUtil . isValidAddress ( address ) ) {
@ -365,12 +417,11 @@ function contractDropdown (events, appAPI, appEvents, opts, instanceContainer) {
return el
return el
}
}
/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
section SETTINGS : Environment , Account , Gas , Value
section SETTINGS : Environment , Account , Gas , Value
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- * /
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- * /
function settings ( container , appAPI , appEvents , opts ) {
function settings ( container , appAPI , appEvents , opts ) {
// SETTINGS HTML
// VARIABLES
var net = yo ` <span class= ${ css . network } ></span> `
var net = yo ` <span class= ${ css . network } ></span> `
const updateNetwork = ( ) => {
const updateNetwork = ( ) => {
executionContext . detectNetwork ( ( err , { id , name } = { } ) => {
executionContext . detectNetwork ( ( err , { id , name } = { } ) => {
@ -382,18 +433,6 @@ function settings (container, appAPI, appEvents, opts) {
}
}
} )
} )
}
}
setInterval ( updateNetwork , 5000 )
function newAccount ( ) {
opts . udapp . newAccount ( '' , ( error , address ) => {
if ( ! error ) {
container . querySelector ( '#txorigin' ) . appendChild ( yo ` <option value= ${ address } > ${ address } </option> ` )
addTooltip ( ` account ${ address } created ` )
} else {
addTooltip ( 'Cannot create an account: ' + error )
}
} )
}
var environmentEl = yo `
var environmentEl = yo `
< div class = "${css.crow}" >
< div class = "${css.crow}" >
< div id = "selectExEnv" class = "${css.col1_1}" >
< div id = "selectExEnv" class = "${css.col1_1}" >
@ -446,6 +485,7 @@ function settings (container, appAPI, appEvents, opts) {
< / s e l e c t >
< / s e l e c t >
< / d i v >
< / d i v >
`
`
// DOM ELEMENT
var el = yo `
var el = yo `
< div class = "${css.settings}" >
< div class = "${css.settings}" >
$ { environmentEl }
$ { environmentEl }
@ -453,15 +493,26 @@ function settings (container, appAPI, appEvents, opts) {
$ { gasPriceEl }
$ { gasPriceEl }
$ { valueEl }
$ { valueEl }
< / d i v >
< / d i v >
`
`
// HELPER FUNCTIONS AND EVENTS
// EVENTS
appEvents . udapp . register ( 'transactionExecuted' , ( error , from , to , data , lookupOnly , txResult ) => {
appEvents . udapp . register ( 'transactionExecuted' , ( error , from , to , data , lookupOnly , txResult ) => {
if ( error ) return
if ( error ) return
if ( ! lookupOnly ) el . querySelector ( '#value' ) . value = '0'
if ( ! lookupOnly ) el . querySelector ( '#value' ) . value = '0'
updateAccountBalances ( container , appAPI )
updateAccountBalances ( container , appAPI )
} )
} )
setInterval ( updateNetwork , 5000 )
function newAccount ( ) {
appAPI . newAccount ( '' , ( error , address ) => {
if ( ! error ) {
container . querySelector ( '#txorigin' ) . appendChild ( yo ` <option value= ${ address } > ${ address } </option> ` )
addTooltip ( ` account ${ address } created ` )
} else {
addTooltip ( 'Cannot create an account: ' + error )
}
} )
}
return el
return el
}
}