Starting with SmartPy Part 1: Smart Contract Crash Course

Starting Your First Smart Contract with SmartPy

Teckhua Chiang
The Cryptonomic Aperiodical
5 min readAug 16, 2019

--

SmartPy is a high-level smart contract library in Python that offers a simple, intuitive and powerful syntax, enabling developers to easily define Michelson smart contracts for the Tezos blockchain. There is an online editor to quickly begin exploring SmartPy. The following is a brief, hands-on tutorial to help you get started developing Tezos smart contracts with SmartPy.

Fundamental Components

Let’s begin by creating a simple smart contract that allows users to store a single phrase string on the blockchain.

First, we must import the SmartPy library in order to use its functions.

import smartpy as sp

We define a Python class PhraseKeeper that inherits from the Contract class of SmartPy. This class will represent our smart contract and enclose all of the storage initialization, entry points, and internal functions.

class PhraseKeeper(sp.Contract):

Next, we define an initialization method for PhraseKeeper that determines the initial storage during contract origination. __init__() accepts one argument, initialPhrase, and calls self.init() to assign its value to the newly-created phrase field of type string in the contract’s storage.

    def __init__(self, initialPhrase):
self.init(phrase = sp.string(initialPhrase))

Then, we can start defining the contract’s behavior through the use of entry points, which serve a similar role to public functions for smart contracts. Our first entry point, setPhrase(), accepts two arguments, self and params. All SmartPy entry points require this exact parameter signature and a @sp.entryPoint decorator to denote it during compilation.

self is a reference to the current instance of the smart contract PhraseKeeper that is always the first argument of every entry point. params can contain multiple fields representing the actual arguments, but in this contract there is only one. setPhrase() takes the value of params and assigns it to the phrase field in self.data, which points to PhraseKeeper’s storage.

    @sp.entryPoint
def setPhrase(self, params):
self.data.phrase = params

Congratulations! We’ve now successfully created a simple SmartPy contract that initializes its storage, consisting of one string, with the value passed during contract deployment. It also provides users with an entry point to update the stored string with another string.

import smartpy as spclass PhraseKeeper(sp.Contract):
def __init__(self, initialPhrase):
self.init(phrase = initialPhrase)
@sp.entryPoint
def setPhrase(self, params):
self.data.phrase = params

Basic Tests

The SmartPy online editor isn’t just a simple text editor for smart contracts — it comes with a built-in simulation suite that provides powerful testing tools for developers. To access detailed information and analytics about our new PhraseKeeper contract, we can quickly define a basic test.

First, we define a SmartPy test with the annotation @addTest(name = "PhraseSetTest") and the method header def test(). Then, PhraseKeeper("Hello World") creates an instance of the PhraseKeeper contract with "Hello World" as the initial phrase in storage, as per our __init__() method. We transform the contract into a viewable format with c1.fullHtml(), and then send the HTML results to the SmartPy output panel with setOutput(html).

@addTest(name = "PhraseSetTest")
def test():
scenario = sp.testScenario()
scenario.h1("String Test")

c1 = PhraseKeeper("Tezos Tacos Nachos")
scenario += c1
scenario.h2("Update text")
scenario += c1.setPhrase("Yum Yum Yum")

After pressing the Run button on the command bar at the top of the editor interface, information about the PhraseKeeper contract should appear on the right panel as pictured below.

While this is a rudimentary test that shows general information about the contract, it is also possible to define more advanced tests that can invoke the smart contract in a local simulator and verify its expected behavior. Please refer to Part 3 for a more in-depth dive into SmartPy’s testing suite.

Multiple Parameters

We can quickly revise our original smart contract and create a SimpleMath contract that is capable of performing on-chain computations. To begin, we change __init__() to create a sum field of type int in storage and set its value to 0. For this contract, hard-coding the starting value makes sense rather than allowing user initialization like in the first example.

import smartpy as sp

class SimpleMath(sp.Contract):
def __init__(self):
self.init(sum = sp.int(0))

SmartPy can infer some datatypes, so the explicit definition of sum can be shortened to sum = 0. Then, we define a computeSum() as an entry point that adds the values of params.augend and params.addend, before assigning it to self.data.sum. Entry points are functions that are callable via contract invocation.

Note that even though computeSum() requires multiple arguments, the entry point header only lists self and params as parameters, without explicitly declaring augend and addend as int fields within params. This unusual approach conforms to Michelson’s single parameter restriction.

@sp.entryPoint
def computeSum(self, params):
self.data.sum = params.augend + params.addend

Luckily, SmartPy will do most of the heavy lifting in the background for us. It will automatically recognize that params is required to contain two int values, which it will wrap in a pair structure when compiling into Michelson, like so: (pair (int %addend) (int %augend)).

import smartpy as spclass SimpleMath(sp.Contract):
def __init__(self):
self.init(sum = 0)
@sp.entryPoint
def computeSum(self, params):
self.data.sum = params.augend + params.addend
@addTest(name = "MathTest")
def test():
scenario = sp.testScenario()
scenario.h1("Simple Math Tests")
contract = SimpleMath() scenario += contract
scenario.h2("Test Addition")
scenario += contract.computeSum(augend = 1, addend = 2).run(sender = sp.address("tz1234"))

Here’s the contract in the SmartPy online editor.

It’s worth noting that Python is perhaps an odd choice as a smart contract interface for Tezos since one of the core premises of the platform is formal verification which depends on explicit type definitions — a feature Python explicitly avoids. Python however does have easy to understand syntax and is a well-known language. We’re excited for this reason to be working with such user-friendly tools.

With these minor modifications, we now have the knowledge to define complex entry points with multiple parameters. Read Part 2 to learn how to enhance your skills and write more advanced smart contracts.

--

--