Home Reference Source

lib/web3/sagas/index.js

import debugModule from "debug";
const debug = debugModule("debugger:web3:sagas");

import { all, takeEvery, apply, fork, join, take, put, select } from 'redux-saga/effects';
import { prefixName } from "lib/helpers";

import * as actions from "../actions";

import Web3Adapter from "../adapter";

function* fetchTransactionInfo(adapter, {txHash}) {
  debug("inspecting transaction");
  var trace;
  try {
    trace = yield apply(adapter, adapter.getTrace, [txHash]);
  } catch(e) {
    debug("putting error");
    yield put(actions.error(e));
    return;
  }

  debug("got trace");
  yield put(actions.receiveTrace(trace));

  let tx = yield apply(adapter, adapter.getTransaction, [txHash]);
  if (tx.to && tx.to != "0x0") {
    yield put(actions.receiveCall({address: tx.to}));
    return;
  }

  let receipt = yield apply(adapter, adapter.getReceipt, [txHash]);
  if (receipt.contractAddress) {
    yield put(actions.receiveCall({binary: tx.input}));
    return;
  }

  throw new Error(
    "Could not find contract associated with transaction. " +
    "Please make sure you're debugging a transaction that executes a " +
    "contract function or creates a new contract."
  );
}

function* fetchBinary(adapter, {address}) {
  debug("fetching binary for %s", address);
  let binary = yield apply(adapter, adapter.getDeployedCode, [address]);

  debug("received binary for %s", address);
  yield put(actions.receiveBinary(address, binary));
}

export function *inspectTransaction(txHash, provider) {
  yield put(actions.init(provider));
  yield put(actions.inspect(txHash));

  let action = yield take( ({type}) =>
    type == actions.RECEIVE_TRACE || type == actions.ERROR_WEB3
  );
  debug("action %o", action);

  var trace;
  if (action.type == actions.RECEIVE_TRACE) {
    trace = action.trace;
    debug("received trace");
  } else {
    return { error: action.error };
  }

  let {address, binary} = yield take(actions.RECEIVE_CALL);
  debug("received call");

  return { trace, address, binary };
}

export function *obtainBinaries(addresses) {
  let tasks = yield all(
    addresses.map( (address) => fork(receiveBinary, address) )
  );

  debug("requesting binaries");
  yield all(
    addresses.map( (address) => put(actions.fetchBinary(address)) )
  );

  let binaries = [];
  binaries = yield all(
    tasks.map(task => join(task))
  );

  debug("binaries %o", binaries);

  return binaries;
}

function *receiveBinary(address) {
  let {binary} = yield take((action) => (
    action.type == actions.RECEIVE_BINARY &&
    action.address == address
  ));
  debug("got binary for %s", address);

  return binary;
}

export function* saga() {
  // wait for web3 init signal
  let {provider} = yield take(actions.INIT_WEB3);
  let adapter = new Web3Adapter(provider);

  yield takeEvery(actions.INSPECT, fetchTransactionInfo, adapter);
  yield takeEvery(actions.FETCH_BINARY, fetchBinary, adapter);
}

export default prefixName("web3", saga);