Calling functions on Smart Contract fails?

Hi there!

I am new to infura and want to play around with interacting with Ethereum. Now, I created an account on Infura.io, created my project, and started to code with Web3j (4.8.2) in Java 15 within a SpringBoot 2.4.1. Anyhow, I keep getting exceptions as soon as I attempt to interact with Infura/Ethereum.

First of all: I am assuming (and maybe here I am wrong) that I can simply use Web3j to connect to Ethereum via Infura? Anyhow, first, when attempting to connect to the Ropsten testnet, I got an Exception. Essentially, I worked out via some tutorials, that I needed to manually add the authHeader to the HttpService object, otherwise, I would get this exception:

java.lang.NoSuchMethodError: 'okhttp3.RequestBody okhttp3.RequestBody.create(java.lang.String, okhttp3.MediaType)'

Now, I managed to get the connection working as shown in my code below. Anyhow, any calls to my smart contract fail with the same exception. I already wrote and tested my smart contract, compiled it, deployed it to Ropsten, and built my Java class from it using web3j-cli. So far, no problems.

Now, my contract features a function run(string memory x) that will return the string “ok” in case i pass the parameter “test” and “not ok” if any other string is passed. just for testing / exercise purposes for now.

Now what I am doing in my Java code is building a Web3j client and connect to Ethereum/Ropsten via my Infura account. All that works:

try {
    HttpService httpService = new HttpService(INFURA_ENDPOINT); // Infura endpoint for ropsten
	String auth = new String(":" + "yyyxxxzzz"); // Infura secret
	byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(StandardCharsets.ISO_8859_1));
	String authHeader = "Basic " + new String(encodedAuth);
	httpService.addHeader(HttpHeaders.AUTHORIZATION, authHeader);
			
	Web3j web3j = Web3j.build(new HttpService(INFURA_ENDPOINT));
			
	String privateKeyString = "xyz"; // private key as exported from Metamask for my account in ropsten
	String address = "0xabc"; // addredd for said account
	Credentials credentials = Credentials.create(privateKeyString);
			
	String contractAddress = "0xabcdef"; // address of the deployed contract in ropsten
			
	final BigInteger gasPrice = BigInteger.valueOf(2205000);
	final BigInteger gasLimit = BigInteger.valueOf(14300000);
	final ContractGasProvider gasProvider = new StaticGasProvider(gasPrice, gasLimit);
	
    final Test contract = Test.load(contractAddress, web3j, credentials, gasProvider);
	
    // NO PROBLEMS UNTIL HERE
    
	String a = contract.run("xyz").send();
	System.out.println("run(xyz): " + a);

} catch(Exception e) {
	System.out.println("Web3j: " +  e.getMessage() + "\n");
	e.printStackTrace();
}

Now, explicitly calling the function run() looks like this in my generated contract Java class:

public RemoteFunctionCall<String> run(String name) {
    final Function function = new Function(FUNC_RUN, 
            Arrays.<Type>asList(new org.web3j.abi.datatypes.Utf8String(name)), 
            Arrays.<TypeReference<?>>asList(new TypeReference<Utf8String>() {}));
    return executeRemoteCallSingleValueReturn(function, String.class);
}

Here’s the Solidity function from the smart contract:

function run(string memory name) public pure returns (string memory) {

    if(strcmp(name, "test")) {
        return "ok";
    }
    
    return "not ok";
}

Now, when I run this, a call such as contract.run("xyz")runs without problems and is also received by Infura - as I can easily check and verify in my dashboard. Yet as soon as I append a send() (same with sendAsync().get() and the lot) I get the following exception:

Exception in thread "main" java.lang.NoSuchMethodError: 'okhttp3.RequestBody okhttp3.RequestBody.create(java.lang.String, okhttp3.MediaType)'
	at org.web3j.protocol.http.HttpService.performIO(HttpService.java:154)
	at org.web3j.protocol.Service.send(Service.java:48)
	at org.web3j.protocol.core.Request.send(Request.java:87)
	at org.web3j.tx.RawTransactionManager.sendCall(RawTransactionManager.java:155)
	at org.web3j.tx.ManagedTransaction.call(ManagedTransaction.java:134)
	at org.web3j.tx.Contract.executeCall(Contract.java:292)
	at org.web3j.tx.Contract.executeCallSingleValueReturn(Contract.java:300)
	at org.web3j.tx.Contract.executeCallSingleValueReturn(Contract.java:311)
	at org.web3j.tx.Contract.lambda$executeRemoteCallSingleValueReturn$1(Contract.java:399)
	at org.web3j.protocol.core.RemoteCall.send(RemoteCall.java:42)
	at com.example.web3j.TestWeb3j.main(TestWeb3j.java:56)

I’m mostly following the tutorials https: //dzone. com/articles/blockchain-simplified-with-ethereum-example-with-j and https: //trimplement. com/blog/2020/03/coding-smart-contracts-tutorial-infura/ here. As far as I understand here, a send() should call the contract’s function and get me the returned string. Anyhow, playing around with sendAsync().get()will cause the same problems.

Is this again a problem where I need to manually add headers to the requests being sent? Is Web3j even compatible/usable with infura without all too much manual overhead?

Hi @xenon, and welcome to the Infura community!

I’m not super familiar with Java, but I’ll try to give some suggestions and point you in the right direction :slight_smile:

From this thread with a similar issue, I would suggest making sure your ports match, and that your library versions aren’t conflicting. If you read down the thread, there are some additional troubleshooting ideas.

If that doesn’t work, I would suggest looking at this thread and explicitly declaring dependencies for the okhhtp version that’s used in your web3j version. If neither of these works, please let us know and we’ll continue to search for you!

Hi, thanks for the reply.

Anyhow, I don’t see how the referenced posts or port issues may be related to this. Ports are open and are not interfering here. Also, library versions are up to date and I cant see any conflicts. Web3j (now version 4.8.3) uses okhttp 4.9.0 (package name of okhttp 4.x remains “okhttp3” though). Here, everything is fine.

After having looked a little into the issue, it seems that infura expects plain (“manual”) rpc requests, where authentication is done via the respective http auth headers (basic auth). This is e.g. also described in the infura docs.
This involves manually building the transaction and sending it to the infura endpoint, e.g. via okhttp

Web3j is meant to automate most of this, which is the reason for why I want to use it here. Now, Web3j implements a class “InfuraHttpService” (https://github.com/web3j/web3j/blob/master/hosted-providers/src/main/java/org/web3j/protocol/infura/InfuraHttpService.java) that seems to be meant as a solution for this, but unfortunately, I am running into the same issues here. Also, unfortunately, this is not documented by the web3j team.

Is there any official documentation for using Infura with Web3j?

We don’t have any official documentation on our side for using Infura with Web3j. Since the InfuraHttpService is meant to be a solution but isn’t working, I would suggest reaching out to the Web3j team to see if they can troubleshoot from their end.

How have you solved that? I’ve added:

	<dependency>
	    <groupId>com.squareup.okhttp3</groupId>
	    <artifactId>okhttp</artifactId>
	    <version>4.9.1</version>
	</dependency> 

to my pom.xml. But I’m worrying about side effects - I’ve noticed none until now.