
I wrote this article on the Starknet Edu blog. You can find the article here.
Note: This article was updated on Sep 20th, 2022 to use Cairo 0.10
Note: This article was updated on Sep 20th, 2022 to use Cairo 0.10
Note: This article was updated on Sep 20th, 2022 to use Cairo 0.10
Note: This article was updated on Sep 20th, 2022 to use Cairo 0.10
Note: This article was updated on Sep 20th, 2022 to use Cairo 0.10
Note: This article was updated on Sep 20th, 2022 to use Cairo 0.10
Note: This article was updated on Sep 20th, 2022 to use Cairo 0.10
$ starknet-compile contracts/ERC721/ERC721.cairo --output artifacts/ERC721.json
$ starknet deploy --contract artifacts/ERC721.json --inputs arg1 arg2 arg3 --network alpha-goerli
Note: I wrote a better guide on how to setup a local development environment here. Use that guide instead of this one as I’ve updated all the articles on this series to use it.
In this tutorial we will be completing the ERC721 workshop created by the StarkWare team so developers can get familiarized with creating smart contracts with Cairo and deploying them to StarkNet’s test network, Goerli.
I’ll be breaking down the workshop into multiple articles to keep each post to a manageable size and to make it easy to find by search engines. Make sure to follow the link at the end of each article to go to the next section.
Write a function that returns the multiplication of the first two arguments if the third argument is an even number or performs an addition if odd.
Create an array with the values 1, 2 and 3, and print the last value to the terminal.
Implement the function y = x^n.
Use the information given in the last section, in order to write a piece of code that when executed puts the current values of ap, fp and pc in memory (say, write ap into [ap], fp into [ap + 1] and pc into [ap + 2]).
Compile and run (with at least 10 steps) the following code. Use the –print_memory and –relocate_prints flags for cairo-run.
func main():
call foo
call foo
call foo
ret
end
func foo():
[ap] = 1000; ap++
ret
end
Try to think what happens when the cpu gets to the ret instruction (which of the registers ap, fp, pc should change when ret is executed and to what values?).
The example code found on this section of the Cairo docs helps us understand why references created with the let keyword are fundamentally different to values created with the tempvar and local keywords and why references are sometimes revoked when performing jumps.
func foo(x):
let y = 1
jmp x_not_zero if x != 0
x_is_zero:
[ap] = y; ap++ # y == 1.
let y = 2
[ap] = y; ap++ # y == 2.
jmp done
x_not_zero:
[ap] = y; ap++ # y == 1.
let y = 3
[ap] = y; ap++ # y == 3.
done:
# Here, y is revoked, and cannot be accessed.
ret
end
Can you spot an inefficiency in the following code? Hint: take a look here. Fix the inefficiency in two ways (implement each of the following fixes separately):
func pow4(n) -> (m : felt):
alloc_locals
local x
jmp body if n != 0
[ap] = 0; ap++
ret
body:
x = n * n
[ap] = x * x; ap++
ret
end
func main():
pow4(n=5)
ret
end
What’s wrong with the following code? (Hint: try to replace ap += SIZEOF_LOCALS with alloc_locals and see what happens) Can you fix it without changing the order of the variable definitions in the code?
func main():
tempvar x = 0
local y
ap += SIZEOF_LOCALS
y = 6
ret
end
Rewrite the solution to Exercise – A simple Cairo program using temporary variables.
func main():
[ap] = 100; ap++
[ap] = [ap - 1] * [ap - 1]; ap++ # x * x (x^2)
[ap] = [ap - 1] * [ap - 2]; ap++ # x^2 * x (x^3)
[ap] = [ap - 2] * 23; ap++ # x^2 * 23
[ap] = [ap - 4] * 45; ap++ # x * 45
[ap] = [ap - 3] + [ap - 2]; ap++ # x^3 + x^2 * 23
[ap] = [ap - 1] + [ap - 2]; ap++ # x^3 + x^2 * 23 + x * 45
[ap] = [ap - 1] + 67; ap++ # x^3 + x^2 * 23 + x * 45 + 67
ret
end
Run the following code, with –steps=32 –print_memory and explain what happens.
func main():
let x = [ap]
[ap] = 1; ap++
[ap] = 2; ap++
[ap] = x; ap++
jmp rel -1 # Jump to the previous instruction.
end
What happens in the following code? (you can start by running it and looking at the memory; note that you will need the –no_end flag)
func main():
[fp + 1] = 2; ap++
[fp] = 5201798304953761792; ap++
jmp rel -1
end