Mi caso de uso es el siguiente: me gustaría tener un demonio que supervise cómo los usuarios interactúan con mi contrato inteligente. La forma en que lo veo es mirar los bloques entrantes e intentar decodificar los datos de entrada con una dirección correspondiente a mi contrato. No pude encontrar en web3J una forma de decodificar datos.
1- ¿Hay alguna forma con web3J de decodificar los datos?
2- ¿Tengo alguna otra forma de lograr mi objetivo que no sea decodificar los datos de entrada? Los eventos me parecen una elección difícil ya que no podré monitorear fácilmente todas las cosas. Y estos métodos no pueden aplicarse a un contrato inteligente que no poseo.
Gracias por la ayuda.
Supongo que algo así como la primera pregunta. Si observa qué es una transacción, para un nodo es solo una cadena de bytes grande y larga. Si los bytes son convertibles a ASCII, puede usar el
web3.toAscii()
Eso puede o no darte algo. Por ejemplo, aquí hay un tx que hice en Ropsten donde obtiene algunos datos de entrada legibles y algunos datos no legibles: https://ropsten.etherscan.io/tx/0xe4058b8f612f20600d8aae1230d93b7b5c63398ddde0a3a6aed236659f425c0e (simplemente haga clic en la entrada Convertir a Ascii en la parte inferior )
Dicho esto, la mejor manera (la más fácil) de hacer esto es tener el dapp. Entonces, cuando completan un formulario, solo guarda los datos de entrada. Lo siguiente mejor, como dijiste, es usar Eventos. Son molestos, pero podría tener solo un evento largo al comienzo de sus contratos:
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;
}
}
Pero luego, para los contratos de otras personas, no tiene suerte ya que no tiene este evento.
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));
Creo que esto te ayudará
La lógica que he utilizado es la siguiente:
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);
}
Tenía el mismo requisito y comencé a piratear esto en el generador de envoltura de contrato web3j. Debido al enfoque demasiado complicado (en mi humilde opinión), abandoné esto y en su lugar escribí mi propia biblioteca java independiente para esto. No necesita web3j en absoluto, solo necesitará el ABI de Contract en formato JSON.
https://github.com/rvullriede/evm-abi-decodificador
Ejemplo de uso:
// 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
Todavía es un proyecto joven, si encuentra problemas (por ejemplo, con contratos específicos), hágamelo saber a través del rastreador de problemas del proyecto github.
¡Espero que ayude!
Cirilo
Cirilo