Tezos (Part 4): How to Integrate JavaScript with Smart Contracts and Run Unit Tests

Protofire.io
Protofire Blog
Published in
7 min readMar 26, 2020

With code samples, this tutorial demonstrates how to use Taquito — a TypeScript library — to compile, deploy, and test smart contracts.

Getting started | Part 1 | Part 2 | Part 3 | Part 4

All steps executed in this article are based on the DeFi smart contracts, which were discussed in our latest series on Tezos. In these blog posts, we explained how to get started with Tezos and choose a language for a smart contract, as well as demonstrated how to deploy and interact with a contract. Finally, we created a private liquidity pool and overviewed how to deposit and withdraw Tezos tokens (tez) without any restriction.

This blog post explores the use of JavaScript to interact with smart contracts in Tezos. We will focus on Taquito — a tool equivalent to the web3.js library in Solidity — which allows us to call the contracts. With Taquito, we will show how to create a script for compiling smart contracts, activate an account using a faucet, deploy a smart contract, and perform unit tests on the smart contract.

What’s Taquito?

Taquito is a TypeScript library that can be used to create DApps or web applications for Tezos. This library was chosen, because it is currently one of the most important tools in the Tezos ecosystem. It has a high adoption rate and is constantly being updated. Taquito provides:

  • abstractions from smart contracts for simpler interaction with their entry points
  • minimal dependencies
  • a well-documented API
  • good Slack support from the Taquito team

If you have any questions regarding Taquito, join the Tezos developers' Telegram channel and/or visit the Tezos StackExchange.

Get a faucet

Before starting to work with contracts, JavaScript, and Taquito, you need to obtain a Tezos address, along with some Tezos tokens. This is called faucet, and it is required in order to pay for the gas costs associated with the methods called from the smart contracts. You can download the files in JSON format from the public Tezos faucet and install them in the application.

How to install Taquito

To install Taquito, we need to execute the following command with Yarn.

In order to interact with the contracts, set a provider, which Taquito will interpret as the network we want to access. Additionally, identify a signer, which is the account we will use to interact with the contracts. In this case, set the provider to carthagenet, a Tezos testnet. InMemorySigner is a local signer implementation for development scenarios, which allows the direct use of a private key in a browser.

Compilation of a contract

We are going to create a script to compile our contracts. For this purpose, using pure JavaScript will suffice. In our case, we will compile the pool.ligo contract.

const { exec } = require("child_process");const fs = require("fs");exec(`ligo compile-contract --michelson-format=json $PWD/contracts/pool.ligo main | tr -d '\r' `, (err, stdout, stderr) => {   if (err) {       throw err;   }   fs.writeFileSync('./build/pool_factory.json', stdout);});

The contract is compiled to a JSON format of Michelson, which will serve later to facilitate the initialization of the contracts with Taquito.

We can call this script build.js and add it to package.json.

Account activations

To activate the faucets previously obtained, use the activate method provided by the Taquito library.

const { Tezos } = require('@taquito/taquito');const { InMemorySigner } = require('@taquito/signer');const faucetA = require('./faucetA.json');const faucetB = require('./faucetB.json');const faucets = [faucetA, faucetB];const rpc = "https://api.tez.ie/rpc/carthagenet";const signer = InMemorySigner.fromFundraiser(faucetA.email, faucetA.password, faucetA.mnemonic.join(' '));Tezos.setProvider({ rpc, signer });const activateFaucets = async () => {   for (const faucet of faucets) {       const {pkh, secret} = faucet;       const operation = await Tezos.tz.activate(pkh, secret);       await operation.confirmation();   }}(async () => {await activateFaucets();})().catch(e => console.error(e));

Deploying a contract

As the next step, we will deploy a contract to the carthagenet network using Taquito. This can be done by creating the deploy.js file along with the previously activated accounts.

The snippet above demonstrates the following:

  • The JSON file previously compiled is configured as code.
  • The storage is initialized. In order to initialize a map, use the MichelsonMap object provided by Taquito.
  • The previously activated faucet is set as the owner of the contract.
  • Now, wait for the operation to complete, so as to proceed with the next steps.

You can also add this script to package.json.

You can check the sample code in this GitHub repo.

Creating unit tests

After implementing the Tezos smart contracts, we are going to perform some unit tests over them for a few reasons. Unit tests can check small parts of the contract, can be carried out using regular tools, such as a simple node assert module, and are significantly faster than other types of tests.

We are going to create a script that describes the context of the contract operation and, through Taquito, we will test the interaction flow with the data and the status of the contract. This script serves as an example for any user to understand how to take advantage of Taquito to operate with Tezos contracts.

On our contract we have two main functions that we will use to create unit tests: deposit and withdraw. These are going to be represented in the Given-When-Then style.

Deposit unit test

First, we need to create the pool.spec.js file, which includes our contracts, and add a script to the JSON package to execute it.

Let’s start with deposit, where the following preconditions for the test will be checked:

  • contract initialization
  • check the initial balance of the account that will make deposit
  • check the initial balance of the account in the contract that will make deposit
  • set an amount to deposit
const contractAddress = contractDeploy.address;const accountInitialBalance = await Tezos.tz.getBalance(accountFaucetA)const value = 1; // Send 1 tezconst initialStorage = await getStorage(contractAddress, [account]);const initialDepositBalance = initialStorage.deposits[accountFaucetA].tezAmount;

Now, define and proceed with the test flow. With the initialized contract through Taquito, we can perform an action by calling an entry point of the contract.

Finally, describe the expected changes due to the specified behavior.

With this, we have completed our first test.

Withdraw unit test

Next, we can continue and perform another test with the withdraw function in a similar way.

// Givenconst contractAddress = contractDeploy.address;Tezos.setProvider({ rpc, signer });const contract = await Tezos.contract.at(contractAddress);const account = await signer.publicKeyHash();const accountInitialBalance = await Tezos.tz.getBalance(accountFaucetA)const value = 1; // Send 1 tezconst initialStorage = await getStorage(contractAddress, [account]);const initialDepositBalance = initialStorage.deposits[account].tezAmount;const initialLiquidity = initialStorage.liquidity;// Whenconst op = await contract.methods.withdraw(UnitValue).send();await op.confirmation();// Thenconst storageAfter = await getStorage(contractAddress, [account]);const afterDepositBalance = storageAfter.deposits[account].tezAmount;const afterLiquidity = storageAfter.liquidity;const accountFaucetAAfterBalance = await Tezos.tz.getBalance(account);assert(accountAfterBalance.isGreaterThan(accountInitialBalance) && afterDepositBalance.isZero(), 'Withdraw is not working');

The tests can be accessed in the Tezos DeFi DApp GitHub repo.

Summary

As you can see, Taquito provides a much easier way to interact with contracts without the need to use the console. We were able to create a script to compile the contracts, deploy them, and finally create unit tests to verify the contracts are functioning properly. Written in an idiomatic TypeScript style, Taquito also provides a set of ready-made React components perfect for any front- or back-end JavaScript project with minimal dependencies.

Shortly Taquito will be introducing the new Taquito Wallet API for applications that need to interact with wallets. It is anticipated that the Wallet API will be suitable for performing operations on the Tezos blockchain. In addition, the new API will have pack/unpack support in the pipeline, a common Tezos feature for smart contracts. For details about Taquito, check out the project’s GitHub repo.

In the next part, we are going to create an ERC20 contract and enable it to interact with the pool.

--

--

Protofire.io
Protofire Blog

We help token-based startups with protocol & smart contract engineering, high-performance trusted data feeds (oracles), and awesome developer tools (SDKs/APIs).