We’re going to write a new smart contract in Michelson using a string passed in the parameter by the user that we'll concatenate to the string already present in the storage before saving the new string into the storage.
(Part 1 is available here.)
After introducing the basics of Michelson in the previous article, we’re going to continue our exploration of this programming language.
In this new installment, we’re introducing an amazing tool that’ll help us write, debug, and examine our Michelson code: the Jupyter notebook with the Michelson kernel developed by the Baking Bad team.
We’re going to write a new smart contract in Michelson using a string passed in the parameter by the user that we'll concatenate to the string already present in the storage before saving the new string into the storage.
It’s highly recommended to read Part 1 first, as it introduces concepts about smart contracts in Michelson we’re going to use here.
But first, let’s have a look at what’s probably the best tool around to code: Michelson!
Baking Bad developed an online Michelson compiler that goes beyond compiling your Michelson code.
It offers syntax highlighting, debugging, and a step-by-step visualization of the stack. You can open the notebook we’re going to use for this lesson using this link (bear in mind the kernel needs a minute or two to load) before selecting the
MichelsonTutorial-Demo3.ipynb
file.The file is divided into two parts:
In the first part, the whole smart contract is dropped into a single cell. You can compile and run it by writing
RUN
%default
parameter storage
in the following cell.After running the smart contract, there’s a detailed description of each step and what each instruction did to modify the stack (in
In [10]
on the picture). At the end of the runtime (in Out [10]
on the picture), you’re left with your new storage.Where this compiler shines is you can enter the instructions to modify the stack one by one and examine their effect after each step.
As in every Michelson smart contract, you start by specifying the parameter and the storage. Then, you type
BEGIN
parameter storage
to start the execution.After this configuration step, you can enter the instructions one by one and run them by hitting
CMD/CTRL + SHIFT
to see how they modify the stack. In the Out [...]
cell, you’re presented with the current value at the top of the stack.Note: you can see a
DUMP
instruction in the step-by-step code. This is not Michelson — this is just an instruction used in the Jupyter notebooks to print the current state of the stack.When you want to end the execution of the smart contract, you enter
COMMIT
, and it’ll return the new storage, provided there’s no error in your code. If there’s one at any step of the execution, you’ll see a message and be able to fix it right away without having to review your code line by line.In the last lesson, we introduced a few instructions that manipulated data either already in the stack or that we pushed ourselves. But what about handling users’ input? This is actually pretty easy!
We’re going to work with the contract present in the Jupyter notebook introduced above. You’re welcome to follow along in the notebook and run the instructions one by one to get a better understanding of how the stack looks like after each instruction. Here’s the full smart contract:
If you remember, a pair containing the parameter and the storage is automatically pushed at the top of the stack when the contract is called. We can then get the left part of the pair (the parameter) and use it. Here’s how it works.
First, let’s initialize our stack:
In this step, we get a fresh stack with a pair containing a parameter of type
string
(world
) and the storage of type string
, too (Hello
). Our final goal is to concatenate these two strings and return them.In the next step, we duplicate the top element of the stack because we need the parameter and the storage in two separate elements of the stack to be able to put them together in one single string.
Michelson doesn’t have variables and is immutable by nature. New elements of the stack can be created with different methods — for example, by pushing them (with the
PUSH
instruction) or by duplicating them (with the DUP
instruction). Remember at every step of the execution, you’re dealing with the top element of the stack. It’s the only one you can work with.Let’s start with the first element of the stack, and let’s get the parameter out of the pair. We use the
CAR
instruction, whose purpose is to break an element of type pair
and to return the left side of the pair (in this case, the parameter passed to the smart contract). After running CAR
, we’re left with the string world
on top of the stack.Now you may be wondering: How can I work with the second element of the stack if Michelson only deals with the first one? It’s very easy! Bring the second element to the top with the
SWAP
instruction, and keep the other one for later.When using the
SWAP
instruction, you tell Michelson: “I don’t need the first element for now, but I’d like to work on the second one.” Michelson will bring down the first element to the second position and the second element up to the first position.Now that the second pair we duplicated at the beginning is at the top, we can use a reverse
CAR
to get the right part of the pair with the CDR
instruction.The
CDR
instruction works like the CAR
instruction, but you’ll keep the right side of the pair you’re manipulating (a pair always contains only two elements, so CDR
and CAR
are the only possible operations). After that, you can see our stack is made of two elements: in the first position, the string Hello
and in the second position, the string world
.Now let’s put them together!
In computer programming, the operation of putting two strings together is called concatenation. It’s only logical that the instruction to put two strings together in Michelson is called
CONCAT
. The operation takes the two strings currently at the top of the stack and returns a single string. For the operation to be successful, two conditions must be true:Now if you remember what we talked about in Part 1, you know what’s going to happen. We must create a pair with a list and the new storage to end the execution of the smart contract (it’s like saying goodbye in Michelson).
First, let’s push an empty list on the top of the stack:
Once the empty list is there, we can create a pair with the empty list and the string:
Once again, be very wary of the order of your elements and their type: Michelson will take the first element to put it on the left side of the pair and the second element to put it on the right side of the pair. Returning a pair of type (Pair string list (operation)) will generate an error.
Now our stack is clean and contains a pair with a list of operations and a string, the execution of the smart contract comes to an end.
You can see the full execution and the transformations of the stack in the video below:
In this new part of the Michelson tutorial for beginners, we had a look at a Jupyter notebook with a Michelson kernel that we’ll use heavily in the following parts of this tutorial to write, debug, and execute code.
New operation codes in Michelson were introduced:
CAR
, which extracts the left part of a pair; DUP
, which duplicates the top element of the stack; CDR
, which extracts the right part of a pair; SWAP
, which swaps the positions of the two elements on the top of the stack; and CONCAT
, which takes two strings and returns a single string made of the two previous strings put together.Animations that represent the operations in the stack were also added to help you better visualize and follow what happens at every step. This will become even more useful when the operations in the stack become more complicated and intricate.
Stay tuned!
(Previously published behind a paywall at https://medium.com/better-programming/an-introduction-to-michelson-the-scripting-language-of-tezos-part-2-4cc972c8237c)