Deploy a smart contract with SmartPy
This tutorial covers writing and deploying a simple smart contract with the SmartPy programming language. SmartPy has syntax similar to Python, but you don't need any experience with Python or SmartPy to do this tutorial.
- If you are more familiar with OCaml, try Deploy a smart contract with CameLIGO.
- If you are more familiar with JavaScript, try Deploy a smart contract with JsLIGO.
- To learn the Archetype language, try Deploy a smart contract with Archetype.
SmartPy 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 SmartPy, including:
- Creating a contract in the online IDE
- 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 string value. It provides entrypoints that clients can call to change the value of that string:
- The
replace
entrypoint accepts a new string as a parameter and stores that string, replacing the existing string. - The
append
entrypoint accepts a new string as a parameter and appends it to the existing string.
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.
-
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.
-
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:
-
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. -
Go to the Ghostnet faucet page at https://faucet.ghostnet.teztnets.com.
-
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.
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 function that initializes the contract and sets the starting value for its storage.
-
Internal functions called entrypoints that run code when clients call the contract.
-
Automated tests that verify that the contract works as expected.
Follow these steps to create the code for the contract:
-
Open the SmartPy online IDE at https://smartpy.io/ide. You can work with SmartPy 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.
-
In the code editor, add this line of code to import SmartPy:
import smartpy as sp
-
Add this code that creates the entrypoints:
@sp.module
def main():
class StoreGreeting(sp.Contract):
def __init__(self, greeting): # Note the indentation
# Initialize the storage with a string passed at deployment time
# Cast the greeting parameter to a string
sp.cast(greeting, sp.string)
self.data.greeting = greeting
@sp.entrypoint # Note the indentation
def replace(self, params):
self.data.greeting = params.text
@sp.entrypoint # Note the indentation
def append(self, params):
self.data.greeting += params.textIndentation is significant in Python, so make sure that your indentation matches this code.
The first two lines create a SmartPy module, which indicates that the code is SmartPy instead of ordinary Python.
Then the code creates a class named StoreGreeting, which represents the smart contract. The contract has an
__init__
function, which runs when the contract is deployed. In this case, the function sets the initial value of the storage to a parameter that you pass when you deploy the contract. This storage value is a string, but the storage can be another primitive type such as an integer or timestamp, or a complex data type that contains multiple values. For more information on contract data types, see Data types. -
Add this code, which creates automated tests:
# Automated tests that run on simulation
@sp.add_test()
def test():
# Initialize the test scenario
scenario = sp.test_scenario("StoreGreeting", main)
scenario.h1("StoreGreeting")
# Initialize the contract and pass the starting value
contract = main.StoreGreeting("Hello")
scenario += contract
# Verify that the value in storage was set correctly
scenario.verify(contract.data.greeting == "Hello")
# Test the entrypoints and check the new storage value
contract.replace(text = "Hi")
contract.append(text = ", there!")
scenario.verify(contract.data.greeting == "Hi, there!")When you run the SmartPy file, SmartPy runs a simulation in which it tests and compiles the contract. In this case, the tests verify that the replace and append endpoints work. For more information about SmartPy and tests, see the SmartPy documentation.
The SmartPy online IDE looks like this:
The complete contract looks like this:
import smartpy as sp
@sp.module
def main():
class StoreGreeting(sp.Contract):
def __init__(self, greeting): # Note the indentation
# Initialize the storage with a string passed at deployment time
# Cast the greeting parameter to a string
sp.cast(greeting, sp.string)
self.data.greeting = greeting
@sp.entrypoint # Note the indentation
def replace(self, params):
self.data.greeting = params.text
@sp.entrypoint # Note the indentation
def append(self, params):
self.data.greeting += params.text
# Automated tests that run on simulation
@sp.add_test()
def test():
# Initialize the test scenario
scenario = sp.test_scenario("Test scenario", main)
scenario.h1("StoreGreeting")
# Initialize the contract and pass the starting value
contract = main.StoreGreeting("Hello")
scenario += contract
# Verify that the value in storage was set correctly
scenario.verify(contract.data.greeting == "Hello")
# Test the entrypoints and check the new storage value
contract.replace(text = "Hi")
contract.append(text = ", there!")
scenario.verify(contract.data.greeting == "Hi, there!")
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. The compilation process automatically runs the tests.
-
Compile the contract and run the tests by clicking the Run Code button:
The right-hand pane of the online IDE shows the results of the simulation, compilation, and testing process. The first step is simulating the deployment (origination) of the contract. The simulation assigns the contract a temporary address and shows the initial state of its storage:
Then, the simulation runs the test cases and shows the results of each call to an entrypoint:
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.
-
Under the origination step, click Show Michelson.
The IDE shows the compiled Michelson code of the contract, which is the language that smart contracts use on Tezos.
-
Below the Michelson code, click Deploy Contract.
-
In the new window, under "Node and Network," select the Ghostnet testnet and accept the default RPC node, as in this picture:
-
Under "Wallet," click Select Account.
-
In the pop-up window, connect your wallet. For Temple wallets, use the Temple tab, and for most other wallets, use the Beacon tab.
-
When your wallet is connected, click Validate.
The Origination page shows your wallet information:
-
At the bottom of the page, click Deploy Contract.
-
In the pop-up window, click Accept.
-
Approve the transaction in your wallet app.
The "Origination Result" section shows information about the deployed contract, including its address:
-
Under the contract address, click Save Contract.
-
In the popup window, give the contract a name and click Add Contract. Saving the contract address like this is important because the address is not shown again.
-
Open the contract in the block explorer Better Call Dev:
-
In a new browser tab, go to https://better-call.dev/.
-
Paste the contract address in the search box and press Enter.
The block explorer shows information about the contract, including recent transactions and the current state of its storage.
-
-
Try calling one of the entrypoints:
-
Go to the Storage tab and check the current state of the storage. If you just originated the contract, the storage is "Hello" because that's the value set in the smart contract code.
-
Go to the Interact tab. This tab shows the entrypoints in the contract and lets you use them.
-
For the
append
entrypoint, in the Parameters section, put some text in the field, as shown in this image: -
Click Execute and then click Wallet.
-
Select your wallet and connect it to the application.
-
Confirm the transaction in your wallet.
-
Wait for a success message that says "The transaction has successfully been broadcasted to the network."
-
Go back to the Storage tab and see that the text that you put in the parameter has been added to the contract storage, as in this picture:
-
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