All Projects → Zilliqa → Zilliqa Javascript Library

Zilliqa / Zilliqa Javascript Library

Licence: gpl-3.0
JavaScript library for Zilliqa blockchain

Programming Languages

typescript
32286 projects

Zilliqa-JavaScript-Library API

Build Status codecov Discord Chat
lerna npm version

Introduction

zilliqa-js is structured as a Lerna monorepo. Each package roughly corresponds to a discrete ZilliqaModule, most of which can be used independently.

The only required package is @zilliqa-js/core, which contains the default HTTPProvider, and other core abstractions that are necessary for other modules to function.

The following table provides a description of each module and what you may want to use it for.

package description dependencies
@zilliqa-js/core Core abstractions and base classes, such as HTTPProvider and network logic for interfacing with the Zilliqa JSON-RPC. none
@zilliqa-js/account Wallet, Account and Transaction abstractions live in this package. @zilliqa-js/core, @zilliqa-js/crypto, @zilliqa-js/util, @zilliqa-js/proto
@zilliqa-js/blockchain Main interface to the Zilliqa JSON-RPC. none
@zilliqa-js/contract Exposes a Contracts module that takes care of smart contract deployment and interaction. @zilliqa-js/account, @zilliqa-js/blockchain, @zilliqa-js/core, @zilliqa-js/util
@zilliqa-js/crypto Exposes several loosely-coupled cryptographic convenience functions for working with the Zilliqa blockchain and its cryptographic primitives, such as Schnorr signatures. @zilliqa-js/util
@zilliqa-js/proto Protobuf source files and corresponding generated JS modules. none
@zilliqa-js/util Miscellaneous functions that take care of serialisation/deserialisation and validation. none
@zilliqa-js/viewblock Library interfacing with ViewBlock's APIs @zilliqa-js/crypto

Pre-Requisite (Windows Users)

zilliqa-js uses scrypt library which depends on node-gyp in order to compile the binaries from source on Windows. node-gyp on Windows requires users to install additional Visual Studio Build tools.

To install the required Visual Studio Build tools:

npm install --global --production windows-build-tools # from an elevated PowerShell or CMD.exe as Administrator

npm config set msvs_version 2015 # 2015 is more compatible; though 2017 may work too

Refer to https://github.com/nodejs/node-gyp#installation for more information about node-gyp installation on Windows.

Installation

It is recommended that developers install the JavaScript client by making use of the umbrella package @zilliqa-js/zilliqa. This takes care of bootstrapping the various modules, which are then accessible as members of the Zilliqa class.

yarn add @zilliqa-js/zilliqa
# you may also need to install the tslib package.
yarn add tslib
# bn.js should be added with the above package. if it is not, install it manually.
yarn add bn.js

Quick Start

Ideally, you should Create a new Nucleus Wallet (an open source Zilliqa testnet wallet).

You should 'fund' the wallet by sending testnet ZIL tokens from the ZIL faucet

You should then replace the value of const privateKey with the one from this wallet.

The code should work with the existing private key but this cannot be guaranteed.

const { BN, Long, bytes, units } = require('@zilliqa-js/util');
const { Zilliqa } = require('@zilliqa-js/zilliqa');
const {
  toBech32Address,
  getAddressFromPrivateKey,
} = require('@zilliqa-js/crypto');

const zilliqa = new Zilliqa('https://dev-api.zilliqa.com');

// These are set by the core protocol, and may vary per-chain.
// You can manually pack the bytes according to chain id and msg version.
// For more information: https://apidocs.zilliqa.com/?shell#getnetworkid

const chainId = 333; // chainId of the developer testnet
const msgVersion = 1; // current msgVersion
const VERSION = bytes.pack(chainId, msgVersion);

// Populate the wallet with an account
const privateKey =
  '3375F915F3F9AE35E6B301B7670F53AD1A5BE15D8221EC7FD5E503F21D3450C8';

zilliqa.wallet.addByPrivateKey(privateKey);

const address = getAddressFromPrivateKey(privateKey);
console.log(`My account address is: ${address}`);
console.log(`My account bech32 address is: ${toBech32Address(address)}`);

async function testBlockchain() {
  try {
    // Get Balance
    const balance = await zilliqa.blockchain.getBalance(address);
    // Get Minimum Gas Price from blockchain
    const minGasPrice = await zilliqa.blockchain.getMinimumGasPrice();

    // Account balance (See note 1)
    console.log(`Your account balance is:`);
    console.log(balance.result);
    console.log(`Current Minimum Gas Price: ${minGasPrice.result}`);
    const myGasPrice = units.toQa('1000', units.Units.Li); // Gas Price that will be used by all transactions
    console.log(`My Gas Price ${myGasPrice.toString()}`);
    const isGasSufficient = myGasPrice.gte(new BN(minGasPrice.result)); // Checks if your gas price is less than the minimum gas price
    console.log(`Is the gas price sufficient? ${isGasSufficient}`);

    // Send a transaction to the network
    console.log('Sending a payment transaction to the network...');
    const tx = await zilliqa.blockchain.createTransaction(
      // Notice here we have a default function parameter named toDs which means the priority of the transaction.
      // If the value of toDs is false, then the transaction will be sent to a normal shard, otherwise, the transaction.
      // will be sent to ds shard. More info on design of sharding for smart contract can be found in.
      // https://blog.zilliqa.com/provisioning-sharding-for-smart-contracts-a-design-for-zilliqa-cd8d012ee735.
      // For payment transaction, it should always be false.
      zilliqa.transactions.new(
        {
          version: VERSION,
          toAddr: '0xA54E49719267E8312510D7b78598ceF16ff127CE',
          amount: new BN(units.toQa('1', units.Units.Zil)), // Sending an amount in Zil (1) and converting the amount to Qa
          gasPrice: myGasPrice, // Minimum gasPrice veries. Check the `GetMinimumGasPrice` on the blockchain
          gasLimit: Long.fromNumber(1),
        },
        false,
      ),
    );

    console.log(`The transaction status is:`);
    console.log(tx.receipt);

    // Deploy a contract
    console.log(`Deploying a new contract....`);
    const code = `scilla_version 0

    (* HelloWorld contract *)

    import ListUtils

    (***************************************************)
    (*               Associated library                *)
    (***************************************************)
    library HelloWorld

    let not_owner_code = Int32 1
    let set_hello_code = Int32 2

    (***************************************************)
    (*             The contract definition             *)
    (***************************************************)

    contract HelloWorld
    (owner: ByStr20)

    field welcome_msg : String = ""

    transition setHello (msg : String)
      is_owner = builtin eq owner _sender;
      match is_owner with
      | False =>
        e = {_eventname : "setHello()"; code : not_owner_code};
        event e
      | True =>
        welcome_msg := msg;
        e = {_eventname : "setHello()"; code : set_hello_code};
        event e
      end
    end


    transition getHello ()
        r <- welcome_msg;
        e = {_eventname: "getHello()"; msg: r};
        event e
    end`;

    const init = [
      // this parameter is mandatory for all init arrays
      {
        vname: '_scilla_version',
        type: 'Uint32',
        value: '0',
      },
      {
        vname: 'owner',
        type: 'ByStr20',
        value: `${address}`,
      },
    ];

    // Instance of class Contract
    const contract = zilliqa.contracts.new(code, init);

    // Deploy the contract.
    // Also notice here we have a default function parameter named toDs as mentioned above.
    // A contract can be deployed at either the shard or at the DS. Always set this value to false.
    const [deployTx, hello] = await contract.deploy(
      {
        version: VERSION,
        gasPrice: myGasPrice,
        gasLimit: Long.fromNumber(10000),
      },
      33,
      1000,
      false,
    );

    // Introspect the state of the underlying transaction
    console.log(`Deployment Transaction ID: ${deployTx.id}`);
    console.log(`Deployment Transaction Receipt:`);
    console.log(deployTx.txParams.receipt);

    // Get the deployed contract address
    console.log('The contract address is:');
    console.log(hello.address);
    //Following line added to fix issue https://github.com/Zilliqa/Zilliqa-JavaScript-Library/issues/168
    const deployedContract = zilliqa.contracts.at(hello.address);

    // Create a new timebased message and call setHello
    // Also notice here we have a default function parameter named toDs as mentioned above.
    // For calling a smart contract, any transaction can be processed in the DS but not every transaction can be processed in the shards.
    // For those transactions are involved in chain call, the value of toDs should always be true.
    // If a transaction of contract invocation is sent to a shard and if the shard is not allowed to process it, then the transaction will be dropped.
    const newMsg = 'Hello, the time is ' + Date.now();
    console.log('Calling setHello transition with msg: ' + newMsg);
    const callTx = await hello.call(
      'setHello',
      [
        {
          vname: 'msg',
          type: 'String',
          value: newMsg,
        },
      ],
      {
        // amount, gasPrice and gasLimit must be explicitly provided
        version: VERSION,
        amount: new BN(0),
        gasPrice: myGasPrice,
        gasLimit: Long.fromNumber(8000),
      },
      33,
      1000,
      false,
    );

    // Retrieving the transaction receipt (See note 2)
    console.log(JSON.stringify(callTx.receipt, null, 4));

    //Get the contract state
    console.log('Getting contract state...');
    const state = await deployedContract.getState();
    console.log('The state of the contract is:');
    console.log(JSON.stringify(state, null, 4));
  } catch (err) {
    console.log(err);
  }
}

testBlockchain();

Notes on the Quick Start script

Note 1: Account balance

The account balance is an object with two fields, balance and nonce.

balance is the account balance in Qa, which is the lowest denomination in Zilliqa. For more information about gas accounting, please refer to here: https://forum.zilliqa.com/t/gas-accounting-in-zilliqa/199

nonce is a counter that keeps track of how many transactions are sent from a given address. In Zilliqa, every transaction sent from an address must have a unique nonce.

{ "balance": "296505000000000", "nonce": "3" }

Note 2: Retrieving transaction receipt

An example of a transaction receipt is this:

{
    "cumulative_gas": 357,
    "epoch_num": "676201",
    "event_logs": [
        {
            "_eventname": "setHello()",
            "address": "0x7a4aa130650396ab7c4006c471576a8404f5092b",
            "params": [
                {
                    "type": "Int32",
                    "value": "2",
                    "vname": "code"
                }
            ]
        }
    ],
    "success": true
}

event_logs comprises of all the events emitted in the transaction. For example, if your transaction calls a transition which emits 3 events, it will be an array of three events. The address is the contract address of the contract which emits the event.

success indicates if the transaction is successful.

API Documentation and examples

Each package contains its own examples and API documentation. For convenience, these are links to the respective README documents.

Development

This repository makes use of several technologies to provide a better and faster development experience for contributors, and has to be bootstrapped before one can do productive work.

Bootstrapping

zilliqa-js leverages Project References, which is available in TypeScript from version 3.x. As such, the build process is slightly different.

# install all dependencies and shared devDependencies
yarn install

# symlink packages, compile TS source files, and generate protobuf files.
yarn bootstrap

# watch TS source files and recompile on change
yarn build:ts -w

Tests

Unit Test

Tests for each package reside in packages/src/*/tests, and are run using jest. Files containing unit tests always have the prefix *.spec.ts, while integration/e2e tests have the prefix *.ispec.ts.

In order to run any tests, you must first make sure the source files are compiled and all dependencies are installed by running yarn bootstrap.

Integration Test

If you wish to run integration tests, you may do so against a local or remote Zilliqa testnet. However, note that the public testnet may not always be caught up to the state-of-the-art, and, therefore, can cause zilliqa-js to behave in unexpected ways.

# run all unit tests
yarn test

# configure environment variables
# $GENESIS_PRIV_KEY - the private key used to run transaction-related tests
# $GENESIS_ADDRESS - the address for the private key
# HTTP_PROVIDER - the URL of the Zilliqa JSON-RPC server
# MNEMONIC - the seed words of the wallet account used to run transaction-related tests
# CHAIN_ID - the chain ID of the specified network
vim .env

# run all integration tests
yarn test:integration

Local Test

To test with a local project without publishing it, you can use yarn link to create a sym-link to the SDK in development.

yarn link [zilliqaJs-projectDir]/packages/zilliqa

# cd to your local project
yarn link @zilliqa-js/zilliqa

Bundling

rollup

zilliqa-js is bundled using rollup. To build the distributable bundles, simple run yarn bundle. This will output two bundles, *.umd.js and *.esm.js, to packages/*/dist. Node.js clients are pointed to the umd bundle, and bundlers are pointed to esm.

NOTE: these bundles are not minified.

webpack

To build an all-in-one static js file, first install webpack globally using yarn global add webpack. Then run yarn build:web. This will generate a dist folder in the current path, which contains a file called zilliqa.min.js. It can be used in normal html file. (A more specific example please refer to example/webpack)

NOTE: there may be some issue to install webpack with npm, thus using yarn is a recommended way

Licence

You can view our licence here.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].