diff --git a/assets/css/universal-dapp.css b/assets/css/universal-dapp.css
index 1c68020991..693c730be8 100644
--- a/assets/css/universal-dapp.css
+++ b/assets/css/universal-dapp.css
@@ -215,7 +215,7 @@
padding: 0 0.4em;
box-sizing: border-box;
float: left;
- word-wrap: break-word;
+ min-width: 100%;
}
#runTabView .contractProperty.hasArgs input {
diff --git a/src/app/execution/txListener.js b/src/app/execution/txListener.js
index 104300ac2d..49ad15f861 100644
--- a/src/app/execution/txListener.js
+++ b/src/app/execution/txListener.js
@@ -249,7 +249,12 @@ class TxListener {
for (var i = 0; i < abi.inputs.length; i++) {
inputTypes.push(abi.inputs[i].type)
}
- return ethJSABI.rawDecode(inputTypes, data)
+ var decoded = ethJSABI.rawDecode(inputTypes, data)
+ var ret = {}
+ for (var k in abi.inputs) {
+ ret[abi.inputs[k].type + ' ' + abi.inputs[k].name] = decoded[k]
+ }
+ return ret
}
}
diff --git a/src/app/execution/txLogger.js b/src/app/execution/txLogger.js
index bc5b0d0468..e847b10d7d 100644
--- a/src/app/execution/txLogger.js
+++ b/src/app/execution/txLogger.js
@@ -1,12 +1,64 @@
'use strict'
var yo = require('yo-yo')
+
+// -------------- styling ----------------------
+var csjs = require('csjs-inject')
var remix = require('ethereum-remix')
+var styleGuide = remix.ui.styleGuide
+var styles = styleGuide()
+
var EventManager = remix.lib.EventManager
var helper = require('../../lib/helper')
var ethJSUtil = require('ethereumjs-util')
var BN = ethJSUtil.BN
var executionContext = require('../../execution-context')
+var css = csjs`
+ .log {
+ display: flex;
+ align-items: baseline;
+ justify-content: space-between;
+ }
+ .tx {
+ color: ${styles.colors.violet};
+ width: 45%;
+ }
+ .txTable, .tr, .td {
+ border-collapse: collapse;
+ font-size: 10px;
+ color: ${styles.colors.grey};
+ border: 1px dashed ${styles.colors.black};
+ }
+ #txTable {
+ margin-top: 1%;
+ margin-bottom: 5%;
+ align-self: center;
+ }
+ .tr, .td {
+ padding: 4px;
+ }
+ .tableTitle {
+ width: 25%;
+ }
+ .buttons {
+ display: flex;
+ }
+ .debug, .details {
+ ${styles.button}
+ min-height: 18px;
+ max-height: 18px;
+ width: 45px;
+ min-width: 45px;
+ font-size: 10px;
+ margin-left: 5px;
+ }
+ .debug {
+ background-color: ${styles.colors.lightOrange};
+ }
+ .details {
+ background-color: ${styles.colors.lightGrey};
+ }
+`
/**
* This just export a function that register to `newTransaction` and forward them to the logger.
* Emit debugRequested
@@ -59,47 +111,131 @@ function log (self, tx, api) {
}
function renderKnownTransaction (self, data) {
- var to = data.tx.to
- if (to) to = helper.shortenAddress(data.tx.to)
+ var from = data.tx.from
+ var to = data.resolvedData.contractName + '.' + data.resolvedData.fn
function debug () {
self.event.trigger('debugRequested', [data.tx.hash])
}
- function detail () {
- // @TODO here should open a modal containing some info (e.g input params, logs, ...)
+ var tx = yo`
+
+
+ ${context(self, {from, to, data})}
+
+
+
+
+
+
+ `
+
+ 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(value(data.resolvedData.params), null, '\t') : ' - ',
+ logs: JSON.stringify(data.logs, null, '\t') || '0',
+ val: data.tx.value
+ })
+ tx.appendChild(table)
+ }
}
- return yo`${context(self, data.tx)}: from:${helper.shortenAddress(data.tx.from)}, to:${to}, ${data.resolvedData.contractName}.${data.resolvedData.fn}, value:${value(data.tx.value)} wei, data:${helper.shortenHexData(data.tx.input)}, ${data.logs.length} logs, hash:${helper.shortenHexData((data.tx.hash))}, `
+
+ return tx
}
function renderUnknownTransaction (self, data) {
+ var from = data.tx.from
var to = data.tx.to
- if (to) to = helper.shortenAddress(data.tx.to)
function debug () {
self.event.trigger('debugRequested', [data.tx.hash])
}
- function detail () {
- // @TODO here should open a modal containing some info (e.g input params, logs, ...)
+ var tx = yo`
+
+
+ ${context(self, {from, to, data})}
+
+
+
+
+
+
+ `
+ 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: JSON.stringify(data.logs) || '0'
+ })
+ tx.appendChild(table)
+ }
}
- return yo`${context(self, data.tx)}: from:${helper.shortenAddress(data.tx.from)}, to:${to}, value:${value(data.tx.value)} wei, data:${helper.shortenHexData((data.tx.input))}, hash:${helper.shortenHexData((data.tx.hash))}, `
+ return tx
}
function renderEmptyBlock (self, data) {
return yo`block ${data.block.number} - O transactions`
}
-function context (self, tx) {
+function context (self, opts) {
+ var data = opts.data || ''
+ var from = opts.from ? helper.shortenHexData(opts.from) : ''
+ var to = opts.to
+ if (data.tx.to) to = to + ' ' + helper.shortenHexData(data.tx.to)
+ var val = data.tx.value
+ var hash = data.tx.hash ? helper.shortenHexData(data.tx.hash) : ''
+ var input = data.tx.input ? helper.shortenHexData(data.tx.input) : ''
+ var logs = data.logs ? data.logs.length : 0
+ var block = data.tx.blockNumber || ''
+ var i = data.tx.transactionIndex
if (executionContext.getProvider() === 'vm') {
- return yo`(vm)`
+ return yo`[vm] from:${from}, to:${to}, value:${value(val)} wei, data:${input}, ${logs} logs, hash:${hash}`
+ } else if (executionContext.getProvider() !== 'vm' && data.resolvedData) {
+ return yo`[block:${block} txIndex:${i}] from:${from}, to:${to}, value:${value(val)} wei`
} else {
- return yo`block:${tx.blockNumber}, txIndex:${tx.transactionIndex}`
+ to = helper.shortenHexData(to)
+ hash = helper.shortenHexData(data.tx.blockHash)
+ return yo`[block:${block} txIndex:${i}] from:${from}, to:${to}, value:${value(val)} wei`
}
}
function value (v) {
try {
- if (v.indexOf && v.indexOf('0x') === 0) {
+ if (v instanceof Array) {
+ var ret = []
+ for (var k in v) {
+ ret.push(value(v[k]))
+ }
+ return ret
+ } else if (BN.isBN(v)) {
+ return v.toString(10)
+ } else if (v.indexOf && v.indexOf('0x') === 0) {
return (new BN(v.replace('0x', ''), 16)).toString(10)
+ } else if (typeof v === 'object') {
+ var retObject = {}
+ for (var i in v) {
+ retObject[i] = value(v[i])
+ }
+ return retObject
} else {
- return v.toString(10)
+ return v
}
} catch (e) {
console.log(e)
@@ -108,3 +244,92 @@ function value (v) {
}
module.exports = TxLogger
+
+// helpers
+
+function createTable (opts) {
+ var table = yo`
`
+
+ var contractAddress = yo`
+
+ contractAddress |
+ ${opts.contractAddress} |
+
+ `
+ if (opts.contractAddress) table.appendChild(contractAddress)
+
+ var from = yo`
+
+ from |
+ ${opts.from} |
+
+ `
+ if (opts.from) table.appendChild(from)
+
+ var toHash
+ var data = opts.data // opts.data = data.tx
+ if (data.to) {
+ toHash = opts.to + ' ' + data.to
+ } else {
+ toHash = opts.to
+ }
+ var to = yo`
+
+ to |
+ ${toHash} |
+
+ `
+ if (opts.to) table.appendChild(to)
+
+ var gas = yo`
+
+ gas |
+ ${opts.gas} |
+
+ `
+ if (opts.gas) table.appendChild(gas)
+
+ var hash = yo`
+
+ hash |
+ ${opts.hash} |
+
+ `
+ if (opts.hash) table.appendChild(hash)
+
+ var input = yo`
+
+ input |
+ ${opts.input} |
+
+ `
+ if (opts.input) table.appendChild(input)
+
+ if (opts['decoded input']) {
+ var inputDecoded = yo`
+
+ decoded input |
+ ${opts['decoded input']} |
+
`
+ table.appendChild(inputDecoded)
+ }
+
+ var logs = yo`
+
+ logs |
+ ${opts.logs || '0'} |
+
+ `
+ if (opts.logs) table.appendChild(logs)
+
+ var val = value(opts.val)
+ val = yo`
+
+ value |
+ ${val} wei |
+
+ `
+ if (opts.val) table.appendChild(val)
+
+ return table
+}
diff --git a/src/app/tabs/run-tab.js b/src/app/tabs/run-tab.js
index 0cf97bb140..1e8e82944b 100644
--- a/src/app/tabs/run-tab.js
+++ b/src/app/tabs/run-tab.js
@@ -300,7 +300,7 @@ function contractDropdown (appAPI, appEvents, instanceContainer) {
var args = createButtonInput.value
txFormat.buildData(contract, contracts, true, constructor, args, appAPI.udapp(), (error, data) => {
if (!error) {
- appAPI.logMessage('transaction added ...')
+ appAPI.logMessage('Transaction added ...')
txExecution.createContract(data, appAPI.udapp(), (error, txResult) => {
if (!error) {
var isVM = executionContext.isVM()
diff --git a/src/lib/helper.js b/src/lib/helper.js
index 917a547b3a..5676c06040 100644
--- a/src/lib/helper.js
+++ b/src/lib/helper.js
@@ -4,6 +4,7 @@ module.exports = {
return address.slice(0, 5) + '...' + address.slice(len - 5, len) + (etherBalance ? ' (' + etherBalance.toString() + ' ether)' : '')
},
shortenHexData: function (data) {
+ if (!data) return ''
if (data.length < 5) return data
var len = data.length
return data.slice(0, 5) + '...' + data.slice(len - 5, len)
diff --git a/test-browser/tests/compiling.js b/test-browser/tests/compiling.js
index 81a7654209..696f12cd45 100644
--- a/test-browser/tests/compiling.js
+++ b/test-browser/tests/compiling.js
@@ -33,7 +33,7 @@ function runTests (browser) {
.waitForElementPresent('.instance button[title="f - transact (not payable)"]')
.click('.instance button[title="f - transact (not payable)"]')
.waitForElementPresent('#editor-container div[class^="terminal"] span[id="tx0xa178c603400a184ce5fedbcfab392d9b77822f6ffa7facdec693aded214523bc"]')
- .assert.containsText('#editor-container div[class^="terminal"] span[id="tx0xa178c603400a184ce5fedbcfab392d9b77822f6ffa7facdec693aded214523bc"]', '(vm): from:0xca3...a733c, to:0x692...77b3a, browser/Untitled.sol:TestContract.f(), value:0 wei, data:0x261...21ff0, 0 logs, hash:0xa17...523bc,DetailsDebug')
+ .assert.containsText('#editor-container div[class^="terminal"] span[id="tx0xa178c603400a184ce5fedbcfab392d9b77822f6ffa7facdec693aded214523bc"]', '[vm] from:0xca3...a733c, to:browser/Untitled.sol:TestContract.f() 0x692...77b3a, value:0 wei, data:0x261...21ff0, 0 logs, hash:0xa17...523bc')
.end()
/*
@TODO: need to check now the return value of the function