How to integrate Web3j to java project
1. Environment prepare
1.1. Install solc
npm install -g solc
Check if success use this command:
solcjs --version
success like this:
1.2. Install web3j-cli
Download web3j-cli 1.4.1 from https://github.com/web3j/web3j-cli/releases
for example I used v1.4.1 :
extract zip files to local file system:
set web3j-cli’s /bin folder to system environment path:
install finish, check version:
1.3. Contract
Here I use the contract “StandardToken.sol” for testing. It can be download at github ( E.G. https://github.com/tintinweb/smart-contract-sanctuary)
2. Compile
Use command solcjs to compile *.sol file to get .abi and .bin files like below:
solcjs StandardToken.sol --bin --abi --optimize -o .\
I got files like this:
3. Generate contract JAVA Wrapper
Command usage:
web3j solidity generate -a \<abiFile\> -b \<binFile\> -o \<destinationFileDir\> -p \<packageName\>
E.G.
4. Integration
4.1. Maven dependencies:
Add dependencies to pom.xml like :
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.web3j</groupId>
<artifactId>core</artifactId>
<version>5.0.0</version>
</dependency>
</dependencies>
4.2. Create java classes:
Copy contract wrapper file to java project and rename it to “StandardTokenContract.java” like below:
Here’s a helper class written by java named “ContractLoader” :
import okhttp3.OkHttpClient;
import org.web3j.crypto.Credentials;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.methods.response.EthGasPrice;
import org.web3j.protocol.http.HttpService;
import org.web3j.tx.Contract;
import org.web3j.tx.gas.ContractGasProvider;
import org.web3j.tx.gas.StaticGasProvider;
import org.web3j.utils.Convert;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.net.InetSocketAddress;
import java.net.Proxy;
public final class ContractLoader {
private static String proxyHost;
private static int proxyPort;
private static String rpcUrl;
private ContractLoader() {
}
public static void env(String proxyHost,
int proxyPort,
String rpcUrl) {
ContractLoader.proxyHost = proxyHost;
ContractLoader.proxyPort = proxyPort;
ContractLoader.rpcUrl = rpcUrl;
}
/**
* Load contract only read block data with default gas-limit 3000000.
*
* @param contractAddress contract which want to operate
* @param contractClazz java class of contract build by web3j-cli-shadow-{version}. E.G.web3j generate solidity -a=.\StandardToken_sol_StandardToken.abi -b=.\StandardToken_sol_StandardToken.bin -o=.\ -p=cn.netoday.web3j-test
* @param <T> return type witch contract java class build by web3j-cli-shadow extends org.web3j.tx.Contract
* @return implements of org.web3j.tx.Contract
* @throws Exception Exception
*/
public static <T extends Contract> T getContract(String contractAddress,
Class<T> contractClazz) throws Exception {
return getContract("0000000000000000000000000000000000000000000000000000000000000000",
Convert.toWei("3000000", Convert.Unit.WEI).toBigInteger(),
contractAddress,
contractClazz);
}
/**
* Load contract with read and write block data with default gas-limit 3000000.
*
* @param senderPrivateKey msg.sender‘s private key. It can operate msg.sender's private assets if provided.
* @param contractAddress contract which want to operate
* @param contractClazz java class of contract build by web3j-cli-shadow-{version}. E.G.web3j generate solidity -a=.\StandardToken_sol_StandardToken.abi -b=.\StandardToken_sol_StandardToken.bin -o=.\ -p=cn.netoday.web3j-test
* @param <T> return type witch contract java class build by web3j-cli-shadow extends org.web3j.tx.Contract
* @return implements of org.web3j.tx.Contract
* @throws Exception Exception
*/
public static <T extends Contract> T getContract(String senderPrivateKey,
String contractAddress,
Class<T> contractClazz) throws Exception {
return getContract(senderPrivateKey,
Convert.toWei("3000000", Convert.Unit.WEI).toBigInteger(),
contractAddress,
contractClazz);
}
/**
* Load contract with read and write block data with customize gas-limit.
*
* @param senderPrivateKey msg.sender‘s private key. It can operate msg.sender's private assets if provided.
* @param gasLimit call contract with customize gas-limit
* @param contractAddress contract which want to operate
* @param contractClazz java class of contract build by web3j-cli-shadow-{version}. E.G.web3j generate solidity -a=.\StandardToken_sol_StandardToken.abi -b=.\StandardToken_sol_StandardToken.bin -o=.\ -p=cn.netoday.web3j-test
* @param <T> return type witch contract java class build by web3j-cli-shadow extends org.web3j.tx.Contract
* @return implements of org.web3j.tx.Contract
* @throws Exception Exception
*/
public static <T extends Contract> T getContract(String senderPrivateKey,
BigInteger gasLimit,
String contractAddress,
Class<T> contractClazz) throws Exception {
if (null == ContractLoader.rpcUrl || "".equals(ContractLoader.rpcUrl)) {
throw new Exception("Rpc url can not be empty!");
}
//set proxy
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (null != ContractLoader.proxyHost && !"".equals(ContractLoader.proxyHost) && ContractLoader.proxyPort > 0) {
builder.proxy(new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(ContractLoader.proxyHost, ContractLoader.proxyPort)));
}
OkHttpClient client = builder.build();
//initial operation for web3j
Web3j web3 = Web3j.build(new HttpService(ContractLoader.rpcUrl, client));
Credentials credentials = Credentials.create(senderPrivateKey);
EthGasPrice gasPrice = web3.ethGasPrice().sendAsync().get();
//reflection of contract
T result = null;
if (gasPrice != null) {
Method method = contractClazz.getMethod("load", String.class, Web3j.class, Credentials.class, ContractGasProvider.class);
result = (T) method.invoke(contractClazz,
contractAddress,
web3,
credentials,
new StaticGasProvider(gasPrice.getGasPrice(), gasLimit)
);
}
return result;
}
}
And here’s a java unit test which used the BSC-TEST rpc point via socks5 proxy:
import com.yayd.contracthelper.ContractLoader;
import com.yayd.contracthelper.StandardTokenContract;
import org.junit.Test;
import org.web3j.utils.Convert;
/**
* Unit test for simple App.
*/
public class AppTest {
private static final String PRIVATE_KEY = "here is your wallet private key to authority";
private static final String RPC_URL = "https://data-seed-prebsc-1-s3.binance.org:8545/";
private static final String CONTRACT_ADDRESS = "here is your contract address on blockchain";
public static final String PROXY_HOSTNAME = "127.0.0.1";
public static final int PROXY_PORT = 10808;
/**
* Test call blockchain
*/
@Test
public void testTransfer() {
try {
ContractLoader.env(
PROXY_HOSTNAME,
PROXY_PORT,
RPC_URL
);
//Load contract only read block data with default gas-limit 3000000.
StandardTokenContract contract = ContractLoader.getContract(
CONTRACT_ADDRESS,
StandardTokenContract.class);
System.out.println(contract.owner().send());
//Load contract with read and write block data with default gas-limit 3000000.
contract = ContractLoader.getContract(
PRIVATE_KEY,
CONTRACT_ADDRESS,
StandardTokenContract.class);
System.out.println(contract.owner().send());
//Load contract with read and write block data with customize gas-limit.
contract = ContractLoader.getContract(
PRIVATE_KEY,
Convert.toWei("3000000", Convert.Unit.WEI).toBigInteger(),
CONTRACT_ADDRESS,
StandardTokenContract.class);
System.out.println(contract.owner().send());
} catch (Exception e) {
e.printStackTrace();
}
}
}
5. References
<Command line tools> : https://docs.web3j.io/4.8.7/command_line_tools/