How to Develop with JZap API

Zap Project

The JZap API is the Java wrapper of the ZapJS API. Its purpose is to enable Java developers to interact with Zap contracts on the Zap Protocol by creating Oracles. With the Zap Protocol 2.0 beta just released on March 31th, 2021, it’s great timing for JZap’s package release. If you’re already familiar with ZapJS, this transition will be a breeze for you. For more information on the Zap Protocol, refer to their docs: https://zapproject.gitbook.io/zapproject/zap-contracts.

Getting Started

Add the package dependency to your maven project’s pom.xml:

<dependency>
<groupId>io.github.zapproject</groupId>
<artifactId>jzap</artifactId>
<version>{latest-version}</version>
</dependency>

For the {latest-version} refer to: https://mvnrepository.com/artifact/io.github.zapproject/jzap/

Or you can head over to the repository:

Now let's set up our local Ethereum network with Hardhat. We will use it for the development and testing of your interactions with Zap Contracts. Luckily there’s a Docker repository configured for Zap Protocol. But first, you will need to have Docker installed: https://docs.docker.com/engine/install/.

Pull from the repository “jzapdocker/hardhat:v1” and run.

If you’re using the Docker CLI, open a new terminal and run:

docker pull jzapdocker/hardhat:v1

docker run jzapdocker/hardhat:v1

This will start our Hardhat node in a docker container. Keep in mind, this docker image also creates endpoints and their curves. If you would like a clean Ethereum network with only the deployed Zap Contracts, clone from this repository.

That concludes setting up our environment for development! Keep in mind the IP address of our hardhat network is “http://172.17.0.2:8545" (which you will be passing in on your Web3j instance) and the network ID is 31337.

e.i. Web3j web3j =
Web3j.build(new HttpService(“http://172.17.0.2:8545"));

I recommend getting familiar with Web3j, an API that interacts with the Ethereum network. It isn’t necessary in order to utilize JZap, other than initializing the class and stating the network ID, but there’s a lot you can do interacting with the Ethereum network.

Contracts

Zap Contract Interaction
Zap Contract Interaction

Refer to Zap Protocol’s docs for more information on Zap Contracts. https://zapproject.gitbook.io/zapproject/zap-contracts

Connecting to a Zap Contract

Zap Contracts can be connected by calling the load() method. There are two ways of calling the load method.

  1. By passing in the type class, NetworkProviderOptions which contains the network ID, Web3j, Credentials, and ContractGasProvider.
  2. By passing in the contract’s address, Web3j, Credentials, and ContractGasProvider.

e.i. Registry registry = Registry.load(networkProviderOptions);

Interacting with Zap Contracts

Contract methods return a RemoteCall object, which in turn requires the send() method call, in order to call that contract function on the network. The remote call will either return the function’s response or a transaction receipt.

The transaction receipt is the logs of the transaction made with a deployed contract. Refer to the docs for more details http://docs.web3j.io/latest/smart_contracts/interacting_with_smart_contract/#transaction-receipt-processors

In JZap, transaction receipts can be used for listening to events emitted by the Zap contracts. Which is explained below…

Listening to Events

There are two ways of listening to events.

  1. As previously mentioned, passing in the transaction receipts into event listeners. This will return a list of specified events that occurred, up until the block number where the function was called from.
    e.i. registry.getNewProviderEvents(txReceipt);
  2. Listening to events with Flowable objects. This is great when you don’t have access to the transaction receipt for a function call. It will obtain an event from specified starting and ending block numbers. Keep in mind this listener only obtains one event. This type of event listeners will return a Flowable object, which requires a subscribe() method call. The subscribe method is used to specify how the event is interacted with.
    e.i. flowable = dispatch.getIncomingEventFlowable(DefaultBlockParameterName.EARLIEST, DefaultBlockParameter.LATEST);
    flowable.subscribe(tx -> { do_something(tx) });

Keep in mind when this was written, the current version of JZap was 0.0.62, and not all contract event listeners have flowable methods (only the dispatch contract for Providers to utilize).
Also, many of the contract methods require a byte[] array sized at 32. If the length of the array is not 32, the Zap Contracts will revert the function call transaction with an error.

e.i. byte[] array = new byte[32];
byte[] temp = “copy array”.getBytes();
System.arraycopy(temp, 0, array, 0, temp.length);

Deploying Zap Contracts

Luckily, our Hardhat node already has the necessary Zap Contracts deployed. However, for testing purposes, you can deploy contracts yourself by calling the deploy() method. The deploy method takes the Web3j, Credentials, ContractGasProvider, and Zap Coordinator contract address.

Again keep in mind most of the contract methods, along with deploy(), returns a RemoteCall object, which requires a send() method call to actually send the function call in the Ethereum network.

e.g. registry.deploy(…).send().

Oracles

In JZap, the Provider and Subscriber are the endpoint users who interact with the Zap Protocol and Zap Contracts through Oracles. The Subscribers are subscribing to the Oracles retrieving the data by making queries. The Providers are data providers of Oracles, who respond to queries with responses.

Provider

The creators of Oracles, who provide data and collect ZAP tokens as compensation. The Provider persists as an event listener for query events emitted on their endpoints. They retrieve the query and processes the respective data as a response().

The Provider class contains instances of the Dispatch, Bondage, Arbiter, and Registry classes. Typically the order of interactions with these contracts would be:

  1. Registry —Setting up Oracle (initiateProvider(), setProviderTitle(), getEndpointBroker(), and initiateProviderCurve()) .
  2. Bondage —Checking balances of Oracle and Subscribers (dotsLimit(), getBoundDots(), getNumEscrow(), and getZapRequired()).
  3. Arbiter — Listening to start and end subscription events from Subscribers.
  4. Dispatch — Listening to queries and responding to them (respond()).

If you refer to the Oracle class in the JZap Oracle Template, https://github.com/zapproject/jzap-oracle-template/blob/main/src/main/java/io/github/oracle/template/jzap/Oracle.java

The Oracle runs as a thread that persists in listening for queries in an infinite loop. In the loop, a Flowable is made to listen for an event with specified starting and ending block numbers. In our case, the starting block is maintained as contract functions are called or query events are found and the ending block defaults to the latest block. On the Flowable, the subscribe() method handles the events, by responding, when they are received.

Subscriber

The clients of Oracles, who request data and pays in ZAP tokens. The Subscriber bonds/unbonds to the Oracle and can make queries once bonded.

Much like the Provider, the Subscriber class contains instances of the Dispatch, Bondage, Arbiter, Registry, and ZapToken classes. Typically the order of interactions with these contracts would be:

  1. Registry — Checking the Provider public key (getProviderPublicKey()).
  2. ZapToken — Checking Zap balance (balanceOf(), allowance(), and approve()).
  3. Bondage — Bonding/unbonding to an Oracle (bond(), unbond(), and delegateBond()).
  4. Arbiter — Subscribing to an Oracle (initiateSubscription())
  5. Dispatch — Start/Cancel query to an Oracle and listen to response events (query() and canacelQuery()).

If you again refer to the JZap Oracle Template, https://github.com/zapproject/jzap-oracle-template/blob/main/src/main/java/io/github/oracle/template/jzap/Subscribe.java, the Subscribe class also runs as a thread which creates a query and persists for response events.

After the query is made, an infinite loop is made to persist in listening for response events. Much like in the Oracle class, a Flowable is made to listen on similar starting and ending blocks. The subscribe() method on the Flowable processes the response from the Oracle/Provider.

Oracle Templates

I recommend referring to the JZap Oracle template for the contract workflow. The master branch consists of the CoinGecko Oracle, other Oracles have their own branch. https://github.com/zapproject/jzap-oracle-template

You can create a new Oracle, by following the Oracle template with a few adjustments.

  1. Modify the Responder.java file, such that the getReponse(query) method processes your query and returns the response. If you’re utilizing an API this is where you would typically make your interactions at.
  2. Modify the Config.json file, such that you set all properties or create new ones for your Oracle. These properties should only contain the information required by the Provider/Oracle.
  3. If any properties were added or removed, be sure to import and handle them in the Oracle class.
  4. The Subscribe class is meant to imitate the endpoint users for your Oracle, this will most likely be used for testing purposes only. Update the constructor of the Subscribe class, such that the endpoint global parameter reflects your Config.json file.

e.i. System.arraycopy(“Translate”.getBytes(), 0, endpoint, 0, 9);

Congrats🎉 You powered through! 🏋️‍♀️💪