Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
B
baas-ide
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
JIRA
JIRA
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
guxukai
baas-ide
Commits
6a527284
Commit
6a527284
authored
Aug 08, 2017
by
yann300
Committed by
GitHub
Aug 08, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #665 from ethereum/compileRunTab9
Compile Run Tab - 9
parents
e3a83e42
38b8de71
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
126 additions
and
875 deletions
+126
-875
renderer.js
src/app/renderer.js
+7
-314
universal-dapp.js
src/universal-dapp.js
+119
-561
No files found.
src/app/renderer.js
View file @
6a527284
...
...
@@ -3,73 +3,18 @@
var
$
=
require
(
'jquery'
)
var
utils
=
require
(
'./utils'
)
var
helper
=
require
(
'../lib/helper.js'
)
// -------------- styling ----------------------
var
csjs
=
require
(
'csjs-inject'
)
var
styleGuide
=
require
(
'./style-guide'
)
var
styles
=
styleGuide
()
var
css
=
csjs
`
.col2 {
width: 70%;
float: left;
}
.col1 extends
${
styles
.
titleL
}
{
width: 30%;
float: left;
}
.toggleText {
text-decoration: underline;
margin-left: 2px;
font-size: .9em;
}
.toggle {
font-size: 1.1em;
color:
${
styles
.
colors
.
blue
}
;
margin: 1em;
cursor: pointer;
font-weight: 400;
display: flex;
align-items: center;
}
.toggle:hover {
opacity: .8;
}
`
// ----------------------------------------------
function
Renderer
(
appAPI
,
compilerEvent
)
{
/**
* After refactor, the renderer is only used to render error/warning
* TODO: This don't need to be an object anymore. Simplify and just export the renderError function.
*
*/
function
Renderer
(
appAPI
)
{
this
.
appAPI
=
appAPI
var
self
=
this
compilerEvent
.
register
(
'compilationFinished'
,
this
,
function
(
success
,
data
,
source
)
{
$
(
'#output'
).
empty
()
if
(
success
)
{
self
.
contracts
(
data
,
source
)
$
(
'#header #menu .envView'
).
css
(
'color'
,
''
)
}
else
{
// envView is the `Contract` tab, as a refactor the entire envView should have his own module
$
(
'#header #menu .envView'
).
css
(
'color'
,
'#FF8B8B'
)
}
// NOTE: still need to display as there might be warnings
if
(
data
[
'error'
])
{
self
.
error
(
data
[
'error'
])
}
if
(
data
[
'errors'
])
{
data
[
'errors'
].
forEach
(
function
(
err
)
{
self
.
error
(
err
)
})
}
})
setInterval
(()
=>
{
updateAccountBalances
(
self
,
appAPI
)
},
1000
)
}
Renderer
.
prototype
.
clear
=
function
()
{
$
(
'#output'
).
empty
()
}
Renderer
.
prototype
.
error
=
function
(
message
,
container
,
options
)
{
if
(
container
===
undefined
)
return
var
self
=
this
var
opt
=
options
||
{}
if
(
!
opt
.
type
)
{
...
...
@@ -82,9 +27,6 @@ Renderer.prototype.error = function (message, container, options) {
$pre
=
$
(
opt
.
useSpan
?
'<span />'
:
'<pre />'
).
text
(
message
)
}
var
$error
=
$
(
'<div class="sol '
+
opt
.
type
+
'"><div class="close"><i class="fa fa-close"></i></div></div>'
).
prepend
(
$pre
)
if
(
container
===
undefined
)
{
container
=
$
(
'#output'
)
}
container
.
append
(
$error
)
var
err
=
message
.
match
(
/^
([^
:
]
*
)
:
([
0-9
]
*
)
:
(([
0-9
]
*
)
:
)?
/
)
if
(
err
)
{
...
...
@@ -110,253 +52,4 @@ Renderer.prototype.error = function (message, container, options) {
})
}
Renderer
.
prototype
.
contracts
=
function
(
data
,
source
)
{
var
self
=
this
var
retrieveMetadataHash
=
function
(
bytecode
)
{
var
match
=
/a165627a7a72305820
([
0-9a-f
]{64})
0029$/
.
exec
(
bytecode
)
if
(
match
)
{
return
match
[
1
]
}
}
var
udappContracts
=
[]
for
(
var
contractName
in
data
.
contracts
)
{
var
contract
=
data
.
contracts
[
contractName
]
udappContracts
.
push
({
name
:
contractName
,
interface
:
contract
[
'interface'
],
bytecode
:
contract
.
bytecode
,
metadata
:
contract
.
metadata
,
metadataHash
:
contract
.
bytecode
&&
retrieveMetadataHash
(
contract
.
bytecode
)
})
}
var
tableRowItems
=
function
(
first
,
second
,
cls
)
{
second
.
get
(
0
).
classList
.
add
(
styles
.
textBoxL
)
// replace <pre> styling with textBoxL
return
$
(
'<div class="crow"/>'
)
.
addClass
(
cls
)
.
append
(
$
(
`<div class="
${
css
.
col1
}
">`
).
append
(
first
))
.
append
(
$
(
`<div class="
${
css
.
col2
}
">`
).
append
(
second
))
}
var
tableRow
=
function
(
description
,
data
)
{
return
tableRowItems
(
$
(
'<span/>'
).
text
(
description
),
$
(
`<input class="
${
css
.
col2
}
${
styles
.
textBoxL
}
" readonly="readonly"/>`
).
val
(
data
))
}
var
preRow
=
function
(
description
,
data
)
{
return
tableRowItems
(
$
(
'<span/>'
).
text
(
description
),
$
(
'<pre/>'
).
text
(
data
)
)
}
var
formatAssemblyText
=
function
(
asm
,
prefix
,
source
)
{
if
(
typeof
asm
===
typeof
''
||
asm
===
null
||
asm
===
undefined
)
{
return
prefix
+
asm
+
'
\
n'
}
var
text
=
prefix
+
'.code
\
n'
$
.
each
(
asm
[
'.code'
],
function
(
i
,
item
)
{
var
v
=
item
.
value
===
undefined
?
''
:
item
.
value
var
src
=
''
if
(
item
.
begin
!==
undefined
&&
item
.
end
!==
undefined
)
{
src
=
source
.
slice
(
item
.
begin
,
item
.
end
).
replace
(
'
\
n'
,
'
\\
n'
,
'g'
)
}
if
(
src
.
length
>
30
)
{
src
=
src
.
slice
(
0
,
30
)
+
'...'
}
if
(
item
.
name
!==
'tag'
)
{
text
+=
' '
}
text
+=
prefix
+
item
.
name
+
' '
+
v
+
'
\
t
\
t
\
t'
+
src
+
'
\
n'
})
text
+=
prefix
+
'.data
\
n'
if
(
asm
[
'.data'
])
{
$
.
each
(
asm
[
'.data'
],
function
(
i
,
item
)
{
text
+=
' '
+
prefix
+
''
+
i
+
':
\
n'
text
+=
formatAssemblyText
(
item
,
prefix
+
' '
,
source
)
})
}
return
text
}
var
getConstructorInterface
=
function
(
abi
)
{
var
funABI
=
{
'name'
:
''
,
'inputs'
:
[],
'type'
:
'constructor'
,
'outputs'
:
[]
}
for
(
var
i
=
0
;
i
<
abi
.
length
;
i
++
)
{
if
(
abi
[
i
].
type
===
'constructor'
)
{
funABI
.
inputs
=
abi
[
i
].
inputs
||
[]
break
}
}
return
funABI
}
var
gethDeploy
=
function
(
contractName
,
jsonInterface
,
bytecode
)
{
var
code
=
''
var
funABI
=
getConstructorInterface
(
JSON
.
parse
(
jsonInterface
))
funABI
.
inputs
.
forEach
(
function
(
inp
)
{
code
+=
'var '
+
inp
.
name
+
' = /* var of type '
+
inp
.
type
+
' here */ ;
\
n'
})
contractName
=
contractName
.
replace
(
/
[
:.
/]
/g
,
'_'
)
code
+=
'var '
+
contractName
+
'Contract = web3.eth.contract('
+
jsonInterface
.
replace
(
'
\
n'
,
''
)
+
');'
+
'
\
nvar '
+
contractName
+
' = '
+
contractName
+
'Contract.new('
funABI
.
inputs
.
forEach
(
function
(
inp
)
{
code
+=
'
\
n '
+
inp
.
name
+
','
})
code
+=
'
\
n {'
+
'
\
n from: web3.eth.accounts[0], '
+
"
\
n data: '0x"
+
bytecode
+
"', "
+
"
\
n gas: '"
+
self
.
appAPI
.
currentblockGasLimit
()
+
"'"
+
'
\
n }, function (e, contract){'
+
'
\
n console.log(e, contract);'
+
"
\
n if (typeof contract.address !== 'undefined') {"
+
"
\
n console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);"
+
'
\
n }'
+
'
\
n })'
return
code
}
var
formatGasEstimates
=
function
(
data
)
{
// FIXME: the whole gasEstimates object should be nil instead
if
(
data
.
creation
===
undefined
&&
data
.
external
===
undefined
&&
data
.
internal
===
undefined
)
{
return
}
var
gasToText
=
function
(
g
)
{
return
g
===
null
?
'unknown'
:
g
}
var
text
=
''
var
fun
if
(
'creation'
in
data
)
{
text
+=
'Creation: '
+
gasToText
(
data
.
creation
[
0
])
+
' + '
+
gasToText
(
data
.
creation
[
1
])
+
'
\
n'
}
if
(
'external'
in
data
)
{
text
+=
'External:
\
n'
for
(
fun
in
data
.
external
)
{
text
+=
' '
+
fun
+
': '
+
gasToText
(
data
.
external
[
fun
])
+
'
\
n'
}
}
if
(
'internal'
in
data
)
{
text
+=
'Internal:
\
n'
for
(
fun
in
data
.
internal
)
{
text
+=
' '
+
fun
+
': '
+
gasToText
(
data
.
internal
[
fun
])
+
'
\
n'
}
}
return
text
}
var
detailsOpen
=
{}
var
getDetails
=
function
(
contract
,
source
,
contractName
)
{
var
button
=
$
(
`<div class="
${
css
.
toggle
}
"><i class="fa fa-info-circle" aria-hidden="true"></i><div class="
${
css
.
toggleText
}
">Contract details (bytecode, interface etc.)</div></div>`
)
var
details
=
$
(
'<div style="display: none;"/>'
)
if
(
contract
.
bytecode
)
{
details
.
append
(
preRow
(
'Bytecode'
,
contract
.
bytecode
))
}
details
.
append
(
preRow
(
'Interface'
,
contract
[
'interface'
]))
if
(
contract
.
bytecode
)
{
details
.
append
(
preRow
(
'Web3 deploy'
,
gethDeploy
(
contractName
.
toLowerCase
(),
contract
[
'interface'
],
contract
.
bytecode
),
'deploy'
))
// check if there's a metadata hash appended
var
metadataHash
=
retrieveMetadataHash
(
contract
.
bytecode
)
if
(
metadataHash
)
{
details
.
append
(
preRow
(
'Metadata location'
,
'bzzr://'
+
metadataHash
))
}
}
if
(
contract
.
metadata
)
{
details
.
append
(
preRow
(
'Metadata'
,
contract
.
metadata
))
}
var
funHashes
=
''
for
(
var
fun
in
contract
.
functionHashes
)
{
funHashes
+=
contract
.
functionHashes
[
fun
]
+
' '
+
fun
+
'
\
n'
}
if
(
funHashes
.
length
>
0
)
{
details
.
append
(
preRow
(
'Functions'
,
funHashes
))
}
var
gasEstimates
=
formatGasEstimates
(
contract
.
gasEstimates
)
if
(
gasEstimates
)
{
details
.
append
(
preRow
(
'Gas Estimates'
,
gasEstimates
))
}
if
(
contract
.
runtimeBytecode
&&
contract
.
runtimeBytecode
.
length
>
0
)
{
details
.
append
(
tableRow
(
'Runtime Bytecode'
,
contract
.
runtimeBytecode
))
}
if
(
contract
.
opcodes
!==
undefined
&&
contract
.
opcodes
!==
''
)
{
details
.
append
(
tableRow
(
'Opcodes'
,
contract
.
opcodes
))
}
if
(
contract
.
assembly
!==
null
)
{
details
.
append
(
preRow
(
'Assembly'
,
formatAssemblyText
(
contract
.
assembly
,
''
,
source
)))
}
button
.
click
(
function
()
{
detailsOpen
[
contractName
]
=
!
detailsOpen
[
contractName
]
details
.
toggle
()
})
if
(
detailsOpen
[
contractName
])
{
details
.
show
()
}
return
$
(
'<div class="contractDetails"/>'
).
append
(
button
).
append
(
details
)
}
var
renderOutputModifier
=
function
(
contractName
,
$contractOutput
)
{
var
contract
=
data
.
contracts
[
contractName
]
var
ctrSource
=
self
.
appAPI
.
currentCompiledSourceCode
()
if
(
ctrSource
)
{
$contractOutput
.
append
(
getDetails
(
contract
,
ctrSource
,
contractName
))
}
return
$contractOutput
}
this
.
appAPI
.
resetDapp
(
udappContracts
,
renderOutputModifier
)
var
$contractOutput
=
this
.
appAPI
.
renderDapp
()
var
$txOrigin
=
$
(
'#txorigin'
)
this
.
appAPI
.
getAccounts
(
function
(
err
,
accounts
)
{
if
(
err
)
{
self
.
error
(
err
.
message
)
}
if
(
accounts
&&
accounts
[
0
])
{
$txOrigin
.
empty
()
for
(
var
a
in
accounts
)
{
$txOrigin
.
append
(
$
(
'<option />'
).
val
(
accounts
[
a
]).
text
(
accounts
[
a
]))
}
$txOrigin
.
val
(
accounts
[
0
])
}
else
{
$txOrigin
.
val
(
'unknown'
)
}
})
$
(
'#output'
).
append
(
$contractOutput
)
$
(
'.'
+
css
.
col2
+
' input,textarea'
).
click
(
function
()
{
this
.
select
()
})
}
function
updateAccountBalances
(
self
,
appAPI
)
{
var
accounts
=
$
(
'#txorigin'
).
children
(
'option'
)
accounts
.
each
(
function
(
index
,
value
)
{
(
function
(
acc
)
{
appAPI
.
getBalance
(
accounts
[
acc
].
value
,
function
(
err
,
res
)
{
if
(
!
err
)
{
accounts
[
acc
].
innerText
=
helper
.
shortenAddress
(
accounts
[
acc
].
value
,
res
)
}
})
})(
index
)
})
}
module
.
exports
=
Renderer
src/universal-dapp.js
View file @
6a527284
/* global
promp
t */
/* global
aler
t */
'use strict'
var
$
=
require
(
'jquery'
)
...
...
@@ -9,8 +9,11 @@ var EventManager = require('ethereum-remix').lib.EventManager
var
crypto
=
require
(
'crypto'
)
var
async
=
require
(
'async'
)
var
TxRunner
=
require
(
'./app/txRunner'
)
var
helper
=
require
(
'./lib/helper'
)
var
yo
=
require
(
'yo-yo'
)
var
txFormat
=
require
(
'./app/execution/txFormat'
)
var
txHelper
=
require
(
'./app/execution/txHelper'
)
var
txExecution
=
require
(
'./app/execution/txExecution'
)
var
helper
=
require
(
'./lib/helper'
)
// copy to copyToClipboard
const
copy
=
require
(
'clipboard-copy'
)
...
...
@@ -21,88 +24,73 @@ var styleGuide = require('./app/style-guide')
var
styles
=
styleGuide
()
var
css
=
csjs
`
html {
overflow: hidden;
}
.options {
float: left;
padding: 0.7em 0.3em;
font-size: 0.9em;
cursor: pointer;
background-color: transparent;
margin-right: 0.5em;
font-size: 1em;
}
.title extends
${
styles
.
titleBox
}
{
cursor: pointer;
background-color:
${
styles
.
colors
.
violet
}
;
justify-content: flex-start;
min-width: 400px;
}
.contract .title:before {
margin-right: 30%;
margin-left: 5%;
content: "\\25BE";
}
.contract.hidesub .title:before {
margin-right: 30%;
margin-left: 5%;
content: "\\25B8";
}
.contract.hidesub {
padding-bottom: 0;
margin: 0;
}
.contract.hidesub > *:not(.title) {
display: none;
}
.size {
margin-left: 20%;
.instanceTitleContainer {
display: flex;
align-items: center;
}
`
var
cssInstance
=
csjs
`
.title {
.title extends
${
styles
.
dropdown
}
{
display: flex;
justify-content: space-around;
min-width: 400px;
align-items: center;
margin-bottom: 1em;
padding: .3em;
font-size: .95em;
cursor: pointer;
background-color:
${
styles
.
colors
.
violet
}
;
border: 2px dotted
${
styles
.
colors
.
blue
}
;
border-radius: 5px;
justify-content: space-between;
height: 32px;
font-size: 11px;
width: 100%;
overflow: hidden;
word-break: break-word;
line-height: initial;
font-weight: bold;
background-color:
${
styles
.
colors
.
white
}
;
}
.titleText {
margin-right: 1em;
word-break: break-all;
word-break: break-word;
min-width: 230px;
}
.instance extends
${
styles
.
displayBox
}
{
padding: 10px 15px 6px 15px;
}
.instance .title:before {
content: "\\25BE";
margin-right: .5em;
margin-left: .5em;
margin-right: 5%;
}
.instance.hidesub .title:before {
content: "\\25B8";
margin-right: .5em;
margin-left: .5em;
margin-right: 5%;
}
.instance.hidesub {
padding-bottom: 0;
margin: 0;
}
.instance.hidesub > *
:not(.title)
{
.instance.hidesub > * {
display: none;
}
.copy extends
${
styles
.
button
}
{
border: 1px dotted
${
styles
.
colors
.
grey
}
;
padding: 0 .3em;
font-weight: bold;
.instance.hidesub .title {
display: flex;
}
.copy {
font-size: 13px;
cursor: pointer;
opacity: 0.8;
margin-left: 3%;
color:
${
styles
.
colors
.
black
}
;
opacity: .5;
}
.copy:hover{
opacity: .7;
opacity: 1;
}
.buttonsContainer {
margin-top: 2%;
display: flex;
}
.instanceButton {}
.closeIcon {
font-size: 10px;
position: relative;
top: -5px;
right: -2px;
}
.udappClose {
margin-left: 3%;
align-self: center;
}
`
...
...
@@ -114,12 +102,10 @@ function UniversalDApp (executionContext, options) {
var
self
=
this
self
.
options
=
options
||
{}
self
.
$el
=
$
(
'<div class="udapp" />'
)
self
.
el
=
yo
`<div class="udapp"></div>`
self
.
personalMode
=
self
.
options
.
personalMode
||
false
self
.
contracts
self
.
transactionContextAPI
var
defaultRenderOutputModifier
=
function
(
name
,
content
)
{
return
content
}
self
.
renderOutputModifier
=
defaultRenderOutputModifier
self
.
web3
=
executionContext
.
web3
()
self
.
vm
=
executionContext
.
vm
()
self
.
executionContext
=
executionContext
...
...
@@ -132,11 +118,10 @@ function UniversalDApp (executionContext, options) {
})
}
UniversalDApp
.
prototype
.
reset
=
function
(
contracts
,
transactionContextAPI
,
renderer
)
{
this
.
$el
.
empty
()
UniversalDApp
.
prototype
.
reset
=
function
(
contracts
,
transactionContextAPI
)
{
this
.
el
.
innerHTML
=
''
this
.
contracts
=
contracts
this
.
transactionContextAPI
=
transactionContextAPI
this
.
renderOutputModifier
=
renderer
this
.
accounts
=
{}
if
(
this
.
executionContext
.
isVM
())
{
this
.
_addAccount
(
'3cd7232cd6f3fc66a57a6bedc1a8ed6c228fff0a327e169c2bcc5e869ed49511'
)
...
...
@@ -234,139 +219,29 @@ UniversalDApp.prototype.getBalance = function (address, cb) {
}
}
UniversalDApp
.
prototype
.
render
=
function
()
{
var
self
=
this
// NOTE: don't display anything if there are no contracts to display
if
(
self
.
contracts
.
length
===
0
)
{
return
self
.
$el
}
var
$legend
=
$
(
'<div class="legend" />'
)
.
append
(
$
(
'<div class="publish"/>'
).
text
(
'Publish'
))
.
append
(
$
(
'<div class="attach"/>'
).
text
(
'Attach'
))
.
append
(
$
(
'<div class="transact"/>'
).
text
(
'Transact'
))
.
append
(
$
(
'<div class="payable"/>'
).
text
(
'Transact(Payable)'
))
.
append
(
$
(
'<div class="call"/>'
).
text
(
'Call'
))
self
.
$el
.
append
(
$legend
)
for
(
var
c
in
self
.
contracts
)
{
var
$contractEl
=
$
(
`<div class="contract
${
css
.
contract
}
"/>`
)
if
(
self
.
contracts
[
c
].
address
)
{
self
.
getInstanceInterface
(
self
.
contracts
[
c
],
self
.
contracts
[
c
].
address
,
$contractEl
)
}
else
{
var
$title
=
$
(
`<span class="
${
css
.
title
}
"/>`
).
text
(
self
.
contracts
[
c
].
name
)
$title
.
click
(
function
(
ev
)
{
$
(
this
).
closest
(
`.
${
css
.
contract
}
`
).
toggleClass
(
`
${
css
.
hidesub
}
`
)
})
if
(
self
.
contracts
[
c
].
bytecode
)
{
$title
.
append
(
$
(
`<div class="
${
css
.
size
}
"></div>`
).
text
((
self
.
contracts
[
c
].
bytecode
.
length
/
2
)
+
' bytes'
))
}
$contractEl
.
append
(
$title
).
append
(
self
.
getCreateInterface
(
$contractEl
,
self
.
contracts
[
c
]))
}
self
.
$el
.
append
(
self
.
renderOutputModifier
(
self
.
contracts
[
c
].
name
,
$contractEl
))
}
return
self
.
$el
}
UniversalDApp
.
prototype
.
getContractByName
=
function
(
contractName
)
{
var
self
=
this
for
(
var
c
in
self
.
contracts
)
{
if
(
self
.
contracts
[
c
].
name
===
contractName
)
{
return
self
.
contracts
[
c
]
}
}
return
null
}
UniversalDApp
.
prototype
.
getCreateInterface
=
function
(
$container
,
contract
)
{
function
remove
()
{
self
.
$el
.
remove
()
}
var
self
=
this
var
createInterface
=
yo
`<div class="create"></div>`
if
(
self
.
options
.
removable
)
{
var
close
=
yo
`<div class="udapp-close" onclick=
${
remove
}
></div>`
createInterface
.
appendChild
(
close
)
}
var
$publishButton
=
$
(
`<button class="publishContract"/>`
).
text
(
'Publish'
).
click
(
function
()
{
self
.
event
.
trigger
(
'publishContract'
,
[
contract
])
})
createInterface
.
appendChild
(
$publishButton
.
get
(
0
))
var
$atButton
=
$
(
'<button class="atAddress"/>'
).
text
(
'At Address'
).
click
(
function
()
{
self
.
clickContractAt
(
self
,
$container
.
find
(
'.createContract'
),
contract
)
})
createInterface
.
appendChild
(
$atButton
.
get
(
0
))
var
$newButton
=
self
.
getInstanceInterface
(
contract
)
if
(
!
$newButton
)
{
return
createInterface
}
createInterface
.
appendChild
(
$newButton
)
// Only display creation interface for non-abstract contracts.
// FIXME: maybe have a flag for this in the JSON?
// FIXME: maybe fix getInstanceInterface() below for this case
if
(
contract
.
bytecode
.
length
===
0
)
{
var
$createButton
=
$newButton
.
querySelector
(
'.constructor .call'
)
// NOTE: we must show the button to have CSS properly lined up
$createButton
.
innerText
=
'Create'
$createButton
.
setAttribute
(
'disabled'
,
'disabled'
)
$createButton
.
setAttribute
(
'title'
,
'This contract does not implement all functions and thus cannot be created.'
)
}
if
((
contract
.
metadata
===
undefined
)
||
(
contract
.
metadata
.
length
===
0
))
{
$publishButton
.
attr
(
'disabled'
,
'disabled'
)
$publishButton
.
attr
(
'title'
,
'This contract does not implement all functions and thus cannot be published.'
)
}
return
createInterface
}
UniversalDApp
.
prototype
.
getInstanceInterface
=
function
(
contract
,
address
,
$target
)
{
var
self
=
this
var
abi
=
JSON
.
parse
(
contract
.
interface
).
sort
(
function
(
a
,
b
)
{
if
(
a
.
name
>
b
.
name
)
{
return
-
1
}
else
{
return
1
}
}).
sort
(
function
(
a
,
b
)
{
if
(
a
.
constant
===
true
)
{
return
-
1
}
else
{
return
1
}
})
var
funABI
=
self
.
getConstructorInterface
(
abi
)
if
(
!
funABI
)
{
return
}
var
createInterface
=
yo
`<div class="createContract"></div>`
var
appendFunctions
=
function
(
address
,
$el
)
{
if
(
$el
)
$el
=
$el
.
get
(
0
)
// TODO this function was named before "appendChild".
// this will render an instance: contract name, contract address, and all the public functions
// basically this has to be called for the "atAddress" (line 393) and when a contract creation succeed
// this returns a DOM element
UniversalDApp
.
prototype
.
renderInstance
=
function
(
contract
,
address
,
contractName
)
{
function
remove
()
{
$instance
.
remove
()
}
var
$instance
=
$
(
`<div class="instance
${
cssInstance
.
instance
}
"/>`
)
if
(
self
.
options
.
removable_instances
)
{
var
close
=
yo
`<div class="udapp-close" onclick=
${
remove
}
></div>`
$instance
.
get
(
0
).
appendChild
(
close
)
}
var
context
=
self
.
executionContext
.
isVM
()
?
'memory'
:
'blockchain'
var
$instance
=
$
(
`<div class="instance
${
css
.
instance
}
"/>`
)
var
context
=
this
.
executionContext
.
isVM
()
?
'memory'
:
'blockchain'
address
=
(
address
.
slice
(
0
,
2
)
===
'0x'
?
''
:
'0x'
)
+
address
.
toString
(
'hex'
)
var
shortAddress
=
helper
.
shortenAddress
(
address
)
var
title
=
yo
`
<div class="
${
cssInstance
.
title
}
" onclick=
${
toggleClass
}
>
<div class="
${
cssInstance
.
titleText
}
">
${
contract
.
name
}
at
${
shortAddress
}
(
${
context
}
) </div>
<div class="
${
cssInstance
.
copy
}
" onclick=
${
copyToClipboard
}
> <i class="fa fa-clipboard" aria-hidden="true"></i> Copy address </div>
</div>
`
var
title
=
yo
`<div class="
${
css
.
title
}
" onclick=
${
toggleClass
}
>
<div class="
${
css
.
titleText
}
">
${
contractName
}
at
${
shortAddress
}
(
${
context
}
) </div>
<i class="fa fa-clipboard
${
css
.
copy
}
" aria-hidden="true" onclick=
${
copyToClipboard
}
title='Copy to clipboard'></i>
</div>`
if
(
this
.
options
.
removable_instances
)
{
var
close
=
yo
`<div class="
${
css
.
udappClose
}
" onclick=
${
remove
}
><i class="
${
css
.
closeIcon
}
fa fa-close" aria-hidden="true"></i></div>`
title
.
appendChild
(
close
)
}
function
toggleClass
()
{
$instance
.
toggleClass
(
`
${
cssInstance
.
hidesub
}
`
)
$instance
.
toggleClass
(
`
${
css
.
hidesub
}
`
)
}
function
copyToClipboard
(
event
)
{
...
...
@@ -383,7 +258,7 @@ UniversalDApp.prototype.getInstanceInterface = function (contract, address, $tar
var
$event
=
$
(
'<div class="event" />'
)
var
close
=
yo
`<div class="udapp-close" onclick=
${
remove
}
></div>`
var
close
=
yo
`<div class="udapp-close" onclick=
${
remove
}
><i class="
${
css
.
closeIcon
}
fa fa-close" aria-hidden="true"></i
></div>`
function
remove
()
{
$event
.
remove
()
}
$event
.
append
(
$
(
'<span class="name"/>'
).
text
(
response
.
event
))
...
...
@@ -392,10 +267,10 @@ UniversalDApp.prototype.getInstanceInterface = function (contract, address, $tar
$events
.
append
(
$event
)
}
if
(
self
.
executionContext
.
isVM
())
{
var
abi
=
txHelper
.
sortAbiFunction
(
contract
)
if
(
this
.
executionContext
.
isVM
())
{
// FIXME: support indexed events
var
eventABI
=
{}
$
.
each
(
abi
,
function
(
i
,
funABI
)
{
if
(
funABI
.
type
!==
'event'
)
{
return
...
...
@@ -405,7 +280,7 @@ UniversalDApp.prototype.getInstanceInterface = function (contract, address, $tar
eventABI
[
hash
.
toString
(
'hex'
)]
=
{
event
:
funABI
.
name
,
inputs
:
funABI
.
inputs
}
})
self
.
vm
.
on
(
'afterTx'
,
function
(
response
)
{
this
.
vm
.
on
(
'afterTx'
,
function
(
response
)
{
for
(
var
i
in
response
.
vm
.
logs
)
{
// [address, topics, mem]
var
log
=
response
.
vm
.
logs
[
i
]
...
...
@@ -428,415 +303,98 @@ UniversalDApp.prototype.getInstanceInterface = function (contract, address, $tar
}
})
}
else
{
var
eventFilter
=
self
.
web3
.
eth
.
contract
(
abi
).
at
(
address
).
allEvents
()
var
eventFilter
=
this
.
web3
.
eth
.
contract
(
abi
).
at
(
address
).
allEvents
()
eventFilter
.
watch
(
parseLogs
)
}
$instance
.
get
(
0
).
appendChild
(
title
)
// Add the fallback function
var
fallback
=
self
.
getFallbackInterface
(
abi
)
var
fallback
=
txHelper
.
getFallbackInterface
(
abi
)
if
(
fallback
)
{
$instance
.
append
(
self
.
getCallButton
({
abi
:
fallback
,
encode
:
function
(
args
)
{
return
''
},
address
:
address
$instance
.
append
(
this
.
getCallButton
({
funABI
:
fallback
,
address
:
address
,
contractAbi
:
abi
}))
}
$
.
each
(
abi
,
function
(
i
,
funABI
)
{
$
.
each
(
abi
,
(
i
,
funABI
)
=>
{
if
(
funABI
.
type
!==
'function'
)
{
return
}
// @todo getData cannot be used with overloaded functions
$instance
.
append
(
self
.
getCallButton
({
abi
:
funABI
,
encode
:
function
(
args
)
{
var
types
=
[]
for
(
var
i
=
0
;
i
<
funABI
.
inputs
.
length
;
i
++
)
{
types
.
push
(
funABI
.
inputs
[
i
].
type
)
}
return
Buffer
.
concat
([
ethJSABI
.
methodID
(
funABI
.
name
,
types
),
ethJSABI
.
rawEncode
(
types
,
args
)
]).
toString
(
'hex'
)
},
address
:
address
$instance
.
append
(
this
.
getCallButton
({
funABI
:
funABI
,
address
:
address
,
contractAbi
:
abi
}))
})
$el
=
$el
||
createInterface
$el
.
appendChild
(
$instance
.
append
(
$events
).
get
(
0
))
}
if
(
!
address
||
!
$target
)
{
createInterface
.
appendChild
(
self
.
getCallButton
({
abi
:
funABI
,
encode
:
function
(
args
)
{
var
types
=
[]
for
(
var
i
=
0
;
i
<
funABI
.
inputs
.
length
;
i
++
)
{
types
.
push
(
funABI
.
inputs
[
i
].
type
)
}
// NOTE: the caller will concatenate the bytecode and this
// it could be done here too for consistency
return
ethJSABI
.
rawEncode
(
types
,
args
).
toString
(
'hex'
)
},
contractName
:
contract
.
name
,
bytecode
:
contract
.
bytecode
,
appendFunctions
:
appendFunctions
}).
get
(
0
))
}
else
{
appendFunctions
(
address
,
$target
)
}
return
createInterface
}
UniversalDApp
.
prototype
.
getConstructorInterface
=
function
(
abi
)
{
for
(
var
i
=
0
;
i
<
abi
.
length
;
i
++
)
{
if
(
abi
[
i
].
type
===
'constructor'
)
{
return
abi
[
i
]
}
}
return
{
'type'
:
'constructor'
,
'payable'
:
false
,
'inputs'
:
[]
}
}
UniversalDApp
.
prototype
.
getFallbackInterface
=
function
(
abi
)
{
for
(
var
i
=
0
;
i
<
abi
.
length
;
i
++
)
{
if
(
abi
[
i
].
type
===
'fallback'
)
{
return
abi
[
i
]
}
}
$instance
.
append
(
$events
)
return
$instance
.
get
(
0
)
}
// TODO this is used by renderInstance when a new instance is displayed.
// this returns a DOM element.
UniversalDApp
.
prototype
.
getCallButton
=
function
(
args
)
{
var
self
=
this
// args.abi, args.encode, args.bytecode [constr only], args.address [fun only]
// args.contractName [constr only], args.appendFunctions [constr only]
var
isConstructor
=
args
.
bytecode
!==
undefined
var
lookupOnly
=
(
args
.
abi
.
constant
&&
!
isConstructor
)
// args.funABI, args.address [fun only]
// args.contractName [constr only]
var
lookupOnly
=
args
.
funABI
.
constant
var
inputs
=
''
if
(
args
.
abi
.
inputs
)
{
$
.
each
(
args
.
abi
.
inputs
,
function
(
i
,
inp
)
{
if
(
inputs
!==
''
)
{
inputs
+=
', '
}
inputs
+=
inp
.
type
+
' '
+
inp
.
name
})
if
(
args
.
funABI
.
inputs
)
{
inputs
=
txHelper
.
inputParametersDeclarationToString
(
args
.
funABI
.
inputs
)
}
var
inputField
=
$
(
'<input/>'
).
attr
(
'placeholder'
,
inputs
).
attr
(
'title'
,
inputs
)
var
$outputOverride
=
$
(
'<div class="value" />'
)
var
outputSpan
=
$
(
'<div class="output"/>'
)
var
getReturnOutput
=
function
(
result
)
{
var
returnName
=
lookupOnly
?
'Value'
:
'Result'
var
returnCls
=
lookupOnly
?
'value'
:
'returned'
return
$
(
'<div class="'
+
returnCls
+
'">'
).
html
(
'<strong>'
+
returnName
+
':</strong> '
+
JSON
.
stringify
(
result
,
null
,
2
))
}
var
getDebugTransaction
=
function
(
result
)
{
var
$debugTx
=
$
(
'<div class="debugTx">'
)
var
$button
=
$
(
'<button title="Launch Debugger" class="debug"><i class="fa fa-bug"></i> Launch debugger </button>'
)
$button
.
click
(
function
()
{
self
.
event
.
trigger
(
'debugRequested'
,
[
result
])
})
$debugTx
.
append
(
$button
)
return
$debugTx
}
var
getDebugCall
=
function
(
result
)
{
var
$debugTx
=
$
(
'<div class="debugCall">'
)
var
$button
=
$
(
'<button title="Launch Debugger" class="debug"><i class="fa fa-bug"></i> Launch debugger </button>'
)
$button
.
click
(
function
()
{
self
.
event
.
trigger
(
'debugRequested'
,
[
result
])
})
$debugTx
.
append
(
$button
)
return
$debugTx
}
var
getGasUsedOutput
=
function
(
result
,
vmResult
)
{
var
$gasUsed
=
$
(
'<div class="gasUsed"></div>'
)
var
caveat
=
lookupOnly
?
'<em>(<span class="caveat" title="Cost only applies when called by a contract">caveat</span>)</em>'
:
''
var
gas
if
(
result
.
gasUsed
)
{
gas
=
result
.
gasUsed
.
toString
(
10
)
$gasUsed
.
html
(
'<strong>Transaction cost:</strong> '
+
gas
+
' gas. '
+
caveat
)
}
if
(
vmResult
&&
vmResult
.
gasUsed
)
{
var
$callGasUsed
=
$
(
'<div class="gasUsed">'
)
gas
=
vmResult
.
gasUsed
.
toString
(
10
)
$callGasUsed
.
append
(
'<strong>Execution cost:</strong> '
+
gas
+
' gas.'
)
$gasUsed
.
append
(
$callGasUsed
)
}
return
$gasUsed
}
var
getDecodedOutput
=
function
(
result
)
{
var
$decoded
if
(
Array
.
isArray
(
result
))
{
$decoded
=
$
(
'<ol>'
)
for
(
var
i
=
0
;
i
<
result
.
length
;
i
++
)
{
$decoded
.
append
(
$
(
'<li>'
).
text
(
result
[
i
]))
}
}
else
{
$decoded
=
result
}
return
$
(
'<div class="decoded">'
).
html
(
'<strong>Decoded:</strong> '
).
append
(
$decoded
)
}
var
getOutput
=
function
()
{
var
$result
=
$
(
'<div class="result" />'
)
var
close
=
yo
`<div class="udapp-close" onclick=
${
remove
}
></div>`
function
remove
()
{
$result
.
remove
()
}
$result
.
get
(
0
).
appendChild
(
close
)
return
$result
}
var
clearOutput
=
function
(
$result
)
{
$
(
':not(.udapp-close)'
,
$result
).
remove
()
}
var
replaceOutput
=
function
(
$result
,
message
)
{
clearOutput
(
$result
)
$result
.
append
(
message
)
}
var
handleCallButtonClick
=
function
(
ev
,
$result
)
{
if
(
!
$result
)
{
$result
=
getOutput
()
if
(
lookupOnly
&&
!
inputs
.
length
)
{
$outputOverride
.
empty
().
append
(
$result
)
}
else
{
outputSpan
.
append
(
$result
)
}
}
var
funArgs
=
''
try
{
funArgs
=
$
.
parseJSON
(
'['
+
inputField
.
val
()
+
']'
)
}
catch
(
e
)
{
replaceOutput
(
$result
,
$
(
'<span/>'
).
text
(
'Error encoding arguments: '
+
e
))
return
}
var
data
=
''
if
(
!
isConstructor
||
funArgs
.
length
>
0
)
{
try
{
data
=
args
.
encode
(
funArgs
)
}
catch
(
e
)
{
replaceOutput
(
$result
,
$
(
'<span/>'
).
text
(
'Error encoding arguments: '
+
e
))
return
}
}
if
(
data
.
slice
(
0
,
9
)
===
'undefined'
)
{
data
=
data
.
slice
(
9
)
}
if
(
data
.
slice
(
0
,
2
)
===
'0x'
)
{
data
=
data
.
slice
(
2
)
}
replaceOutput
(
$result
,
$
(
'<span>Waiting for transaction to be mined...</span>'
))
if
(
isConstructor
)
{
if
(
args
.
bytecode
.
indexOf
(
'_'
)
>=
0
)
{
replaceOutput
(
$result
,
$
(
'<span>Deploying and linking required libraries...</span>'
))
self
.
linkBytecode
(
args
.
contractName
,
function
(
err
,
bytecode
)
{
if
(
err
)
{
replaceOutput
(
$result
,
$
(
'<span/>'
).
text
(
'Error deploying required libraries: '
+
err
))
}
else
{
args
.
bytecode
=
bytecode
handleCallButtonClick
(
ev
,
$result
)
}
})
return
}
else
{
data
=
args
.
bytecode
+
data
}
}
var
decodeResponse
=
function
(
response
)
{
// Only decode if there supposed to be fields
if
(
args
.
abi
.
outputs
&&
args
.
abi
.
outputs
.
length
>
0
)
{
try
{
var
i
var
outputTypes
=
[]
for
(
i
=
0
;
i
<
args
.
abi
.
outputs
.
length
;
i
++
)
{
outputTypes
.
push
(
args
.
abi
.
outputs
[
i
].
type
)
}
// decode data
var
decodedObj
=
ethJSABI
.
rawDecode
(
outputTypes
,
response
)
// format decoded data
decodedObj
=
ethJSABI
.
stringify
(
outputTypes
,
decodedObj
)
for
(
i
=
0
;
i
<
outputTypes
.
length
;
i
++
)
{
var
name
=
args
.
abi
.
outputs
[
i
].
name
if
(
name
.
length
>
0
)
{
decodedObj
[
i
]
=
outputTypes
[
i
]
+
' '
+
name
+
': '
+
decodedObj
[
i
]
}
else
{
decodedObj
[
i
]
=
outputTypes
[
i
]
+
': '
+
decodedObj
[
i
]
}
}
return
getDecodedOutput
(
decodedObj
)
}
catch
(
e
)
{
return
getDecodedOutput
(
'Failed to decode output: '
+
e
)
}
}
}
var
decoded
self
.
runTx
({
to
:
args
.
address
,
data
:
data
,
useCall
:
lookupOnly
},
function
(
err
,
txResult
)
{
self
.
event
.
trigger
(
'transactionExecuted'
,
[
args
.
address
,
data
,
lookupOnly
,
txResult
])
if
(
!
txResult
)
{
replaceOutput
(
$result
,
$
(
'<span/>'
).
text
(
'callback contain no result '
+
err
).
addClass
(
'error'
))
return
}
var
result
=
txResult
.
result
if
(
err
)
{
replaceOutput
(
$result
,
$
(
'<span/>'
).
text
(
err
).
addClass
(
'error'
))
// VM only
}
else
if
(
self
.
executionContext
.
isVM
()
&&
result
.
vm
.
exception
===
0
&&
result
.
vm
.
exceptionError
)
{
replaceOutput
(
$result
,
$
(
'<span/>'
).
text
(
'Exception during execution. ('
+
result
.
vm
.
exceptionError
+
'). Please debug the transaction for more information.'
).
addClass
(
'error'
))
$result
.
append
(
getDebugTransaction
(
txResult
))
// VM only
}
else
if
(
self
.
executionContext
.
isVM
()
&&
result
.
vm
.
return
===
undefined
)
{
replaceOutput
(
$result
,
$
(
'<span/>'
).
text
(
'Exception during execution. Please debug the transaction for more information.'
).
addClass
(
'error'
))
$result
.
append
(
getDebugTransaction
(
txResult
))
}
else
if
(
isConstructor
)
{
replaceOutput
(
$result
,
getGasUsedOutput
(
result
,
result
.
vm
))
$result
.
append
(
getDebugTransaction
(
txResult
))
args
.
appendFunctions
(
self
.
executionContext
.
isVM
()
?
result
.
createdAddress
:
result
.
contractAddress
)
}
else
if
(
self
.
executionContext
.
isVM
())
{
var
outputObj
=
'0x'
+
result
.
vm
.
return
.
toString
(
'hex'
)
clearOutput
(
$result
)
$result
.
append
(
getReturnOutput
(
outputObj
)).
append
(
getGasUsedOutput
(
result
,
result
.
vm
))
decoded
=
decodeResponse
(
result
.
vm
.
return
)
if
(
decoded
)
{
$result
.
append
(
decoded
)
}
if
(
lookupOnly
)
{
$result
.
append
(
getDebugCall
(
txResult
))
}
else
{
$result
.
append
(
getDebugTransaction
(
txResult
))
}
}
else
if
(
lookupOnly
)
{
clearOutput
(
$result
)
$result
.
append
(
getReturnOutput
(
result
)).
append
(
getGasUsedOutput
({}))
decoded
=
decodeResponse
(
ethJSUtil
.
toBuffer
(
result
))
if
(
decoded
)
{
$result
.
append
(
decoded
)
}
}
else
{
clearOutput
(
$result
)
$result
.
append
(
getReturnOutput
(
result
)).
append
(
getGasUsedOutput
(
result
))
$result
.
append
(
getDebugTransaction
(
txResult
))
}
})
}
var
title
if
(
isConstructor
)
{
title
=
'Create'
}
else
if
(
args
.
abi
.
name
)
{
title
=
args
.
abi
.
name
if
(
args
.
funABI
.
name
)
{
title
=
args
.
funABI
.
name
}
else
{
title
=
'(fallback)'
}
var
button
=
$
(
'<button />'
)
var
button
=
$
(
`<button class="
${
css
.
instanceButton
}
"/>`
)
.
addClass
(
'call'
)
.
attr
(
'title'
,
title
)
.
text
(
title
)
.
click
(
handleCallButtonClick
)
if
(
lookupOnly
&&
!
inputs
.
length
)
{
handleCallButtonClick
()
.
click
(()
=>
{
txFormat
.
buildData
(
args
.
contractAbi
,
self
.
contracts
,
false
,
args
.
funABI
,
inputField
.
val
(),
self
,
self
.
executionContext
,
(
error
,
data
)
=>
{
if
(
!
error
)
{
txExecution
.
callFunction
(
args
.
address
,
data
,
args
.
funABI
,
self
,
(
error
,
txResult
)
=>
{
// TODO here should send the result to the dom-console
console
.
log
(
'function call'
,
error
,
txResult
)
alert
(
error
+
' '
+
txResult
.
transactionHash
)
})
}
else
{
alert
(
error
)
}
})
})
// TODO the auto call to constant function has been removed. needs to readd it later.
var
$contractProperty
=
$
(
'<div class="contractProperty"/>'
)
var
$contractProperty
=
$
(
`<div class="contractProperty
${
css
.
buttonsContainer
}
"></div>`
)
$contractProperty
.
append
(
button
)
.
append
((
lookupOnly
&&
!
inputs
.
length
)
?
$outputOverride
:
inputField
)
if
(
isConstructor
)
{
$contractProperty
.
addClass
(
'constructor'
)
}
if
(
lookupOnly
)
{
$contractProperty
.
addClass
(
'constant'
)
}
if
(
args
.
abi
.
inputs
&&
args
.
abi
.
inputs
.
length
>
0
)
{
if
(
args
.
funABI
.
inputs
&&
args
.
funABI
.
inputs
.
length
>
0
)
{
$contractProperty
.
addClass
(
'hasArgs'
)
}
if
(
args
.
abi
.
payable
===
true
)
{
if
(
args
.
funABI
.
payable
===
true
)
{
$contractProperty
.
addClass
(
'payable'
)
}
return
$contractProperty
.
append
(
outputSpan
)
}
UniversalDApp
.
prototype
.
linkBytecode
=
function
(
contractName
,
cb
)
{
var
self
=
this
var
bytecode
=
self
.
getContractByName
(
contractName
).
bytecode
if
(
bytecode
.
indexOf
(
'_'
)
<
0
)
{
return
cb
(
null
,
bytecode
)
}
var
m
=
bytecode
.
match
(
/__
([^
_
]{1,36})
__/
)
if
(
!
m
)
{
return
cb
(
'Invalid bytecode format.'
)
}
var
libraryName
=
m
[
1
]
if
(
!
self
.
getContractByName
(
libraryName
))
{
return
cb
(
'Library '
+
libraryName
+
' not found.'
)
}
self
.
deployLibrary
(
libraryName
,
function
(
err
,
address
)
{
if
(
err
)
{
return
cb
(
err
)
}
var
libLabel
=
'__'
+
libraryName
+
Array
(
39
-
libraryName
.
length
).
join
(
'_'
)
var
hexAddress
=
address
.
toString
(
'hex'
)
if
(
hexAddress
.
slice
(
0
,
2
)
===
'0x'
)
{
hexAddress
=
hexAddress
.
slice
(
2
)
}
hexAddress
=
Array
(
40
-
hexAddress
.
length
+
1
).
join
(
'0'
)
+
hexAddress
while
(
bytecode
.
indexOf
(
libLabel
)
>=
0
)
{
bytecode
=
bytecode
.
replace
(
libLabel
,
hexAddress
)
}
self
.
getContractByName
(
contractName
).
bytecode
=
bytecode
self
.
linkBytecode
(
contractName
,
cb
)
})
}
UniversalDApp
.
prototype
.
deployLibrary
=
function
(
contractName
,
cb
)
{
var
self
=
this
if
(
self
.
getContractByName
(
contractName
).
address
)
{
return
cb
(
null
,
self
.
getContractByName
(
contractName
).
address
)
}
var
bytecode
=
self
.
getContractByName
(
contractName
).
bytecode
if
(
bytecode
.
indexOf
(
'_'
)
>=
0
)
{
self
.
linkBytecode
(
contractName
,
function
(
err
,
bytecode
)
{
if
(
err
)
cb
(
err
)
else
self
.
deployLibrary
(
contractName
,
cb
)
})
}
else
{
self
.
runTx
({
data
:
bytecode
,
useCall
:
false
},
function
(
err
,
txResult
)
{
if
(
err
)
{
return
cb
(
err
)
}
var
address
=
self
.
executionContext
.
isVM
()
?
txResult
.
result
.
createdAddress
:
txResult
.
result
.
contractAddress
self
.
getContractByName
(
contractName
).
address
=
address
cb
(
err
,
address
)
})
}
}
UniversalDApp
.
prototype
.
clickContractAt
=
function
(
self
,
$output
,
contract
)
{
var
address
=
prompt
(
'What Address is this contract at in the Blockchain? ie: 0xdeadbeaf...'
)
self
.
getInstanceInterface
(
contract
,
address
,
$output
)
return
$contractProperty
}
UniversalDApp
.
prototype
.
runTx
=
function
(
args
,
cb
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment