Deploying Smart Contracts on Testnet with Taquito

Last time, we looked through basic and complex data types in LIGO. The knowledge is sufficient for a simple smart contract. Yet, for the other users to interact with the contract, it has to be deployed on a blockchain.

Developers use special tools to do that. In this lesson, we install the library Taquito and publish a contract on the Tezos testnet.

Installation and test run of Taquito

Taquito is a TypeScript library that simplifies the interaction with the Tezos blockchain and smart contracts. For example, here’s how the manual deployment of a smart contract looks in the Tezos client console:

tezos-client originate contract <contract name>
  for <user> transferring <number of tez> from <from_user>
  running <path to the file with the code>
  --init '<state of storage>'
  --burn-cap <maximum fee>

The deployment script in Taquito looks even simpler:

try {
  const op = await tezos.contract.originate({
    //smart contract code
    code: `{
          `,
    //storage state
    init: ``,
  });

Taquito also enables one to send tokens, check address balances, and develop a simple web interface for a smart contract.

Installing Taquito

To work with Taquito, you will need nodeJS. Download it from the official website and install it on your machine. Then install the package manager yarn. It will download Taquito and automatically write it in the system.

To do so, open the console and execute the following command:

sudo npm install --global yarn

1

Taquito tools are now ready, so all that’s left is to test its operation. Open Visual Studio Code, create a new folder called taq-test, and create two files in it named app.ts and main.ts.

App.ts will record Taquito functions and the basic code, and params and function calls in main.ts. This would simplify the code structure and help us avoid calling functions before declaring them.

2

Open the terminal in VS Code and go to taq-test with the command cd. Then add the Taquito library to the folder:

cd ~/Documents/taq-test

yarn add @taquito/taquito

3

If NodeJS and yarn were installed correctly, the terminal will display a long list of installed files.

Open app.ts and add the following code:

import { TezosToolkit } from '@taquito/taquito'
export class App {
  public async main() {}
}

Add the following in main.ts:

import { App } from './app'

new App().main()

Don’t forget to save the files by pressing ctrl+S or ⌘+S, otherwise, the execution environment will perceive them as empty.

The extension .ts means that the files contain TypeScript code. You will need the TypeScript library to make it work, so execute the following in the VS Code terminal:

sudo npm install typescript --save-dev

4

In case of successful installation, the terminal will show 3 or 4 warnings about licensing and the lack of project description. If there are more warnings, it means you forgot sudo at the start of the command or do it in a folder other than taq-test.

The last step is to execute the script main.ts in the virtual node. To do that, type the following in the terminal:

npx ts-node main.ts

5

The terminal will report the launch of npx with a single string. It means that npx was successfully imported into the Taquito app. As the main function of app.ts is empty, npx has closed it at once. Any other result than that means that you have made a mistake while installing TypeScript or Taquito.

Please note that in order to work with smart contracts, you will have to install Taquito and TypeScript in the project folder every single time. Unlike JavaScript, they are uninstallable globally.

Getting data from the Tezos blockchain through Taquito

Taquito allows one to read address balances in the Tezos network, send tokens, and publish smart contracts. It doesn’t require you to run your own Tezos node: Taquito connects to public nodes via RPC (remote procedure call).

So let’s connect to the mainnet and request the balance from a baker’s address. To do that, we should activate the TezosToolkit library in app.ts and prepare a constant for an RPC link of a Tezos public node:

import { TezosToolkit } from '@taquito/taquito'
export class App {
  //declaring private tezos modifier of TezosToolkit type
  private tezos: TezosToolkit

  //declaring the constructor rpcUrl that will broadcast the Tezos public node address to TezosToolkit
  constructor(rpcUrl: string) {
    this.tezos = new TezosToolkit(rpcUrl)
  }

  public async main() {}
}

Write the RPC link to the Tezos Mainnet public node in main.ts and transfer it to the App class:

import { App } from './app'
//declaring the constant with the node’s address
const RPC_URL = 'https://mainnet.smartpy.io'
//launch App that will broadcast the node’s address to the main function
new App(RPC_URL).main()

When executing npx ts-node main.ts Taquito will get a link to a node but won’t do anything as app.ts contains no methods for interacting with the network. So what we do now is adding a method to get an address balance to app.ts:

import { TezosToolkit } from '@taquito/taquito'
export class App {
  private tezos: TezosToolkit

  constructor(rpcUrl: string) {
    this.tezos = new TezosToolkit(rpcUrl)
  }

  //declaring the method getBalance with input param address
  public getBalance(address: string): void {
    //Taquito sends a request for balance to the node. If the node executed the request, the script displays the value in the console, otherwise it says “Address not found”
    this.tezos.rpc
      .getBalance(address)
      .then((balance) => console.log(balance))
      .catch((e) => console.log('Address not found'))
  }

  public async main() {}
}

Add the baker’s address and call the method getBalance in the main.ts script:

import { App } from './app'

const RPC_URL = 'https://mainnet.smartpy.io'
//declare the constant with the Everstake baker’s address
const ADDRESS = 'tz1aRoaRhSpRYvFdyvgWLL6TGyRoGF51wDjM'
//launching App, sending a link to the node, calling getBalance and sending it the address
new App(RPC_URL).getBalance(ADDRESS)

Launch the script with npx ts-node main.ts.

6

Taquito will return the number of free tez at Everstake’s address.

7

The balance we get is the same as in tzStats.

Creating a testnet account in the Tezos network with Taquito

Transactions have to be signed with a secret key. For those purposes, Taquito uses the module signer that works with blockchain account data. To avoid spending actual tez, we connect to the Tezos testnet. First, we get the address and test tez at the faucet tzalpha. Follow the link, convince them you’re not a robot, and click Get Testnet tez.

8

The faucet will create a new address and issue account data: a passphrase, a secret key, and a public address.

9

Save the account data in a separate file acc.json in the taq-test folder.

10

Now we can add the signer module to the project. In VS Code, open the terminal, go to taq-test and execute the following:

yarn add @taquito/signer

Just like with installing Taquito, the terminal will warn you about missing licenses and display a list of installed files:

11

Create a new file tx.ts and add signer into it:

import { TezosToolkit } from '@taquito/taquito'
//import inMemorySigner. It will save the private key in the memory and use it to sign transactions
import { InMemorySigner } from '@taquito/signer'
//declare the constant acc directing the script to acc.json
const acc = require('./acc.json')
export class Tx {
  private tezos: TezosToolkit
  rpcUrl: string
  constructor(rpcUrl: string) {
    this.tezos = new TezosToolkit(rpcUrl)
    this.rpcUrl = rpcUrl

    //declare params with the method fromFundraiser: mail, password, and passphrase that allows one to get the private key
    this.tezos.setSignerProvider(InMemorySigner.fromFundraiser(acc.email, acc.password, acc.mnemonic.join(' ')))
  }
  //get the public and the private keys and activate the account
  public async activateAccount() {
    const { pkh, secret } = acc
    try {
      const operation = await this.tezos.tz.activate(pkh, secret)
      await operation.confirmation()
    } catch (e) {
      console.log(e)
    }
  }
  public async main() {}
}

In main.ts, call the method activateAccount():

import { App } from './app'
//import Tx.ts
import { Tx } from './tx'
//change the RPC link from the mainnet to testnet. Don’t you fear smartpy in the link: it’s merely the server address.
const RPC_URL = 'https://florencenet.smartpy.io/'
const ADDRESS = 'tz1aRoaRhSpRYvFdyvgWLL6TGyRoGF51wDjM'
//call the function Tx, send it the testnet link, and ask to activate the account
new Tx(RPC_URL).activateAccount()

All that’s left is to execute main.ts in the terminal:

npx ts-node main.ts

12

If the testnet has activated the account, the console will report the launch of npx without errors. Now you can confirm the activation in the testnet browser.

Open acc.json and copy the public key from “pkh.” Go to florence.tzstats and find your account using the key. The balance should have nearly a hundred test tez, and a record on activation in the history of transactions.

13

Now we have set up Taquito and activated the test account. To work in the mainnet, do the same: create a JSON file with account details and connect it using signer.

Publish the contract on the testnet

Last time, we launched a smart contract using Docker and dry-run. VM with the contract closed at once and didn’t use storage.

Actual smart contracts for tokens and DApps use storage to store user data all the time. We’ll cover that in greater detail next time. Now we should focus on publishing the contract in the testnet to see how storage saves data.

Go to VS Code and create deploy.js. Paste the following code in the file:

import { TezosToolkit } from '@taquito/taquito';
import { importKey } from '@taquito/signer';

const provider = 'https://florencenet.smartpy.io/';

async function deploy() {
 const tezos = new TezosToolkit(provider);
 await importKey(
   tezos,
   "", //mail
   "", //password
   [
     "", //passphrase
   ].join(' '),
   ""//private key
 );

deploy();

Input the account data in the empty spaces: mail, password, passphrase, and private key found in acc.json.

14

After the account details, add the contract code. We will use a modified version from the one we saw in the first lesson:

​​function main (const num : int; const store : int) is
 ((nil : list (operation)),  store + num)

This smart contract receives an int-type param num from the user and sums it up with the number kept in storage.

Compile the contract code in Michelson. To avoid launching Docker yet another time, use the online development environment.

Paste the code in the editor, select Compile Contract in the drop-down list, and click Run. The compiler will produce the contract code in Michelson.

15

Return to deploy.ts and paste the following after the account details:

try {
  const op = await tezos.contract.originate({
    //smart contract code
    code: `{ parameter int ;
      storage int ;
      code { UNPAIR ; ADD ; NIL operation ; PAIR } }
          `,
    //storage state
    init: `0`,
  });

Now describe the contract deployment process. The final code will look like this:

import { TezosToolkit } from '@taquito/taquito'
import { importKey } from '@taquito/signer'

const provider = 'https://florencenet.smartpy.io/'

async function deploy() {
  const tezos = new TezosToolkit(provider)
  await importKey(
    tezos,
    'hoqfgsoy.qyisbhtk@tezos.example.org', //mail
    'ZnnZLS0v6O', //password
    [
      'able', //passphrase
      'public',
      'usual',
      'hello',
      'october',
      'owner',
      'essence',
      'old',
      'author',
      'original',
      'various',
      'gossip',
      'core',
      'high',
      'hire',
    ].join(' '),
    '2bed8dc244ee43a1e737096c4723263c269049d8' //private key
  )

  try {
    const op = await tezos.contract.originate({
      //smart contract code
      code: `{ parameter int ;
       storage int ;
       code { UNPAIR ; ADD ; NIL operation ; PAIR } }
           `,
      //storage state
      init: `0`,
    })

    //beginning to deploy
    console.log('Awaiting confirmation...')
    const contract = await op.contract()
    //deployment report: amount of used gas, storage state
    console.log('Gas Used', op.consumedGas)
    console.log('Storage', await contract.storage())
    //operation hash one can use to find the contract in the explorer
    console.log('Operation hash:', op.hash)
  } catch (ex) {
    console.error(ex)
  }
}

deploy()

Open the console and execute npx ts-node deploy.ts. The terminal will produce a report on contract publishing.

16

Copy the hash and find the contract deployment transaction in florence.tzstats. It will specify the smart contract’s address on the testnet.

Now try to call the published contract. To do that, create a script that would call the main function and send it a number. Create a new file called call.ts and paste in it the following code:

import { TezosToolkit } from '@taquito/taquito'
import { InMemorySigner } from '@taquito/signer'
const acc = require('./acc.json')
export class Call {
  private tezos: TezosToolkit
  rpcUrl: string

  constructor(rpcUrl: string) {
    this.tezos = new TezosToolkit(rpcUrl)
    this.rpcUrl = rpcUrl

    //declaring the parameters using fromFundraiser: mail, password, and passphrase from which one can extract the private key
    this.tezos.setSignerProvider(InMemorySigner.fromFundraiser(acc.email, acc.password, acc.mnemonic.join(' ')))
  }

  public add(add: number, contract: string) {
    this.tezos.contract
      .at(contract) //call the contract to get its entry points
      .then((contract) => {
        console.log(`Adding ${add} to storage...`)
        //calling the main function. Unlike ligo syntax, the main entry point is referred to as default
        return contract.methods.default(add).send()
      })
      .then((op) => {
        console.log(`Awaiting for ${op.hash} to be confirmed...`)
        return op.confirmation(1).then(() => op.hash) //waiting for 1 confirmation to get the results faster
      })
      .then((hash) => console.log(`Call done}`)) //call is successful
      .catch((error) => console.log(`Error: ${JSON.stringify(error, null, 2)}`))
  }
}

Now make up a separate script to call call.ts, send contract address, and argument value. To that end, create a file called maincall.ts and paste the following code in it:

import { Call } from './call'

const RPC_URL = 'https://florencenet.smartpy.io/'
const CONTRACT = '' //published contract address
const ADD = 5 //number to be received by the main function. You can change it
new Call(RPC_URL).add(ADD, CONTRACT)

Assign the address of the published test contract to the constant CONTRACT. Open the console and execute the following command:

npx ts-node maincall.ts

When the terminal finishes the operation, follow the link or find your contract by the address. As you see, the storage state has changed.

17

Some conclusions

Taquito is a tool for working with the Tezos blockchain using JavaScript and TypeScript. With its help, developers can call smart contract entry points and the Tezos network similar to regular JS methods. Taquito also allows one to store data from several accounts in different fails and place frequently used code in separate modules.

The Taquito library is required for the development of DApp on Tezos. Developers will find it easier to integrate JavaScript in a web application rather than to translate user requests into console commands of the Tezos client.

We will keep using Taquito to create fungible and non-fungible tokens (NFT) on Tezos.

  • Written by Pavel Skoroplyas
  • Produced by Svetlana Koval
  • Stylistic framework by Dmitri Boyko
  • Visuals by Krzystof Szpak
  • Layouts by Zara Arakelian
  • Development by Oleksandr Pupko
  • Directed by Vlad Likhuta