diff --git a/packages/embark-ui/src/actions/index.js b/packages/embark-ui/src/actions/index.js index 2dfebcdf3..5f1f65a8a 100644 --- a/packages/embark-ui/src/actions/index.js +++ b/packages/embark-ui/src/actions/index.js @@ -103,6 +103,13 @@ export const transaction = { failure: (error) => action(TRANSACTION[FAILURE], {error}) }; +export const DECODED_TRANSACTION = createRequestTypes('DECODED_TRANSACTION'); +export const decodedTransaction = { + request: (hash) => action(DECODED_TRANSACTION[REQUEST], {hash}), + success: (transaction) => action(DECODED_TRANSACTION[SUCCESS], {transaction}), + failure: (error) => action(DECODED_TRANSACTION[FAILURE], {error}) +}; + export const PROCESSES = createRequestTypes('PROCESSES'); export const processes = { request: () => action(PROCESSES[REQUEST]), diff --git a/packages/embark-ui/src/containers/TransactionDecoderContainer.js b/packages/embark-ui/src/containers/TransactionDecoderContainer.js index 6f9c17410..1fb2537be 100644 --- a/packages/embark-ui/src/containers/TransactionDecoderContainer.js +++ b/packages/embark-ui/src/containers/TransactionDecoderContainer.js @@ -6,8 +6,8 @@ import {withRouter} from 'react-router-dom'; import TransactionDecoder from '../components/TransactionDecoder'; import PageHead from '../components/PageHead'; import { Row, Col } from 'reactstrap'; -import { transaction as transactionAction } from '../actions'; -import {getTransaction} from "../reducers/selectors"; +import { decodedTransaction as decodedTransactionAction } from '../actions'; +import {getDecodedTransaction} from "../reducers/selectors"; const getQueryParams = (props) => { return qs.parse(props.location.search, { @@ -19,7 +19,7 @@ class TransactionDecoderContainer extends Component { componentDidMount() { const { hash } = getQueryParams(this.props); if (hash) { - this.props.fetchTransaction(hash); + this.props.fetchDecodedTransaction(hash); } } @@ -28,7 +28,7 @@ class TransactionDecoderContainer extends Component { const prevHash = getQueryParams(prevProps).hash; if (hash && hash !== prevHash) { - this.props.fetchTransaction(hash); + this.props.fetchDecodedTransaction(hash); } } @@ -48,13 +48,13 @@ class TransactionDecoderContainer extends Component { } TransactionDecoderContainer.propTypes = { - fetchTransaction: PropTypes.func, + fetchDecodedTransaction: PropTypes.func, transaction: PropTypes.object }; -function mapStateToProps(state, props) { +function mapStateToProps(state) { return { - transaction: getTransaction(state, getQueryParams(props).hash), + transaction: getDecodedTransaction(state), error: state.errorMessage, loading: state.loading }; @@ -62,6 +62,6 @@ function mapStateToProps(state, props) { export default withRouter(connect( mapStateToProps, { - fetchTransaction: transactionAction.request + fetchDecodedTransaction: decodedTransactionAction.request } )(TransactionDecoderContainer)); diff --git a/packages/embark-ui/src/reducers/index.js b/packages/embark-ui/src/reducers/index.js index f9328d050..46cdcd952 100644 --- a/packages/embark-ui/src/reducers/index.js +++ b/packages/embark-ui/src/reducers/index.js @@ -3,7 +3,7 @@ import {REQUEST, SUCCESS, FAILURE, CONTRACT_COMPILE, FILES, LOGOUT, AUTHENTICATE FETCH_CREDENTIALS, UPDATE_BASE_ETHER, CHANGE_THEME, FETCH_THEME, EXPLORER_SEARCH, DEBUGGER_INFO, SIGN_MESSAGE, VERIFY_MESSAGE, TOGGLE_BREAKPOINT, UPDATE_PREVIEW_URL, UPDATE_DEPLOYMENT_PIPELINE, WEB3_CONNECT, WEB3_DEPLOY, WEB3_ESTIMAGE_GAS, FETCH_EDITOR_TABS, - SAVE_FILE, SAVE_FOLDER, REMOVE_FILE} from "../actions"; + SAVE_FILE, SAVE_FOLDER, REMOVE_FILE, DECODED_TRANSACTION} from "../actions"; import {EMBARK_PROCESS_NAME, DARK_THEME, DEPLOYMENT_PIPELINES, DEFAULT_HOST, ELEMENTS_LIMIT} from '../constants'; const BN_FACTOR = 10000; @@ -376,6 +376,16 @@ function editorTabs(state = [], action) { return state; } +function decodedTransaction(state = {}, action) { + if (action.type === DECODED_TRANSACTION[SUCCESS] && action.transaction) { + return action.transaction; + } + if (action.type === DECODED_TRANSACTION[FAILURE]) { + return action.error; + } + return state; +} + function previewUrl(state= `${window.location.protocol}//${window.location.host}/`, action) { if (action.type === UPDATE_PREVIEW_URL) { return action.payload; @@ -419,7 +429,8 @@ const rootReducer = combineReducers({ theme, editorTabs, previewUrl, - editorOperationStatus + editorOperationStatus, + decodedTransaction }); export default rootReducer; diff --git a/packages/embark-ui/src/reducers/selectors.js b/packages/embark-ui/src/reducers/selectors.js index 10c7b5040..ffcaabd1b 100644 --- a/packages/embark-ui/src/reducers/selectors.js +++ b/packages/embark-ui/src/reducers/selectors.js @@ -28,6 +28,10 @@ export function getTransaction(state, hash) { return state.entities.transactions.find((transaction) => transaction.hash === hash); } +export function getDecodedTransaction(state) { + return state.decodedTransaction; +} + export function getTransactionsByAccount(state, address) { return state.entities.transactions.filter((transaction) => transaction.from === address); } diff --git a/packages/embark-ui/src/sagas/index.js b/packages/embark-ui/src/sagas/index.js index b1b5cbeb5..ed1dcf02b 100644 --- a/packages/embark-ui/src/sagas/index.js +++ b/packages/embark-ui/src/sagas/index.js @@ -81,6 +81,7 @@ export const toggleBreakpoint = doRequest.bind(null, actions.toggleBreakpoint, a export const authenticate = doRequest.bind(null, actions.authenticate, api.authenticate); export const initRegularTxs = doRequest.bind(null, actions.initRegularTxs, api.regularTxs); export const stopRegularTxs = doRequest.bind(null, actions.stopRegularTxs, api.regularTxs); +export const decodeTransaction = doRequest.bind(null, actions.decodedTransaction, api.fetchTransaction); export const fetchCredentials = doRequest.bind(null, actions.fetchCredentials, storage.fetchCredentials); export const saveCredentials = doRequest.bind(null, actions.saveCredentials, storage.saveCredentials); @@ -103,6 +104,10 @@ export function *watchFetchTransaction() { yield takeEvery(actions.TRANSACTION[actions.REQUEST], fetchTransaction); } +export function *watchDecodeTransaction() { + yield takeEvery(actions.DECODED_TRANSACTION[actions.REQUEST], decodeTransaction); +} + export function *watchFetchTransactions() { yield takeEvery(actions.TRANSACTIONS[actions.REQUEST], fetchTransactions); } @@ -557,6 +562,7 @@ export default function *root() { fork(watchListenToContractEvents), fork(watchFetchBlock), fork(watchFetchTransactions), + fork(watchDecodeTransaction), fork(watchPostCommand), fork(watchPostCommandSuggestions), fork(watchFetchVersions), diff --git a/packages/embark/src/lib/modules/blockchain_connector/index.js b/packages/embark/src/lib/modules/blockchain_connector/index.js index 4253352c8..2cc4db052 100644 --- a/packages/embark/src/lib/modules/blockchain_connector/index.js +++ b/packages/embark/src/lib/modules/blockchain_connector/index.js @@ -1,11 +1,12 @@ const Web3 = require('web3'); const async = require('async'); const Provider = require('./provider.js'); -const Transaction = require('ethereumjs-tx'); const ethUtil = require('ethereumjs-util'); const utils = require('../../utils/utils'); const constants = require('../../constants'); const embarkJsUtils = require('embarkjs').Utils; +const {bigNumberify} = require('ethers/utils/bignumber'); +const RLP = require('ethers/utils/rlp'); const WEB3_READY = 'blockchain:ready'; @@ -420,10 +421,12 @@ class BlockchainConnector { '/embark-api/blockchain/transactions/:hash', (req, res) => { self.getTransactionByHash(req.params.hash, (err, transaction) => { - if (err) { - self.logger.error(err); - } - res.send(transaction); + if (!err) return res.send(transaction); + + self.getTransactionByRawTransactionHash(req.params.hash, (err, transaction) => { + if(err) return res.send({ error: "Could not find or decode transaction hash" }); + res.send(transaction); + }); }); } ); @@ -645,20 +648,39 @@ class BlockchainConnector { } getTransactionByRawTransactionHash(hash, cb) { - const rawData = Buffer.from(ethUtil.stripHexPrefix(hash), 'hex'); - const tx = new Transaction(rawData, 'hex'); + let rawData, decoded; + + try { + rawData = Buffer.from(ethUtil.stripHexPrefix(hash), 'hex'); + decoded = RLP.decode(rawData); + } catch(e) { + return cb("could not decode transaction"); + } + + const [ + nonce, + gasPrice, + gasLimit, + to, + value, + data, + v, + r, + s + ] = decoded; + const transaction = { - from: `0x${tx.getSenderAddress().toString('hex').toLowerCase()}`, - gasPrice: tx.gasPrice.toString('utf8'), - input: `0x${tx.input.toString('hex').toLowerCase()}`, - nonce: tx.nonce.toString('utf8'), - v: `0x${tx.v.toString('hex').toLowerCase()}`, - r: `0x${tx.r.toString('hex').toLowerCase()}`, - s: `0x${tx.s.toString('hex').toLowerCase()}`, - value: tx.value.toString('utf8'), - to: `0x${tx.to.toString('hex').toLowerCase()}`, - hash + nonce: bigNumberify(nonce).toNumber(), + gasPrice: bigNumberify(gasPrice).toNumber(), + gasLimit: bigNumberify(gasLimit).toNumber(), + data: data, + v: `0x${v.toString('hex').toLowerCase()}`, + r: `0x${r.toString('hex').toLowerCase()}`, + s: `0x${s.toString('hex').toLowerCase()}`, + value: value.toString('utf8'), + to: `0x${to.toString('hex').toLowerCase()}` }; + cb(null, transaction); }