Skip to main content

Deploy a smart contract with JsLIGO

This tutorial covers writing and deploying a simple smart contract with the LIGO programming language. Specifically, this tutorial uses the JsLIGO version of LIGO, which has syntax similar to JavaScript, but you don't need any experience with JavaScript or LIGO to do this tutorial.

LIGO is a high-level programming language that you can use to write smart contracts for the Tezos blockchain. It abstracts away the complexity of using Michelson (the smart contract language directly available on-chain) to make it easier to write smart contracts on Tezos.

In this tutorial, you will learn how to:

  • Create a wallet to store cryptocurrency tokens
  • Get free tez tokens (the native cryptocurrency token on Tezos) from a faucet
  • Code a contract in LIGO, including:
    • Defining the storage for the contract
    • Defining entrypoints in the contract
    • Writing code to run when the entrypoints are called
  • Deploy (or originate) the contract to Tezos and set its starting storage value
  • Look up the current state of the contract
  • Call the contract

What is a smart contract?

A smart contract is a computer program that is stored on a blockchain and runs on a blockchain. Because the blockchain is spread across many computer nodes, you don't have to think about where to host the program or worry whether a computer will run it or not. Responsibility for running the contract is distributed across all of the nodes in the Tezos system, so when you deploy a smart contract, you can be confident that it will be available and unmodified when someone wants to run it.

A smart contract has these parts:

  • Persistent storage, data that the contract can read and write
  • One or more entrypoints, which are a kind of function that clients can call, like endpoints in an API or functions or methods in many programming languages
  • A Tezos account that can store tokens (technically, the contract is itself a type of Tezos account, but you can think of it as a program with a Tezos account)

Tutorial contract

The contract that you deploy in this tutorial stores a single integer. It provides entrypoints that clients can call to change the value of that integer:

  • The increment entrypoint accepts an integer as a parameter and adds that integer to the value in storage
  • The decrement entrypoint accepts an integer as a parameter and subtracts that integer from the value in storage
  • The reset entrypoint takes no parameters and resets the value in storage to 0

After you deploy the contract, you or any other user can call it from various sources, including web applications, other contracts, and the Octez command-line client. However, no one can prevent it from running or tamper with its code or its storage.

Creating and funding a wallet

To deploy and work with the contract, you need a wallet and some tez tokens. You can get test tokens for free on the Ghostnet test network:

  1. Install a Tezos-compatible wallet. Which wallet you install is up to you and whether you want to install a wallet on your computer, in a browser extension, or as a mobile app.

    If you don't know which one to choose, try the Temple browser extension.

    Desktop wallets for Tezos include the Temple browser extension, Kukai, and Umami.

    Mobile apps include Temple, Kukai, and Umami.

  2. Switch the wallet to use the Ghostnet testnet instead of Tezos Mainnet. Ghostnet is a network for testing Tezos applications where tokens are free so you don't have to spend real currency to work with your applications.

    For example, for the Temple browser wallet, click Tezos Mainnet at the top and then click Ghostnet Testnet, as in this picture:

    Selecting the Ghostnet testnet in the Temple wallet

  3. From your wallet, get the address of your account, which starts with tz1. This is the address that applications use to work with your wallet.

  4. Go to the Ghostnet faucet page at https://faucet.ghostnet.teztnets.com.

  5. On the faucet page, paste your wallet address into the input field labeled "Or fund any address" and click the button for the amount of tez to add to your wallet. 20 tez is enough to work with the tutorial contract, and you can return to the faucet later if you need more tez.

    It may take a few minutes for the faucet to send the tokens and for those tokens to appear in your wallet.

    You can use the faucet as much as you need to get tokens on the testnet, but those tokens are worthless and cannot be used on Mainnet.

    Fund your wallet using the Ghostnet Faucet

Now you have an account and funds that you can use to work with Tezos.

Creating the contract

The contract that you will create has these basic parts:

  • A type that describes the contract's storage, in this case an integer. The storage can be a primitive type such as an integer, string, or timestamp, or a complex data type that contains multiple values. For more information on contract data types, see Data types.

  • Functions called entrypoints that run code when clients call the contract.

  • A type that describes the return value of the entrypoints.

Follow these steps to create the code for the contract:

  1. Open the LIGO online IDE at https://ide.ligolang.org/. You can work with LIGO code in any IDE, but this online IDE keeps you from having to install software on your computer, and it also simplifies the process of deploying contracts.

  2. At the top right of the page, in the Network menu, select Ghostnet, as shown in this picture:

    Selecting Ghostnet in the list of networks

  3. Connect a wallet to the IDE:

    1. At the top right of the page, click the Keypair Manager button.

    2. In the Keypair Manager window, import the account that you created earlier or create and fund a new account to use with the IDE.

      • To import the account that you created earlier, export the private key from your wallet app, click Import in the Keypair Manager window, and paste the private key. Now you can use your account in the IDE.

      • To create an account to use with the IDE, click Create in the Keypair Manager window, give the new keypair a name, and click Create. Then, copy the address of the keypair and get tez from the faucet as you did in Creating and funding a wallet.

  4. In the IDE, create a project from the empty template and select the JsLIGO syntax, as shown in this picture:

    Creating a project

    The IDE creates a project and a contract file named Contract.jsligo.

  5. In the contract file, create a namespace named Counter to hold the code for the contract:

    namespace Counter {

    }
  6. Inside the namespace, create a TypeScript type to set the storage type to an integer:

    type storage = int;
  7. Add this code to define the return type for the entrypoints. Tezos entrypoints return two values: a list of other operations to call and the new value of the contract's storage.

    type returnValue = [list<operation>, storage];
  8. Add the code for the increment and decrement entrypoints:

    // Increment entrypoint
    @entry
    const increment = (delta : int, store : storage) : returnValue =>
    [list([]), store + delta];

    // Decrement entrypoint
    @entry
    const decrement = (delta : int, store : storage) : returnValue =>
    [list([]), store - delta];

    These functions begin with the @entry annotation to indicate that they are entrypoints. They accept two parameters: the change in the storage value (an integer) and the current value of the storage (in the storage type that you created earlier in the code). They return a value of the type returnValue that you created in the previous step.

    Each function returns an empty list of other operations to call and the new value of the storage.

  9. Add this code for the reset entrypoint:

    // Reset entrypoint
    @entry
    const reset = (_p : unit, _s : storage) : returnValue =>
    [list([]), 0];

    This function is similar to the others, but it does not take the current value of the storage into account. It always returns an empty list of operations and 0.

The complete contract code looks like this:

namespace Counter {
type storage = int;
type returnValue = [list<operation>, storage];

// Increment entrypoint
@entry
const increment = (delta : int, store : storage) : returnValue =>
[list([]), store + delta];

// Decrement entrypoint
@entry
const decrement = (delta : int, store : storage) : returnValue =>
[list([]), store - delta];

// Reset entrypoint
@entry
const reset = (_p : unit, _s : storage) : returnValue =>
[list([]), 0];
}

Testing and compiling the contract

Before you can deploy the contract to Tezos, you must compile it to Michelson, the base language of Tezos contracts.

  1. Set the compiler to target the namespace to compile in your code:

    1. On the left side of the page, under Actions, click Project Settings.
    2. On the Project Settings tab, in the Module name field, set the module name to Counter.
    3. Close the Project Settings tab.
  2. Test the contract by passing parameters and the storage value to the LIGO dry-run command:

    1. On the left side of the page, under Actions, click Dry Run.

    2. In the Dry Run window, select the Increment entrypoint, set the input parameter to 32 and the storage to 10. The Dry Run window looks like this:

      The Dry Run window, showing the entrypoint to run, the parameter to pass, and the value of the storage
    3. Click Run.

      At the bottom of the window, the Result field shows the response (LIST_EMPTY(), 42). This response means that the contract did not call any other contracts, so the list of operations is empty. Then it shows the new value of the storage. You can test the decrement function in the same way. If you see any errors, make sure that the code of your contract matches the code in the previous section.

    4. Test the Reset entrypoint in the same way, but pass unit as the input parameter and any integer in the storage field. The Reset entrypoint takes no parameters, but technically it accepts the value unit, which means no parameter.

      The Result field shows the response (LIST_EMPTY(), 0), which means that the storage value is now 0.

  3. On the left side of the page, under Actions, click Compile, and in the Compile window, click Compile again.

If the compilation succeeds, the IDE prints the compiled code to the terminal and saves it to the file build/contracts/Contract.tz. You can see the code by expanding your project on the left side of the page, under .workspaces, and double-clicking Contract.tz. If you see error messages, verify that your contract code matches the code in the previous section.

Now you can deploy the contract.

Deploying (originating) to the testnet

Deploying a contract to the network is called "originating." Originating the contract requires a small amount of Tezos tokens as a fee.

  1. On the left side of the page, under Actions, click Deploy. You may see a warning that the initial storage is not set. You can ignore this warning because you can set the initial storage now.

  2. In the Deploy contract window, in the Init storage field, set the initial value for the contract's storage to an integer.

  3. In the Signer field, make sure your account is selected.

  4. Click Estimate.

    The window shows the estimated fees to deploy the contract, as in this picture:

    The estimate of the fees to deploy the contract
  5. Click Deploy.

    The deployment process can take a few minutes. When the contract is deployed, the Deploy contract window shows the address at the bottom of the window.

  6. Copy the address of the deployed contract, which starts with KT1.

warning

Copy the contract address now, because it will not be shown again.

Now you can call the contract from any Tezos client, including web applications and command-line applications like The Octez client.

Calling the contract

These steps show you how to inspect the contract with a block explorer, which is a web application that shows information about Tezos. It also allows you to call the contract.

  1. Open the block explorer Better Call Dev at this link: https://better-call.dev/

  2. Paste the address of the contract in the search field and press Enter.

    The block explorer shows information about the contract, including recent transactions and the current state of its storage.

    The block explorer, showing information about the contract
  3. Try calling one of the entrypoints:

    1. Go to the Storage tab and check the current state of the storage, which should be the integer that you put in the Deploy window.

    2. Go to the Interact tab. This tab shows the entrypoints in the contract and lets you use them.

    3. For the increment entrypoint, in the Parameters section, put an integer in the field, as shown in this image:

      Putting in a value for an entrypoint parameter
    4. Click Execute and then click Wallet.

    5. Select your wallet and connect it to the application.

    6. Confirm the transaction in your wallet.

    7. Wait for a success message that says "The transaction has successfully been broadcasted to the network."

    8. Go back to the Storage tab and see the new value of the storage, as in this picture:

      Updated storage value

Summary

Now the contract is running on the Tezos blockchain. You or any other user can call it from any source that can send transactions to Tezos, including Octez, dApps, and other contracts.

If you want to continue working with this contract, here are some ideas:

  • Change permissions for the contract so only your account can call its entrypoints
  • Add your own entrypoints and originate a new contract; note that you cannot update the existing contract after it is deployed
  • Create a dApp to call the contract from a web application, similar to the dApp that you create in the tutorial Build a simple web application