4

My use case is the following: I would like to have a daemon monitoring how users are interacting with my smart contract. The way I see it is to look at incoming blocks and try to decode input data with a to address corresponding to my contract. I was unable to find in web3J a way to decode data.

1- Is there any way with web3J to decode the data ?

2- Have I any other way to achieve my goal than decode the input data ? Events seems to me as an hard choice as I will not be able to easily monitor every things. And this methods cannot apply to smart contract that I don't own.

Thanks for the help.

2
  • 1
    A proposal for JS exists already abi-decoder answer. Doing a crawler in JS that is regularly pushing data is an option.
    – Cyril
    Nov 22, 2017 at 13:51
  • 1
    An suggestion was also already done for web3j here. However it does not help with the compatibility with the library.
    – Cyril
    Nov 22, 2017 at 13:53

4 Answers 4

3

I guess sort of for the first question. If you look at what a transaction is, to a node its just a big long byte string. If the bytes are convertible to ASCII, you can use use the

web3.toAscii()

That may or may not give you something. For instance, here's a tx a I did on Ropsten where you get some readable input data back and some non-readable data: https://ropsten.etherscan.io/tx/0xe4058b8f612f20600d8aae1230d93b7b5c63398ddde0a3a6aed236659f425c0e (just click the input Convert to Ascii at the bottom)

That said, the best (easiest) way to do this is to own the dapp. So when they fill out a form, you just save the input data. The next best like you said is to use Events. They are annoying, but you could have just one long event at the beginning of your contracts:

    contract Test {
       event Input(string desc, address _party, uint _input1, string _input2);  

     function somefunc(uint _input1, string _input2) returns(bool success){
        Input("Input",msg.sender,_input1,_input2);
      return true;
   }
}

But then for other people's contracts your out of luck since you don't have this event.

4
  • 2
    Thanks you for the answer. I've just added an new issue on web3j github for implementing such a possibility. Looking at the code it does not look too hard to reverse engineer some functions and decode the string. What is encoded is function <name> , parameters value.
    – Cyril
    Nov 22, 2017 at 13:48
  • 1
  • 2
    Awesome, great stuff to know. It seems like you'll be ok trying to decode it as long as the contract isn't intentionally trying to hide the inputs
    – thefett
    Nov 22, 2017 at 15:05
  • 1
    Even in this case, I don't mind too much. I will extract the input and offer the input to users as they might have authority to access it that my server app hasn't.
    – Cyril
    Nov 22, 2017 at 15:11
1
    ERC20 javaToken = ERC20.load(contractAddress, web3, creds, new DefaultGasProvider());
    System.out.println("ALL HISTORY OF TT");
    javaToken.transferEventFlowable(DefaultBlockParameterName.EARLIEST, DefaultBlockParameterName.LATEST)
     .subscribe(event
     -> System.out.println("from: " + event._from + ", to: " + event._to + ", value: " + event._value));    

I think this will help you

1

The logic that I have used is as follows:

web3j.transactionflowable.subscribe(tx -> {

checkIfMyTransaction(tx.getTo, tx.getHash);

});

public void checkIfMyTransaction(String toAddress, String txHash){

// check data base if the address belong to my application and then following logic. This can be contract address or wallet address. 

// if contract address:

EthTransaction ethTransaction=web3j.getTransactionByHash(txHash).send;
Transaction transaction=ethTransaction.getTransaction.get();
transaction.getFrom;
transaction.getBlockNumer;

// Take all info like blocknumber, blockhash etc from above call. For input data, we create new method. 

decodeInput(transaction.getInput);
}

public void decodeInput(String data) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    String inputData = data;
    String method = inputData.substring(0,10);
    log.info("Method >>>>>> " +method);
    String to = inputData.substring(10,74);
    String value = inputData.substring(74);
    Method refMethod = TypeDecoder.class.getDeclaredMethod("decode",String.class,int.class,Class.class);
    refMethod.setAccessible(true);
    Address address = (Address)refMethod.invoke(null,to,0,Address.class);
    log.info("Address>>>>>> " +address.toString());
    Uint256 amount = (Uint256) refMethod.invoke(null,value,0,Uint256.class);
    log.info("amount >>>>>> " +amount);
}
1

I had the same requirement and started to hack this into web3j contract wrapper generator. Due to the (IMHO) overly complicated approach I abandoned this and instead wrote my own, standalone java library for this. You don't need web3j at all, you'll only need to Contract's ABI in JSON format.

https://github.com/rvullriede/evm-abi-decoder

Usage Example:

// Abi can be found here: https://etherscan.io/address/0x7a250d5630b4cf539739df2c5dacb4c659f2488d#code
AbiDecoder uniswapv2Abi=new AbiDecoder(pathToAbiJsonFile).getFile());

// tx: https://etherscan.io/tx/0xde2b61c91842494ac208e25a2a64d99997c382f6aaf0719d6a719b5cff1f8a07
String inputData="0x18cbafe5000000000000000000000000000000000000000000000000000000000098968000000000000000000000000000000000000000000000000000165284993ac4ac00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000d4cf8e47beac55b42ae58991785fa326d9384bd10000000000000000000000000000000000000000000000000000000062e8d8510000000000000000000000000000000000000000000000000000000000000002000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2";

/**
 * #  Name          Type       Data
 * ----------------------------------------------------------------------
 * 0  amountIn      uint256    10000000
 * 1  amountOutMin  uint256    6283178947560620
 * 2  path          address[]  0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
 *                             0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
 * 3  to            address    0xD4CF8e47BeAC55b42Ae58991785Fa326d9384Bd1
 * 4  deadline      uint256    1659426897
 */

DecodedFunctionCall decodedFunctionCall=uniswapv2Abi.decodeFunctionCall(inputData);

System.out.println(decodedFunctionCall.getName()); // prints swapExactTokensForETH

It's still a young project, if you encounter problems (e.g. with specific contracts) please let me know via the github project issue tracker.

Hope that helps!

2
  • Don't copy & paste the same answer multiple times. They will be marked as spam.
    – Ismael
    Aug 4, 2022 at 14:00
  • Thx for the hint! I was just trying to help also on the other question. I'll link to this thread instead.
    – Raphael
    Aug 4, 2022 at 16:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.