Installation and usage of the platform

Constructing smart contracts with Java/Kotlin Contract SDK

This section describes Java/Kotlin Сontract SDK Toolkit – a toolkit for development, testing and deploying Docker smart contracts in Waves Enterprise public blockchain networks. Use the toolkit to fast take off with the Waves Enterprise ecosystem using any of the JVM programming languages, since smart contracts are deployed in a Docker container. You can create a smart contract using any of the JVM languages, such as Java.

Smart contracts are often deployed into different environments and networks. For example, you can scaffold local environment based on a sandbox node and deploy contracts to this network for test use-cases.

All the transaction handling is done via methods of a single class marked with @ContractHandler annotation. The methods which implement handling logic are marked with @ContractInit (for CreateContractTx) and @ContractAction (for CallContractTx).

To deploy your contract, issue 103 и 104 transactions.

Requirements

Before you start developing your smart contracts, make sure that the following software is installed:

  • Docker

  • JDK 8 or higher

To deploy your smart contracts, the following software should be installed:

  • Docker

  • JRE 8 or higher

Dependencies

Quickstart

Take the following steps to create your new contract:

Note

All examples below are taken from the Samples .

1. Create contract handler

@ContractHandler
public class SampleContractHandler {

    private final ContractState contractState;
    private final ContractTransaction tx;

    private final Mapping<List<MySampleContractDto>> mapping;

    public SampleContractHandler(ContractState contractState, ContractTransaction tx) {
        this.contractState = contractState;
        mapping = contractState.getMapping(
          new TypeReference<List<MySampleContractDto>>() {
          }, "SOME_PREFIX");
        this.tx = tx;
    }
}

2. Add @ContractInit and @ContractAction methods to handle contract transactions

public class SampleContractHandler {

  // ...

  @ContractInit
  public void createContract(String initialParam) {
    contractState.put("INITIAL_PARAM", initialParam);
  }

  @ContractAction
  public void doSomeAction(String dtoId) {
      contractState.put("INITIAL_PARAM", Instant.ofEpochMilli(tx.getTimestamp().getUtcTimestampMillis()));

      if (mapping.has(dtoId)) {
          throw new IllegalArgumentException("Already has " + dtoId + " on state");
      }
      mapping.put(dtoId,
              Arrays.asList(
                      new MySampleContractDto("john", 18),
                      new MySampleContractDto("harry", 54)
              ));
  }
}

3. Dispatch the contract with the specified contract handler and settings

public class MainDispatch {
  public static void main(String[] args) {
      ContractDispatcher contractDispatcher = GrpcJacksonContractDispatcherBuilder.builder()
              .contractHandlerType(SampleContractHandler.class)
              .objectMapper(getObjectMapper())
              .build();

      contractDispatcher.dispatch();
  }

  private static ObjectMapper getObjectMapper() {
      ObjectMapper objectMapper = new ObjectMapper();
      objectMapper.registerModule(new JavaTimeModule());
      return objectMapper;
  }
}

4. Create Docker image

FROM openjdk:8-alpine
MAINTAINER Waves Enterprise <>

ENV JAVA_MEM="-Xmx256M"
ENV JAVA_OPTS=""

ADD build/libs/*-all.jar app.jar

RUN chmod +x app.jar
RUN eval $SET_ENV_CMD
CMD ["/bin/sh", "-c", "eval ${SET_ENV_CMD} ; java $JAVA_MEM $JAVA_OPTS -jar app.jar"]

5. Push the image to the Docker repository used by WE node mining contract transactions

Publish the image to the registry used by the Waves Enterprise blockchain node. For convenience, you can use the build_and_push_to_docker.sh bash script which builds your smart contract image, pushes it to the specified registry and displays image and imageHash.

./build_and_push_to_docker.sh my.registry.com/contracts/my-awesome-docker-contract:1.0.0

6. Sign and broadcast transactions for creating and invoking the published contract

You will need image and imageHash of the published contract to create it.

CreateContractTx example:

{
  "image": "my.registry.com/contracts/my-awesome-docker-contract:1.0.0",
  "fee": 0,
  "imageHash": "d17f6c1823176aa56e0e8184f9c45bc852ee9b076b06a586e40c23abde4d7dfa",
  "type": 103,
  "params": [
      {
        "type": "string",
        "value": "createContract",
        "key": "action"
      },
      {
        "type": "string",
        "value": "initialValue",
        "key": "createContract"
      }
  ],
  "version": 2,
  "sender": "3M3ybNZvLG7o7rnM4F7ViRPnDTfVggdfmRX",
  "feeAssetId": null,
  "contractName": "myAwesomeContract"
}

To call contract you will need contractId = CreateContractTx.id.

CallContractTx example:

{
   "contractId": "7sVc6ybnqZr523xWK5Sg7xADsX597qga8iQNAS9f1D3c",
   "fee": 0,
   "type": 104,
   "params": [
     {
     "type": "string",
     "value": "doSomeAction",
     "key": "action"
     },
     {
       "type": "string",
       "value": "someValue",
       "key": "createContract"
     }
   ],
   "version": 2,
   "sender": "3M3ybNZvLG7o7rnM4F7ViRPnDTfVggdfmRX",
   "feeAssetId": null,
   "contractVersion": 1
}

Notes on usage

Usage with Java 11 and higher

The library has been tested against Java 8, 11 and 17. When using with Java 11 and higher, additional Java options should be specified for the io.grpc to enable optimizations:

--add-opens java.base/jdk.internal.misc=ALL-UNNAMED --add-opens=java.base/java.nio=ALL-UNNAMED -Dio.netty.tryReflectionSetAccessible=true

A complete example can be found in Dockerfile for Java 17.

See also