Skip to content

Developing with Hardhat


Note that the Scilla hardhat plugin is currently experimental; use at your own risk

Developing, testing and deploying contracts for both Scilla and EVM is conveniently done with hardhat. There is a (currently experimental) hardhat plugin allowing you to test Scilla contracts.

To get this working:

1. Install the scilla tools

git clone https://github.com/Zilliqa/scilla.git

And follow the instructions in the INSTALL.md. This should leave you with the scilla-checker and scilla-fmt binaries in your path.

2. Initialise a new hardhat project

mkdir contract_dev
cd contract_dev
yarn init
yarn add --dev hardhat
npx hardhat

Select create a new typescript project.

Now:

yarn add git+https://github.com/zilliqa/hardhat-scilla-plugin

and add the following to hardhat.config.js:

import "hardhat-scilla-plugin"

Now you can deploy a contract by adding the source code as contracts/Hello.scilla:

scilla_version 0

library MetaSayHello

type Error =
| NotOwner

let make_error =
  fun (result: Error) =>
    let result_code =
      match result with
     | NotOwner => Int32 -1
      end
    in
    { _exception: "Error"; code: result_code }


contract SayHello(
 init_contract_owner: ByStr20,
 init_string : String
 )

field message : String = init_string
field owner : ByStr20 = init_contract_owner

procedure Throw(error: Error)
  e = make_error error;
  throw e
end

procedure AssertOwner(address: ByStr20)
   my_owner <- owner;
   is_owner = builtin eq my_owner address;
   match is_owner with
   | True => (* Yep *)
   | False =>
     err = NotOwner;
     Throw err
   end
end

transition SetMessage(in_message: String)
  AssertOwner _sender;
  message := in_message
end

transition SayHello()
  a_msg <- message;
  e = { _eventname: "Hello";
       message: a_msg
       };
  event e
end

and a deployment script, scripts/deploy.ts:

import { expect } from 'chai';
import { ScillaContract, initZilliqa } from 'hardhat-scilla-plugin';
import hre, { ethers } from 'hardhat';

describe("Hello", function () {
    const privateKeys = [ "<your private key>" ];
    const network_url = "<network URL>";
    const chain_id = <chain_id>;

    before("set up the network", async function () {
        initZilliqa(network_url, chain_id, privateKeys);

        let contract: ScillaContract = await hre.deployScilla("SayHello", "5c2d46955de58033638f552bfd1bca408e6fc8ac", "TestA");
        console.log(`Contract ${JSON.stringify(contract)}`)
    });

    it("should do nothing", async function() {
    });
});

Run your script:

npx hardhat scripts/deploy.ts

It's often useful to run:

mitmweb --reverse:https://dev-api.zilliqa.com -p 8082

So you can monitor what calls are being made. You can generate keys for testing using zli (but one day there will be a plugin function to allow you to do this).

There are examples of this in zilliqa-developer and in our acceptance test suite in our acceptance tests.

Here is a sample networks stanza for your hardhat.config.ts; the keys configured for isolated server and other environments are the default test private keys, which are loaded with large balances at network startup:

  networks: {
    isolated_server: {
      url: "http://localhost:5555/",
      websocketUrl: "ws://localhost:5555/",
      accounts: [
        "d96e9eb5b782a80ea153c937fa83e5948485fbfc8b7e7c069d7b914dbc350aba",
        "589417286a3213dceb37f8f89bd164c3505a4cec9200c61f7c6db13a30a71b45",
        "e7f59a4beb997a02a13e0d5e025b39a6f0adc64d37bb1e6a849a4863b4680411",
        "410b0e0a86625a10c554f8248a77c7198917bd9135c15bb28922684826bb9f14"
      ],
      chainId: 0x8001,
      web3ClientVersion: "Zilliqa/v8.2",
      protocolVersion: 0x41,
      zilliqaNetwork: true,
      miningState: false
    },
    ganache: {
      url: "http://localhost:7545",
      websocketUrl: "ws://localhost:7545",
      chainId: 1337,
      web3ClientVersion: "Ganache/v7.4.1/EthereumJS TestRPC/v7.4.1/ethereum-js",
      protocolVersion: 0x3f,
      accounts: [
        // memonic: guard same cactus near figure photo remove letter target alien initial remove
        "67545ce31f5ca86719cf3743730435768515ebf014f84811463edcf7dcfaf91e",
        "9be4f8840833f64d4881027f4a53961d75bc649ac4801b33f746487ca8873f14",
        "32a75b674cc41405c914de1fe7b031b832dfd9203e1a287d09122bab689519e3",
        "dd8ce58f8cecd59fde7000fff9944908e89364b2ef36921c35725957617ddd32"
      ],
      zilliqaNetwork: false,
      miningState: true
    },
    public_testnet: {
      url: "https://evm-api-dev.zilliqa.com",
      websocketUrl: "https://evm-api-dev.zilliqa.com",
      accounts: [
        "d96e9eb5b782a80ea153c937fa83e5948485fbfc8b7e7c069d7b914dbc350aba",
        "db11cfa086b92497c8ed5a4cc6edb3a5bfe3a640c43ffb9fc6aa0873c56f2ee3",
        "410b0e0a86625a10c554f8248a77c7198917bd9135c15bb28922684826bb9f14",
        "589417286a3213dceb37f8f89bd164c3505a4cec9200c61f7c6db13a30a71b45"
      ],
      chainId: 33101,
      zilliqaNetwork: true,
      web3ClientVersion: "Zilliqa/v8.2",
      protocolVersion: 0x41,
      miningState: false
    },
    localdev: {
      url: "http://localhost:5301",
      websocketUrl: "ws://localhost:5301",
      accounts: [
        "d96e9eb5b782a80ea153c937fa83e5948485fbfc8b7e7c069d7b914dbc350aba",
        "589417286a3213dceb37f8f89bd164c3505a4cec9200c61f7c6db13a30a71b45",
        "e7f59a4beb997a02a13e0d5e025b39a6f0adc64d37bb1e6a849a4863b4680411",
        "410b0e0a86625a10c554f8248a77c7198917bd9135c15bb28922684826bb9f14"
      ],
      chainId: 0x8001,
      web3ClientVersion: "Zilliqa/v8.2",
      protocolVersion: 0x41,
      zilliqaNetwork: true,
      miningState: false
    }
  },