|
|
|
@ -17,18 +17,43 @@ var typeConversion = remixLib.execution.typeConversion |
|
|
|
|
var css = csjs` |
|
|
|
|
.log { |
|
|
|
|
display: flex; |
|
|
|
|
align-items: end; |
|
|
|
|
justify-content: space-between; |
|
|
|
|
cursor: pointer; |
|
|
|
|
} |
|
|
|
|
.log:hover { |
|
|
|
|
opacity: 0.8; |
|
|
|
|
} |
|
|
|
|
.caret { |
|
|
|
|
color: ${styles.terminal.icon_Color_Menu}; |
|
|
|
|
font-size: 15px; |
|
|
|
|
cursor: pointer; |
|
|
|
|
display: flex; |
|
|
|
|
position: absolute; |
|
|
|
|
left: 7px; |
|
|
|
|
} |
|
|
|
|
.caret:hover { |
|
|
|
|
color: ${styles.terminal.icon_HoverColor_Menu}; |
|
|
|
|
} |
|
|
|
|
.txLog { |
|
|
|
|
width: 75%; |
|
|
|
|
} |
|
|
|
|
.txItem { |
|
|
|
|
color: ${styles.terminal.text_Primary}; |
|
|
|
|
margin-right: 5px; |
|
|
|
|
float: left; |
|
|
|
|
} |
|
|
|
|
.txItemTitle { |
|
|
|
|
font-weight: bold; |
|
|
|
|
} |
|
|
|
|
.tx { |
|
|
|
|
color: ${styles.terminal.text_Title_TransactionLog}; |
|
|
|
|
font-weight: bold; |
|
|
|
|
width: 45%; |
|
|
|
|
float: left; |
|
|
|
|
margin: 0 10px; |
|
|
|
|
} |
|
|
|
|
.txTable, .tr, .td { |
|
|
|
|
.txTable, |
|
|
|
|
.tr, |
|
|
|
|
.td { |
|
|
|
|
border-collapse: collapse; |
|
|
|
|
font-size: 10px; |
|
|
|
|
color: ${styles.terminal.text_Primary}; |
|
|
|
@ -38,27 +63,36 @@ var css = csjs` |
|
|
|
|
margin-top: 1%; |
|
|
|
|
margin-bottom: 5%; |
|
|
|
|
align-self: center; |
|
|
|
|
width: 85%; |
|
|
|
|
} |
|
|
|
|
.tr, .td { |
|
|
|
|
padding: 4px; |
|
|
|
|
vertical-align: baseline; |
|
|
|
|
} |
|
|
|
|
.td:first-child { |
|
|
|
|
min-width: 30%; |
|
|
|
|
width: 30%; |
|
|
|
|
align-items: baseline; |
|
|
|
|
font-weight: bold; |
|
|
|
|
} |
|
|
|
|
.tableTitle { |
|
|
|
|
width: 25%; |
|
|
|
|
} |
|
|
|
|
.buttons { |
|
|
|
|
display: flex; |
|
|
|
|
margin-right: 10px; |
|
|
|
|
} |
|
|
|
|
.debug, .details { |
|
|
|
|
.debug { |
|
|
|
|
${styles.terminal.button_Log_Debug} |
|
|
|
|
margin-left: 5px; |
|
|
|
|
width: 55px; |
|
|
|
|
min-width: 55px; |
|
|
|
|
min-height: 20px; |
|
|
|
|
max-height: 20px; |
|
|
|
|
font-size: 11px; |
|
|
|
|
} |
|
|
|
|
` |
|
|
|
|
.debug:hover { |
|
|
|
|
opacity: 0.8; |
|
|
|
|
}` |
|
|
|
|
/** |
|
|
|
|
* This just export a function that register to `newTransaction` and forward them to the logger. |
|
|
|
|
* Emit debugRequested |
|
|
|
@ -132,6 +166,15 @@ class TxLogger { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function debug (e, data, self) { |
|
|
|
|
e.stopPropagation() |
|
|
|
|
if (data.tx.isCall && data.tx.envMode !== 'vm') { |
|
|
|
|
modalDialog.alert('Cannot debug this call. Debugging calls is only possible in JavaScript VM mode.') |
|
|
|
|
} else { |
|
|
|
|
self.event.trigger('debugRequested', [data.tx.hash]) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function log (self, tx, api) { |
|
|
|
|
var resolvedTransaction = api.resolvedTransaction(tx.hash) |
|
|
|
|
if (resolvedTransaction) { |
|
|
|
@ -149,142 +192,68 @@ function log (self, tx, api) { |
|
|
|
|
function renderKnownTransaction (self, data) { |
|
|
|
|
var from = data.tx.from |
|
|
|
|
var to = data.resolvedData.contractName + '.' + data.resolvedData.fn |
|
|
|
|
function debug () { |
|
|
|
|
self.event.trigger('debugRequested', [data.tx.hash]) |
|
|
|
|
} |
|
|
|
|
var obj = {from, to} |
|
|
|
|
var tx = yo` |
|
|
|
|
<span id="tx${data.tx.hash}"> |
|
|
|
|
<div class="${css.log}"> |
|
|
|
|
<div class="${css.log}" onclick=${e => txDetails(e, tx, data, obj)}> |
|
|
|
|
<i class="${css.caret} fa fa-caret-right"></i> |
|
|
|
|
${context(self, {from, to, data})} |
|
|
|
|
<div class=${css.buttons}> |
|
|
|
|
<button class=${css.details} onclick=${txDetails}>Details</button> |
|
|
|
|
<button class=${css.debug} onclick=${debug}>Debug</button> |
|
|
|
|
<div class=${css.debug} onclick=${(e) => debug(e, data, self)}>Debug</div> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</span> |
|
|
|
|
` |
|
|
|
|
|
|
|
|
|
var table |
|
|
|
|
function txDetails () { |
|
|
|
|
if (table && table.parentNode) { |
|
|
|
|
tx.removeChild(table) |
|
|
|
|
} else { |
|
|
|
|
table = createTable({ |
|
|
|
|
contractAddress: data.tx.contractAddress, |
|
|
|
|
data: data.tx, |
|
|
|
|
from, |
|
|
|
|
to, |
|
|
|
|
gas: data.tx.gas, |
|
|
|
|
hash: data.tx.hash, |
|
|
|
|
input: data.tx.input, |
|
|
|
|
'decoded input': data.resolvedData && data.resolvedData.params ? JSON.stringify(typeConversion.stringify(data.resolvedData.params), null, '\t') : ' - ', |
|
|
|
|
'decoded output': data.resolvedData && data.resolvedData.decodedReturnValue ? JSON.stringify(typeConversion.stringify(data.resolvedData.decodedReturnValue), null, '\t') : ' - ', |
|
|
|
|
logs: data.logs, |
|
|
|
|
val: data.tx.value, |
|
|
|
|
transactionCost: data.tx.transactionCost, |
|
|
|
|
executionCost: data.tx.executionCost, |
|
|
|
|
status: data.tx.status |
|
|
|
|
}) |
|
|
|
|
tx.appendChild(table) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return tx |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function renderCall (self, data) { |
|
|
|
|
function debug () { |
|
|
|
|
if (data.tx.envMode === 'vm') { |
|
|
|
|
self.event.trigger('debugRequested', [data.tx.hash]) |
|
|
|
|
} else { |
|
|
|
|
modalDialog.alert('Cannot debug this call. Debugging calls is only possible in JavaScript VM mode.') |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
var to = data.resolvedData.contractName + '.' + data.resolvedData.fn |
|
|
|
|
var from = data.tx.from ? data.tx.from : ' - ' |
|
|
|
|
var input = data.tx.input ? helper.shortenHexData(data.tx.input) : '' |
|
|
|
|
var obj = {from, to} |
|
|
|
|
var tx = yo` |
|
|
|
|
<span id="tx${data.tx.hash}"> |
|
|
|
|
<div class="${css.log}"> |
|
|
|
|
<span class=${css.txLog}><span class=${css.tx}>[call]</span> from:${from}, to:${to}, data:${input}, return: </span> |
|
|
|
|
<div class="${css.log}" onclick=${e => txDetails(e, tx, data, obj)}> |
|
|
|
|
<i class="${css.caret} fa fa-caret-right"></i> |
|
|
|
|
<span class=${css.txLog}> |
|
|
|
|
<span class=${css.tx}>[call]</span> |
|
|
|
|
<div class=${css.txItem}><span class=${css.txItemTitle}>from:</span> ${from}</div> |
|
|
|
|
<div class=${css.txItem}><span class=${css.txItemTitle}>to:</span> ${to}</div> |
|
|
|
|
<div class=${css.txItem}><span class=${css.txItemTitle}>data:</span> ${input}</div> |
|
|
|
|
</span> |
|
|
|
|
<div class=${css.buttons}> |
|
|
|
|
<button class=${css.details} onclick=${txDetails}>Details</button> |
|
|
|
|
<button class=${css.debug} onclick=${debug}>Debug</button> |
|
|
|
|
<div class=${css.debug} onclick=${(e) => debug(e, data, self)}>Debug</div> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
<div> ${JSON.stringify(typeConversion.stringify(data.resolvedData.decodedReturnValue), null, '\t')}</div> |
|
|
|
|
</span> |
|
|
|
|
` |
|
|
|
|
|
|
|
|
|
var table |
|
|
|
|
function txDetails () { |
|
|
|
|
if (table && table.parentNode) { |
|
|
|
|
tx.removeChild(table) |
|
|
|
|
} else { |
|
|
|
|
table = createTable({ |
|
|
|
|
isCall: data.tx.isCall, |
|
|
|
|
contractAddress: data.tx.contractAddress, |
|
|
|
|
data: data.tx, |
|
|
|
|
from, |
|
|
|
|
to, |
|
|
|
|
gas: data.tx.gas, |
|
|
|
|
input: data.tx.input, |
|
|
|
|
'decoded input': data.resolvedData && data.resolvedData.params ? JSON.stringify(typeConversion.stringify(data.resolvedData.params), null, '\t') : ' - ', |
|
|
|
|
'decoded output': data.resolvedData && data.resolvedData.decodedReturnValue ? JSON.stringify(typeConversion.stringify(data.resolvedData.decodedReturnValue), null, '\t') : ' - ', |
|
|
|
|
logs: data.logs, |
|
|
|
|
val: data.tx.value, |
|
|
|
|
transactionCost: data.tx.transactionCost, |
|
|
|
|
executionCost: data.tx.executionCost |
|
|
|
|
}) |
|
|
|
|
tx.appendChild(table) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return tx |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function renderUnknownTransaction (self, data) { |
|
|
|
|
var from = data.tx.from |
|
|
|
|
var to = data.tx.to |
|
|
|
|
function debug () { |
|
|
|
|
self.event.trigger('debugRequested', [data.tx.hash]) |
|
|
|
|
} |
|
|
|
|
var obj = {from, to} |
|
|
|
|
var tx = yo` |
|
|
|
|
<span id="tx${data.tx.hash}"> |
|
|
|
|
<div class="${css.log}"> |
|
|
|
|
<i class="${css.caret} fa fa-caret-right"></i> |
|
|
|
|
<div class="${css.log}" onclick=${e => txDetails(e, tx, data, obj)}> |
|
|
|
|
${context(self, {from, to, data})} |
|
|
|
|
<div class=${css.buttons}> |
|
|
|
|
<button class=${css.details} onclick=${txDetails}>Details</button> |
|
|
|
|
<button class=${css.debug} onclick=${debug}>Debug</button> |
|
|
|
|
<div class=${css.debug} onclick=${(e) => debug(e, data, self)}>Debug</div> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</span> |
|
|
|
|
` |
|
|
|
|
var table |
|
|
|
|
function txDetails () { |
|
|
|
|
if (table && table.parentNode) { |
|
|
|
|
tx.removeChild(table) |
|
|
|
|
} else { |
|
|
|
|
table = createTable({ |
|
|
|
|
data: data.tx, |
|
|
|
|
from, |
|
|
|
|
to, |
|
|
|
|
val: data.tx.value, |
|
|
|
|
input: data.tx.input, |
|
|
|
|
hash: data.tx.hash, |
|
|
|
|
gas: data.tx.gas, |
|
|
|
|
logs: data.tx.logs, |
|
|
|
|
transactionCost: data.tx.transactionCost, |
|
|
|
|
executionCost: data.tx.executionCost, |
|
|
|
|
status: data.tx.status |
|
|
|
|
}) |
|
|
|
|
tx.appendChild(table) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return tx |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function renderEmptyBlock (self, data) { |
|
|
|
|
return yo`<span class=${css.txLog}><span class='${css.tx}'>[block:${data.block.number} - 0 transactions]</span></span>` |
|
|
|
|
return yo` |
|
|
|
|
<span class=${css.txLog}> |
|
|
|
|
<span class='${css.tx}'><div class=${css.txItem}>[<span class=${css.txItemTitle}>block:${data.block.number} - </span> 0 transactions]</span></span> |
|
|
|
|
</span>` |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function context (self, opts) { |
|
|
|
@ -300,13 +269,44 @@ function context (self, opts) { |
|
|
|
|
var i = data.tx.transactionIndex |
|
|
|
|
var value = val ? typeConversion.toInt(val) : 0 |
|
|
|
|
if (executionContext.getProvider() === 'vm') { |
|
|
|
|
return yo`<span class=${css.txLog}><span class=${css.tx}>[vm]</span> from:${from}, to:${to}, value:${value} wei, data:${input}, ${logs} logs, hash:${hash}</span>` |
|
|
|
|
return yo` |
|
|
|
|
<div> |
|
|
|
|
<span class=${css.txLog}> |
|
|
|
|
<span class=${css.tx}>[vm]</span> |
|
|
|
|
<div class=${css.txItem}><span class=${css.txItemTitle}>from:</span> ${from}</div> |
|
|
|
|
<div class=${css.txItem}><span class=${css.txItemTitle}>to:</span> ${to}</div> |
|
|
|
|
<div class=${css.txItem}><span class=${css.txItemTitle}>value:</span> ${value} wei</div> |
|
|
|
|
<div class=${css.txItem}><span class=${css.txItemTitle}>data:</span> ${input}</div> |
|
|
|
|
<div class=${css.txItem}><span class=${css.txItemTitle}>logs:</span> ${logs}</div> |
|
|
|
|
<div class=${css.txItem}><span class=${css.txItemTitle}>hash:</span> ${hash}</div> |
|
|
|
|
</span> |
|
|
|
|
</div>` |
|
|
|
|
} else if (executionContext.getProvider() !== 'vm' && data.resolvedData) { |
|
|
|
|
return yo`<span class=${css.txLog}><span class='${css.tx}'>[block:${block} txIndex:${i}]</span> from:${from}, to:${to}, value:${value} wei, ${logs} logs, data:${input}, hash:${hash}</span>` |
|
|
|
|
return yo` |
|
|
|
|
<div> |
|
|
|
|
<span class=${css.txLog}> |
|
|
|
|
<span class='${css.tx}'>[block:${block} txIndex:${i}]</span> |
|
|
|
|
<div class=${css.txItem}><span class=${css.txItemTitle}>from:</span> ${from}</div> |
|
|
|
|
<div class=${css.txItem}><span class=${css.txItemTitle}>to:</span> ${to}</div> |
|
|
|
|
<div class=${css.txItem}><span class=${css.txItemTitle}>value:</span> ${value} wei</div> |
|
|
|
|
<div class=${css.txItem}><span class=${css.txItemTitle}>data:</span> ${input}</div> |
|
|
|
|
<div class=${css.txItem}><span class=${css.txItemTitle}>logs:</span> ${logs}</div> |
|
|
|
|
<div class=${css.txItem}><span class=${css.txItemTitle}>hash:</span> ${hash}</div> |
|
|
|
|
</span> |
|
|
|
|
</div>` |
|
|
|
|
} else { |
|
|
|
|
to = helper.shortenHexData(to) |
|
|
|
|
hash = helper.shortenHexData(data.tx.blockHash) |
|
|
|
|
return yo`<span class=${css.txLog}><span class='${css.tx}'>[block:${block} txIndex:${i}]</span> from:${from}, to:${to}, value:${value} wei</span>` |
|
|
|
|
return yo` |
|
|
|
|
<div> |
|
|
|
|
<i class="${css.caret} fa fa-caret-right"></i> |
|
|
|
|
<span class=${css.txLog}> |
|
|
|
|
<span class='${css.tx}'>[block:${block} txIndex:${i}]</span> |
|
|
|
|
<div class=${css.txItem}><span class=${css.txItemTitle}>from:</span> ${from}</div> |
|
|
|
|
<div class=${css.txItem}><span class=${css.txItemTitle}>to:</span> ${to}</div> |
|
|
|
|
<div class=${css.txItem}><span class=${css.txItemTitle}>value:</span> ${value} wei</div> |
|
|
|
|
</span> |
|
|
|
|
</div>` |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -314,6 +314,40 @@ module.exports = TxLogger |
|
|
|
|
|
|
|
|
|
// helpers
|
|
|
|
|
|
|
|
|
|
function txDetails (e, tx, data, obj) { |
|
|
|
|
var table = document.querySelector(`#${tx.id} [class^="txTable"]`) |
|
|
|
|
var from = obj.from |
|
|
|
|
var to = obj.to |
|
|
|
|
var log = document.querySelector(`#${tx.id} [class^='log']`) |
|
|
|
|
var caret = document.querySelector(`#${tx.id} [class^='caret']`) |
|
|
|
|
var caretDown = yo`<i class="${css.caret} fa fa-caret-down"></i>` |
|
|
|
|
var caretRight = yo`<i class="${css.caret} fa fa-caret-right"></i>` |
|
|
|
|
if (table && table.parentNode) { |
|
|
|
|
tx.removeChild(table) |
|
|
|
|
log.removeChild(caret) |
|
|
|
|
log.appendChild(caretRight) |
|
|
|
|
} else { |
|
|
|
|
log.removeChild(caret) |
|
|
|
|
log.appendChild(caretDown) |
|
|
|
|
table = createTable({ |
|
|
|
|
isCall: data.tx.isCall, |
|
|
|
|
contractAddress: data.tx.contractAddress, |
|
|
|
|
data: data.tx, |
|
|
|
|
from, |
|
|
|
|
to, |
|
|
|
|
gas: data.tx.gas, |
|
|
|
|
input: data.tx.input, |
|
|
|
|
'decoded input': data.resolvedData && data.resolvedData.params ? JSON.stringify(typeConversion.stringify(data.resolvedData.params), null, '\t') : ' - ', |
|
|
|
|
'decoded output': data.resolvedData && data.resolvedData.decodedReturnValue ? JSON.stringify(typeConversion.stringify(data.resolvedData.decodedReturnValue), null, '\t') : ' - ', |
|
|
|
|
logs: data.logs, |
|
|
|
|
val: data.tx.value, |
|
|
|
|
transactionCost: data.tx.transactionCost, |
|
|
|
|
executionCost: data.tx.executionCost |
|
|
|
|
}) |
|
|
|
|
tx.appendChild(table) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function createTable (opts) { |
|
|
|
|
var table = yo`<table class="${css.txTable}" id="txTable"></table>` |
|
|
|
|
|
|
|
|
|