0

I have been trying to send funds from one ethereum account to another using web3j to test that it works on Android. I am using an Infura cloud instance.

First, it appears I need to send it async because Android requires that you do so. In the code down below I have tried to do so - but it fails on the last step, when I try to get from the Future. If I do not try to get the value then there is no exception, but I obviously cannot do anything with the value that I want to do.

        final String FROM_ADDRESS = "0x6861B070f43842FC16eAD07854eE5D91B9D27C13";
    final String TO_ADDRESS = "0x31B98D14007bDEe637298086988A0bBd31184523";

    //Credentials credentials = obtainCredentials(WALLET_DIRECTORY);

    Callable<TransactionReceipt> task = new Callable<TransactionReceipt>() {
        @Override
        public TransactionReceipt call() throws Exception {
            Web3j web3 = Web3jFactory.build(
                    new HttpService("https://rinkeby.infura.io/SxLC8uFzMPfzwnlXHqx9")
            );
            Log.d(TAG, web3.ethGasPrice().getJsonrpc());

            ClientTransactionManager clientTransactionManager =
                    new ClientTransactionManager(web3, FROM_ADDRESS);
            Log.d(TAG, clientTransactionManager.getFromAddress());

            org.web3j.tx.Transfer tran = new org.web3j.tx.Transfer(web3, clientTransactionManager);
            Log.d(TAG, String.valueOf(tran.getSyncThreshold()));

            RemoteCall<TransactionReceipt> rc = tran.sendFunds(
                    TO_ADDRESS,
                    BigDecimal.valueOf(1.0),
                    Convert.Unit.ETHER
            );
            Log.d(TAG, String.valueOf(rc.toString()));
            return rc.send();
        }
    };
    Future<TransactionReceipt> future = Async.run(task);
    return future.get();

It comes with this exception:

11-19 12:49:03.418 32442-32442/com.example.graeme.beamitup W/System.err: java.util.concurrent.ExecutionException: org.web3j.protocol.exceptions.ClientConnectionException: Invalid response received: okhttp3.internal.http.RealResponseBody@3c286ab
11-19 12:49:03.418 32442-32442/com.example.graeme.beamitup W/System.err:     at java.util.concurrent.FutureTask.report(FutureTask.java:94)
11-19 12:49:03.419 32442-32442/com.example.graeme.beamitup W/System.err:     at java.util.concurrent.FutureTask.get(FutureTask.java:164)
11-19 12:49:03.419 32442-32442/com.example.graeme.beamitup W/System.err:     at com.example.graeme.beamitup.Transfer.sendTransfer(Transfer.java:183)
11-19 12:49:03.419 32442-32442/com.example.graeme.beamitup W/System.err:     at com.example.graeme.beamitup.MainActivity.onCreate(MainActivity.java:26)
11-19 12:49:03.419 32442-32442/com.example.graeme.beamitup W/System.err:     at android.app.Activity.performCreate(Activity.java:6272)

It points out an invalid response from the HTTP transfer - but shouldn't this be happening even without trying the Future.get? The code executes either way, correct? What have I done wrong to create this error?

0

1) This line is probably not doing what you expect:

Log.d(TAG, String.valueOf(rc.toString()));

rc has type RemoteCall<TransactionReceipt>, which means it needs to be executed. Instead, your code converts the invocation to a String (twice): once from the toString() and once from String.valueOf.

2) You create a future, then wait for it to complete, and I know you know this is pointless. I dispensed with the future, no idea why Android insists on a future. My simpler code gives the same result as your code, so at least we know that the future is not introducing the problem you report.

3) The error arises after this JSON-RPC payload is sent:

{"jsonrpc":"2.0","method":"eth_gasPrice","params":[],"id":1}

The ClientTransactionManager.sendTransaction() method dies when it attempts to execute:

return web3j.ethSendTransaction(transaction)
            .send();

Although web3j.ethSendTransaction(transaction) seems to work fine, the chained send() method returns an unsuccessful response. I suspect authentication is required, but of course no credentials were provided so the transaction was rejected.

I don't work in Android, so here is the code I worked with:

import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.RemoteCall;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.protocol.http.HttpService;
import org.web3j.tx.ClientTransactionManager;
import org.web3j.utils.Convert;

import java.math.BigDecimal;

public class SO {
    private static final String FROM_ADDRESS = "0x6861B070f43842FC16eAD07854eE5D91B9D27C13";
    private static final String TO_ADDRESS = "0x31B98D14007bDEe637298086988A0bBd31184523";

    public static void main(String[] args) throws Exception {
        TransactionReceipt value = new SO().test();
        System.out.println(value);
    }

    private TransactionReceipt test() throws Exception {
        //Credentials credentials = obtainCredentials(WALLET_DIRECTORY);

        Web3j web3 = Web3j.build(
            new HttpService("https://rinkeby.infura.io/SxLC8uFzMPfzwnlXHqx9")
        );
        System.out.println("ethGasPrice=" + web3.ethGasPrice().getJsonrpc());

        ClientTransactionManager clientTransactionManager =
            new ClientTransactionManager(web3, FROM_ADDRESS);
        System.out.println("From address=" + clientTransactionManager.getFromAddress());

        org.web3j.tx.Transfer transfer = new org.web3j.tx.Transfer(web3, clientTransactionManager);
        System.out.println("transfer=" + String.valueOf(transfer.getSyncThreshold()));

        RemoteCall<TransactionReceipt> rc = transfer.sendFunds(
            TO_ADDRESS,
            BigDecimal.valueOf(1.0),
            Convert.Unit.ETHER
        );
        TransactionReceipt receipt = rc.send();
        System.out.println("receipt=" + receipt.toString());
        return receipt;
    }
}
  • Thanks for your reply. You were right that the problem ended up being related to authorization - I had not realized that you could derive the address of an ethereum account from the public key, so I hadn't understood the web3j authorization system properly. This led to me failing to understand how to authorize my transfers properly. I've now implemented it with another web3j sendFunds function that requires and uses authorization. – WarSame Dec 17 '17 at 5:36
  • Revisiting this, I meant that you can derive the public key/address from the private key. – WarSame Jan 23 '18 at 22:56
  • I understood you the first time, no problem. Vote up my answer (click the up arrow above) if you are so inclined :) – Mike Slinn Jan 24 '18 at 5:50
  • I did! I'm too low reputation for my votes to show yet :/ – WarSame Jan 24 '18 at 14:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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