Getting Started with Web3j

With JS domination for front-end development in the dApp industry, you might be a Java developer thinking of creating a front end in Java, still wanting to harness the power of Ethereum’s power of decentralization. If you’ve googled around enough, you might know there’s a library “Web3j” to interact with Ethereum blockchain using Java. So you know what to do, you know what to use, and you start the project but just then you think, how?

Web3j is a very useful library if you’re a Java developer trying to explore blockchain. But the problem with it is there’s not enough documentation or help you need around to get started with it. Hence, let’s try to make it as simple as it is, and try to build something which uses blockchain using Java’s Web3j library.

Our project would be a very simple Auction project. It would allow you to bid, and find the highest bid at the end of the auction. We won’t be explaining the solidity code for this. Solidity has a pretty neat and well written documentation for that here.

The Smart Contract

Here’s our simple Open Auction contract which can be found in Solidity by Example section of the Solidity Docs. We save this as Auction.sol anywhere.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
pragma solidity ^0.4.20;
 
contract SimpleAuction {
    address public beneficiary;
    uint public auctionEnd;
 
    address public highestBidder;
    uint public highestBid;
 
    mapping(address => uint) pendingReturns;
 
    bool ended;
 
    event HighestBidIncreased(address bidder, uint amount);
    event AuctionEnded(address winner, uint amount);
 
    function SimpleAuction(uint _biddingTime, address _beneficiary) public {
        beneficiary = _beneficiary;
        auctionEnd = now + _biddingTime;
    }
 
    function bid() public payable {
        require(now <= auctionEnd);
        require(msg.value > highestBid);
 
        if (highestBid != 0) {
            pendingReturns[highestBidder] += highestBid;
        }
        highestBidder = msg.sender;
        highestBid = msg.value;
        emit HighestBidIncreased(msg.sender, msg.value);
    }
 
    function withdraw() public returns (bool) {
        uint amount = pendingReturns[msg.sender];
        if (amount > 0) {
            pendingReturns[msg.sender] = 0;
            if (!msg.sender.send(amount)) {
                pendingReturns[msg.sender] = amount;
                return false;
            }
        }
        return true;
    }
 
    function auctionEnd() public {
        require(now >= auctionEnd);
        require(!ended); 
 
        ended = true;
        emit AuctionEnded(highestBidder, highestBid);
 
        beneficiary.transfer(highestBid);
    }
 
    function getHighestBid() public constant returns(uint){
        return highestBid;
    }
}

So to place bids and withdraw amounts using Java, we will need to setup a few things.

Downloading Web3j

First is, download the Web3j library from here. Extract the downloaded file anywhere (we’ll be referring to this extracted folder as Web3j folder)

Importing External Libraries

Import all the jar files in the lib folder into your Java Project (Ways to import external jars in Eclipse and in IntelliJ)

Creating Wrapper Class

Before we can interact with the smart contract in Java, we need to create a wrapper class for the smart contract. We can then use this wrapper class to interact with the smart contract in our Java code. To do that, we’d need to create a .bin and an .abi file. So here’s what we need to do.

  1. Compile the contract using command solcjs {path to contract}/Auction.sol --bin --abi --optimize -o .
  2. You’ll find two new files in the that directory, one with .bin extension and one with .abi extension. Copy these two files to the bin folder of Web3j folder you extracted in the beginning.
  3. Open command window in the bin folder of Web3j folder, and run the command web3j solidity generate Auction_sol_SimpleAuction.bin Auction_sol_SimpleAuction.abi -o . -p org.your.package.name
  4. You’ll find a Java file in org/your/package/name folder in the bin folder of Web3j folder. That file has our wrapper class. So just copy the file in the src folder of the Java project and then we’re good to go.

Creating Wallet File

We’ll also need to create a wallet through which we will be making transactions. To create a wallet, from bin folder in the Web3j folder, run the command web3j wallet create. Enter the password for the wallet file, and re-enter the password, and then provide the location where you want to save the password file. You’ll have your wallet ready to be used.

The Java Part

Now that we have the wrapper class, we can use it in our project to interact with the Ethereum Blockchain. To setup a connection with the Ethereum network, we’ll be using Infura (We can also use a local node, we’d just need to connect to localhost:port using Httpservice in Java). Register on Infura and you’ll get your connection links in the email. Use those links to connect to an Ethereum network using Httpservice.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
public class AuctionExample {
 
    private Web3j web3;
    private Credentials credentials;
    private String CONTRACT_ADDRESS = "0x8aec305dbb2cb96be809e691a23e2b4e23a84308";
    Auction_sol_SimpleAuction contract;
    private String _beneficiary = "0x463479ebd39B1DCF6B645997f3512692c123dE71";
 
    public AuctionExample(){
        try {
            web3 = Web3j.build(new HttpService("https://ropsten.infura.io/gc91pM9K2fuyiEMla2uk"));
            credentials = WalletUtils.loadCredentials("helloworld", "C:\Users\Steve Mann\Downloads\web3j-3.2.0\bin\UTC--2018-03-01T20-27-57.800000000Z--258f5abb174baf7928aaa416cb17fb6dff889246.json");
 
        }catch(Exception e){
            e.printStackTrace();
        }
    }
 
    public void GetClientVersion(){
        try {
 
            Web3ClientVersion version = web3.web3ClientVersion().sendAsync().get();
            System.out.println("version : " + version.getWeb3ClientVersion());
 
 
        }catch(Exception e){
            e.printStackTrace();
        }
    }
 
 
    public void deployContract(){
        System.out.println("Going to deploy smart contract");
        try {
 
            contract = Auction_sol_SimpleAuction.deploy(
                    web3, credentials,
                    new BigInteger("22000000000"), new BigInteger("510000"),
                    new BigInteger("0"), _beneficiary
                    ).send();
            CONTRACT_ADDRESS = contract.getContractAddress();
            System.out.printf("Contract Address : " + contract.getContractAddress());
        } catch(Exception e){
            e.printStackTrace();
        }
 
    }
 
    public void loadContract(){
        System.out.println("Going to load smart contract");
        try {
            contract = Auction_sol_SimpleAuction.load(
                    CONTRACT_ADDRESS, web3, credentials,
                    new BigInteger("22000000000"), new BigInteger("510000"))
        } catch(Exception e){
            e.printStackTrace();
        }
 
    }
    public void bid(BigInteger weiValue){
        System.out.println("Call the method bid()");
        try{
            TransactionReceipt receipt = contract.bid(weiValue).send();
            System.out.println( "Bid TxHash : " + receipt.getTransactionHash());
        }catch (Exception e){
            e.printStackTrace();
        }
    }
 
 
    public void withdraw(){
        System.out.println("Call the method withdraw()");
        try{
            TransactionReceipt receipt = contract.withdraw().send();
            System.out.println( "Withdraw TxHash : " + receipt.getTransactionHash());
        }catch (Exception e){
            e.printStackTrace();
        }
    }
 
    public BigInteger getHighestBid(){
        System.out.println("Call the method getHighestBid()"); 
        BigInteger result = new BigInteger("0");
        try{
            result = contract.getHighestBid().send();
            System.out.println( "getHighestBid TxHash : " + receipt.getTransactionHash());
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }
 
    public static void main(String args[]){
        AuctionExample auction = new AuctionExample();
        auction.deployContract();
        auction.bid(new BigInteger("5000000000000000000");
        auction.withdraw();
        auction.getHighestBid();
    }
}

Deploying a Contract

We can see that to create a contract, we need to call the deploy method of the wrapper class. The signature for this deploy method is

public static RemoteCall<Auction_sol_SimpleAuction> deploy(Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit, BigInteger _biddingTime, String _beneficiary)
Here last two parameters are the parameters for the constructor of the smart contract as it takes two parameters, _biddingTime and _beneficiary. For a contract where constructor takes no parameters, then last two parameters won’t be needed.
So a generic signature for deploy method would look something like
public static RemoteCall<YourSmartContract> deploy(<web3j>, <credentials>, GAS_PRICE, GAS_LIMIT,[<initialValue>,] <param1>, ..., <paramN>)
Where the <initialValue> parameter is only needed if the contructor of the smart contract is set as payable. <param1, … , paramN> are the parameters of the constructor in the smart contract.

Making Transactional Calls

Next up, we call the bid method. Bid method can be called by simply sending the contract.bid().send() transaction which will return a TransactionReceipt.
TransactionReceipt receipt = contract.bid(weiValue).send();
For all transactional calls (i.e. method calls which don’t return anything) , TransactionReceipt will be returned.
The transaction receipt is useful for two reasons:
  1. It provides details of the mined block that the transaction resides in
  2. Solidity Events that are called will be logged as part of the transaction, which can then be extracted

A generic transactional call will look like

TransactionReceipt transactionReceipt = contract.someMethod(<param1>, ...).send();

Next, we withdraw() method which works in a similar way as bid() method does.

Calling Constant Methods

Next up is getHighestBid() method. This is a constant method which returns something, uint in our case. uint is handled by BigInteger class in Java and hence the getHighestBid() will return BigInteger which can be stored. It would be called like this

result = contract.getHighestBid().send();

Here result is a BigInteger.

A generic call to a constant method would look something like

Type result = contract.someMethod(<param1>, ...).send();

 

That’s how most of the things will be done in the Java part. We have successfully interacted with a smart contract on Ethereum Blockchain using Java.

Thanks for reading and feel free to ask questions.

Share this:
Share
«

Leave a Reply