How to write Chaincode Contract for Hyperledger Fabric in TypeScript
Tags: blockchain, typescript, tutorial, opensource
Published: 2021-02-14 12:36:07

_*Hello developer, in this tutorial we will learn how to create Chaincode Contract for Hyperledger Fabric. This post is the first of a series dedicated to setting up a development environment for Hyperledger Fabric.*_

### Create a folder and a package.json file
```bash
$ mkdir contracts/myFirstContract
$ cd contracts/myFirstContract
$ touch package.json
```

### Edit contracts/myFirstContract/package.json file (replace with this)
```json
{
    "name": "myfirstcontract",
    "version": "0.1.0",
    "description": "Hyperledger Fabric Chaincode Contract",
    "main": "dist/index.js",
    "typings": "dist/index.d.ts",
    "engines": {
        "node": ">=8",
        "npm": ">=5"
    },
    "scripts": {
        "lint": "tslint -c tslint.json './**/*.ts'  -e './node_modules/**'",
        "pretest": "npm run lint",
        "start": "fabric-chaincode-node start",
        "build": "tsc",
        "build:watch": "tsc -w",
        "prepublishOnly": "npm run build"
    },
    "engineStrict": true,
    "author": "Hyperledger",
    "license": "Apache-2.0",
    "dependencies": {
        "fabric-contract-api": "^2.0.0",
        "fabric-shim": "^2.0.0",
        "hyperledger-fabric-chaincode-helper": "^0.0.14"
    },
    "devDependencies": {
        "@types/chai": "^4.1.7",
        "@types/mocha": "^5.2.5",
        "@types/node": "^10.12.10",
        "@types/sinon": "^5.0.7",
        "@types/sinon-chai": "^3.2.1",
        "chai": "^4.2.0",
        "mocha": "^5.2.0",
        "nyc": "^14.1.1",
        "sinon": "^7.1.1",
        "sinon-chai": "^3.3.0",
        "ts-node": "^7.0.1",
        "tslint": "^5.11.0",
        "typescript": "^3.1.6"
    },
    "nyc": {
        "extension": [
            ".ts",
            ".tsx"
        ],
        "exclude": [
            "coverage/**",
            "dist/**"
        ],
        "reporter": [
            "text-summary",
            "html"
        ],
        "all": true,
        "check-coverage": true,
        "statements": 100,
        "branches": 100,
        "functions": 100,
        "lines": 100
    },
    "resolutions": {
        "class-transformer": "^0.3.1",
        "minimist": "^0.2.1"
    }
}
 
```

```bash
$ npm install
```

### Create: contracts/myFirstContract/typescript/tsconfig.json

```bash
$ touch typescript/tsconfig.json
```

```json
{
  "compilerOptions": {
      "outDir": "dist",
      "target": "es2017",
      "moduleResolution": "node",
      "module": "commonjs",
      "declaration": true,
      "sourceMap": true
  },
  "include": [
      "./**/*.ts"
  ],
  "exclude": [
      "./**/*.spec.ts"
  ]
}

```

### Create: contracts/myFirstContract/typescript/tslint.json

```bash
$ touch typescript/tslint.json
```

```json
{
  "defaultSeverity": "error",
  "extends": [
      "tslint:recommended"
  ],
  "jsRules": {},
  "rules": {
      "indent": [true, "spaces", 4],
      "linebreak-style": [true, "LF"],
      "quotemark": [true, "single"],
      "semicolon": [true, "always"],
      "no-console": false,
      "curly": true,
      "triple-equals": true,
      "no-string-throw": true,
      "no-var-keyword": true,
      "no-trailing-whitespace": true,
      "object-literal-key-quotes": [true, "as-needed"]
  },
  "rulesDirectory": []
}
```

### Create the entry file: contracts/myFirstContract/typescript/index.ts

```bash
$ touch typescript/index.ts
```

```typescript
'use strict';

import { MyFirstContract } from './lib/myfirstcontract';
export { MyFirstContract } from './lib/myfirstcontract';

export const contracts: any[] = [ MyFirstContract ];
```

### Create the main file: contracts/myFirstContract/typescript/lib/myfirstcontract.ts

```bash
$ touch typescript/lib/myfirstcontract.ts
```

```typescript
/*
 * SPDX-License-Identifier: Apache-2.0
 */

'use strict';

import { BlockotusContract } from 'hyperledger-fabric-chaincode-helper';

import type { Context } from 'fabric-contract-api';

export class MyFirstContract extends BlockotusContract {

    constructor(...args) {
        super(...args);
    }

    public async initLedger() {
        console.log('initLedger');
    }

    public helloWorld(ctx: Context) {
        const params = this.getParams(ctx);
        return `Hello ${params[0]}`;
    }

}

```

Here we are, your first contract with no functionality is ready! :champagne: