Developing Smart Contracts Using Hyperledger Composer

Tutorial 3 of 5

Introduction

Goal of the Tutorial

This tutorial aims to guide you through the process of developing smart contracts using Hyperledger Composer. We will be learning how to define business networks that use blockchain technology, and how to write smart contracts, or chaincode, to interact with the blockchain.

Learning Objectives

By the end of this tutorial, you will be able to:
- Understand the basic concepts of Hyperledger Composer
- Write your own smart contracts using Hyperledger Composer
- Deploy your smart contracts on a blockchain business network

Prerequisites

Before starting this tutorial, you should have a basic understanding of blockchain technology, JavaScript programming, and Node.js. Familiarity with Hyperledger Fabric is beneficial but not a strict requirement.

Step-by-Step Guide

Installing the Development Environment

Before we can start writing our smart contracts, we need to install the necessary tools. This includes Node.js, npm, Docker, and the Hyperledger Composer CLI.

npm install -g composer-cli

This command installs the Hyperledger Composer command line interface.

Defining the Business Network

A business network in Hyperledger Composer is defined by a set of models (the assets, participants, and transactions) and scripts (the business logic, or smart contracts). We define these in the models and lib directories, respectively.

For example, we might define an asset Car and a transaction TradeCar in our model file (models/org.example.mynetwork.cto).

asset Car identified by vin {
  o String vin
  --> Member owner
}

transaction TradeCar {
  --> Car car
  --> Member newOwner
}

In the lib directory, we then define the business logic for the TradeCar transaction in a script file (lib/logic.js).

function tradeCar(trade) {
  trade.car.owner = trade.newOwner;
  return getAssetRegistry('org.example.mynetwork.Car')
    .then(function (assetRegistry) {
      return assetRegistry.update(trade.car);
    });
}

Code Examples

Example 1: Defining a Simple Asset

/* Define an asset 'SampleAsset' with a string property 'value' */
asset SampleAsset identified by assetId {
  o String assetId
  o String value
}

Example 2: Writing a Simple Transaction

/* Define a transaction 'SampleTransaction' that changes the 'value' of a 'SampleAsset' */
transaction SampleTransaction {
  --> SampleAsset asset
  o String newValue
}

/* In your script file, write the function that implements the transaction */
function sampleTransaction(tx) {
  tx.asset.value = tx.newValue;
  return getAssetRegistry('org.example.mynetwork.SampleAsset')
    .then(function (assetRegistry) {
      return assetRegistry.update(tx.asset);
    });
}

Summary

In this tutorial, we learned how to set up our development environment for Hyperledger Composer, how to define assets and transactions in a business network, and how to write the business logic for these transactions in the form of smart contracts.

As next steps, you might want to explore more complex business networks, with multiple types of assets and participants, and more complex transactions. You can also learn how to test your business network and how to deploy it on a real blockchain.

Practice Exercises

  1. Define a business network for a simple supply chain, with assets Product and Shipment, and a transaction DeliverShipment.

  2. Write a transaction that changes the ownership of a car from one member to another.

  3. Write a transaction that splits a shipment into two smaller shipments.

Solutions

  1. Here's a possible solution for a simple supply chain network.
asset Product identified by productId {
  o String productId
  o String description
  o Double price
}

asset Shipment identified by shipmentId {
  o String shipmentId
  --> Product[] products
  --> Member owner
}

transaction DeliverShipment {
  --> Shipment shipment
  --> Member newOwner
}
  1. Here's a possible solution for a car ownership change.
transaction ChangeOwner {
  --> Car car
  --> Member newOwner
}

function changeOwner(tx) {
  tx.car.owner = tx.newOwner;
  return getAssetRegistry('org.example.mynetwork.Car')
    .then(function (assetRegistry) {
      return assetRegistry.update(tx.car);
    });
}
  1. Here's a possible solution for splitting a shipment.
transaction SplitShipment {
  --> Shipment shipment
  o Product[] productsOne
  o Product[] productsTwo
}

function splitShipment(tx) {
  var shipmentOne = factory.newResource('org.example.mynetwork', 'Shipment', 'SHIP1');
  shipmentOne.products = tx.productsOne;
  shipmentOne.owner = tx.shipment.owner;

  var shipmentTwo = factory.newResource('org.example.mynetwork', 'Shipment', 'SHIP2');
  shipmentTwo.products = tx.productsTwo;
  shipmentTwo.owner = tx.shipment.owner;

  return getAssetRegistry('org.example.mynetwork.Shipment')
    .then(function (assetRegistry) {
      return assetRegistry.addAll([shipmentOne, shipmentTwo]);
    });
}