Taxonomy Icon


Learning objectives

Date fruit trading is a centuries-old industry that has been hampered by challenges such as poor tracking, decreasing transparency, and substantial regulatory burdens. In this tutorial, I’ll use date trading as a use case to show you how blockchain technology can be used to disrupt the food trading industry.


A basic knowledge of JavaScript is helpful in understanding this tutorial.

Estimated time

Completing this tutorial should take about 30 minutes.


The date is the fruit of the date palm tree (Phoenix dactylifera). Dates are considered a fundamental food in the Middle East, with Egypt and Saudi Arabia leading the world in date production. As trade developed worldwide, dates were introduced to regions in Northern Africa, Southwest Asia, Spain, Mexico, and the U.S. Some date varieties are exclusive to specific countries, while others are common between countries. Even in a country like Saudi Arabia, each region is known for specific varieties: Al Madinah is known for Ajwa, Al Hasa for Kholas, and Al Qassim for Sokkari.

Figure 1. Some types of dates

Some types of dates

Trading journey

After they sprout on the palm trees and before they arrive on grocery store shelves, dates go through several stages:

At the farm

Most date farms use a forklift truck to harvest the fruit. A picker is lifted into the tree and they hang a plastic tray underneath the date bunches to be harvested. The picker then shakes out any dates that have already ripened and fallen off the strands. Once the tray is full, it is lowered down and packed to be sent to a factory for cleaning, sorting, and packaging.

At the factory

Once the packages arrive at the factory, any rotten dates are filtered out manually before cleaning. The dates are then rinsed with hot water and dried to clean and disinfect them. After cleaning, the dates are sorted and graded (by either human or computer) to assess the quality of the fruit, based on factors like dimensions and blistering. Next, the dates are moved to a vacuum line for packaging and sealing. The labeled packages are then moved to cold storage before going to market.

At the market

The producer sells the dates at wholesale or retail trade. Production costs account for 40 percent of the sale price. A research study on the marketing cost structure of dates in Saudi Arabia found that the average retail price of dates is almost twice as much as the wholesale price, and that labor and storage costs are the most significant factors affecting date market pricing. If export mechanisms evolve, the annual revenue for Saudi Arabian dates is estimated to reach 10 billion Saudi Riyals (about 2.7 billion USD).

Figure 2. Stages of the date lifecycle

Date lifecycle stages

Blockchain for dates

Blockchain trading is all about keeping a record of every transaction. This makes it easier to track dates from farms to markets to your table, which increases food authenticity. Tracing dates throughout this process also helps to identify the sources of infectious organisms when poisoning occurs.

Figure 3. Blockchain network for date trading

Blockchain network for date trading

Let’s implement it!

Now I’ll show you how to implement a blockchain using Hyperledger Composer Playground, an open development toolset and framework that simplifies the development of blockchain applications. The process consists of three steps.

Step 0. Create a new business network

Once you go to Hyperledger Composer Playground, click on Deploy a new business network to get started. Choose empty-business-network and then click Deploy.

Step 1. Modeling

In the model file, you define the business network using an object-oriented modeling language. It is comprised of participants, assets, and transactions, and these resources are all wrapped in a namespace.


As you know, this process has three types of participants: farm, factory, and souq (marketplace). Since they all share the same properties, you need to create an abstract participant class and all participants will extend from it:

abstract participant Business identified by id {
  o String id
  o Address address
  o Double accountBalance

participant Farm extends Business {

participant DatesFactory extends Business {

participant Souq extends Business {

You can see that the id and accountBalance properties have String and Double primitive types, while Address is defined as follows:

concept Address {
  o String city
  o String street optional
  o String zip optional


The main asset you are tracking is Package, which contains a specific number of date boxes that all contain one type of date. The second asset is the Contract between the participants, in which they agree on an arrival time and box price before the first transaction occurs.

asset Package identified by packageId {
  o String packageId
  o PackageStatus status
  o DateType type
  o Long boxCount
  --> Contract contract

asset Contract identified by contractId {
  o String contractId
  --> Farm farm
  --> DatesFactory datesFactory
  --> Souq souq
  o DateTime arrivalDateTime
  o Double boxPrice

Since PackageStatus and DateType have a limited number of possible values, you define them as enumerated types:

enum DateType {
  o AJWA  

enum PackageStatus {

There are a lot more types of dates, but let’s work with three for the sake of simplicity.


First, the farm sends the package to the factory. Once the dates are packaged, they are then sent to the souq to be sold. The amount of money the souq then sends to the farm is determined by the box price and the arrival time.

abstract transaction PackageTransaction {
  --> Package package

transaction SendPackageToFactory extends PackageTransaction {

transaction SendPackageToSouq extends PackageTransaction {

transaction SendMoneyToFarm extends PackageTransaction {

I’ve included one additional transaction for setting up a demo. I’ll explain the function of this transaction in the next section.

transaction SetupDemo {

Step 2. Scripting

Once the domain model is in place, you can implement the executable transaction processor functions, which are written in the script file in JavaScript.

In the setupDemo transaction, you create and initialize an object from each asset and participant; it is then added to the registry:

async function setupDemo(setupDemo) {  // eslint-disable-line no-unused-vars

const factory = getFactory();

    const farm = factory.newResource(NS, 'Farm', 'farm1');
    const farmAddress = factory.newConcept(NS, 'Address'); = 'Qassim';
    farm.address = farmAddress;
    farm.accountBalance = 0;

    const souq = factory.newResource(NS, 'Souq', 'souq1');
    const souqAddress = factory.newConcept(NS, 'Address'); = 'Riyadh';
    souq.address = souqAddress;
    souq.accountBalance = 0;

    const datesFactory = factory.newResource(NS, 'DatesFactory', 'datesFactory1');
    const datesFactoryAddress = factory.newConcept(NS, 'Address'); = 'Qassim';
    datesFactory.address = datesFactoryAddress;
    datesFactory.accountBalance = 0;

    const contract = factory.newResource(NS, 'Contract', 'contract1'); = factory.newRelationship(NS, 'Farm', 'farm1');
    contract.souq = factory.newRelationship(NS, 'Souq', 'souq1');
    contract.datesFactory = factory.newRelationship(NS, 'DatesFactory', 'datesFactory1');
    const tomorrow = setupDemo.timestamp;
    tomorrow.setDate(tomorrow.getDate() + 1);
    contract.arrivalDateTime = tomorrow; // the package has to arrive tomorrow
    contract.boxPrice = 50; // pay 50 SR per box

    const package = factory.newResource(NS, 'Package', 'package1');
    package.type = 'AJWA';
    package.status = 'INITIAL_STATE';
    package.boxCount = 100;
    package.contract = factory.newRelationship(NS, 'Contract', 'contract1');

    const farmRegistry = await getParticipantRegistry(NS + '.Farm');
    await farmRegistry.addAll([farm]);

    const souqRegistry = await getParticipantRegistry(NS + '.Souq');
    await souqRegistry.addAll([souq]);

    const datesFactoryRegistry = await getParticipantRegistry(NS + '.DatesFactory');
    await datesFactoryRegistry.addAll([datesFactory]);

    const contractRegistry = await getAssetRegistry(NS + '.Contract');
    await contractRegistry.addAll([contract]);

    const packageRegistry = await getAssetRegistry(NS + '.Package');
    await packageRegistry.addAll([package]);

The package status is then updated by sendPackageToFactory and sendPackageToSouq:

async function sendPackageToFactory(sendPackageToFactory) {  // eslint-disable-line no-unused-vars
    var factory = getFactory();
    sendPackageToFactory.package.status = 'FACTORY_PACKAGING';
    return getAssetRegistry(NS + '.Package').then(function (registry) {
      return registry.update(sendPackageToFactory.package);

async function sendPackageToSouq(sendPackageToSouq) {  // eslint-disable-line no-unused-vars
    var factory = getFactory();
    sendPackageToSouq.package.status = 'PACKAGE_READY';
    return getAssetRegistry(NS + '.Package').then(function (registry) {
      return registry.update(sendPackageToSouq.package);

The final transaction is sendMoneyToFarm, which is named to payOut, which does the following:

  • Calculates the payout as boxPrice multiplied by boxCount.
  • Updates the status to PACKAGE_RECIEVED.
  • Changes the payout value to zero if the package arrives later than the time specified in the contract. (This may sound harsh, but it’s designed for simplicity; in a real case, you could add a penalty in the contract rather than not paying at all.)
async function payOut(sendMoneyToFarm) {  // eslint-disable-line no-unused-vars

const contract = sendMoneyToFarm.package.contract;
    const package = sendMoneyToFarm.package;
    let payOut = contract.boxPrice * package.boxCount;

console.log('Received at: ' + sendMoneyToFarm.timestamp);
    console.log('Contract arrivalDateTime: ' + contract.arrivalDateTime);

    package.status = 'PACKAGE_RECIEVED';

    if (sendMoneyToFarm.timestamp > contract.arrivalDateTime) {
        payOut = 0;
        console.log('Late package');

console.log('Payout: ' + payOut); += payOut;
    contract.souq.accountBalance -= payOut;

console.log('Farm: ' +$identifier + ' new balance: ' +;
    console.log('Souq: ' + contract.souq.$identifier + ' new balance: ' + contract.souq.accountBalance);

    const farmRegistry = await getParticipantRegistry('');
    await farmRegistry.update(;

    const souqRegistry = await getParticipantRegistry('');
    await souqRegistry.update(contract.souq);

    const packageRegistry = await getAssetRegistry('');
    await packageRegistry.update(package);

Step 3. Define the access control rules

For each business network, there will be one access control file. This file defines the access control rules for the business network. For simplicity, you’ll use the basic file which gives the current user, NetworkAdmin, full access to business network and system-level operations.

rule NetworkAdminUser {
    description: "Grant business network administrators full access to user resources"
    participant: "org.hyperledger.composer.system.NetworkAdmin"
    operation: ALL
    resource: "**"
    action: ALLOW

rule NetworkAdminSystem {
    description: "Grant business network administrators full access to system resources"
    participant: "org.hyperledger.composer.system.NetworkAdmin"
    operation: ALL
    resource: "org.hyperledger.composer.system.**"
    action: ALLOW


In this tutorial, you learned how to apply and implement a blockchain to track date packages from farm to market. There are many deployment options to test your business network. Playground offers a user interface that enables you to quickly model and test a blockchain network. If you want to import the business network in this tutorial, you can find it here.