diff --git a/lessons/inter-contract-calling/01/01.mdx b/lessons/inter-contract-calling/01/01.mdx index 596cbd85..8909019c 100644 --- a/lessons/inter-contract-calling/01/01.mdx +++ b/lessons/inter-contract-calling/01/01.mdx @@ -112,8 +112,9 @@ editor: scenario.verify(test_bot.data.mutez_points == sp.mutez(5000)) --- -### Intro -Awesome work defeating those nasty aliens :rocket: +## Intro +Awesome work defeating those nasty aliens 🚀 + But, beware that was only the **first wave**, there's a greater challenge that lies ahead of you. At least one good thing came out of the first battle, you managed to collect some **mutez** 💵 when you defeated the first wave. @@ -122,20 +123,20 @@ It's a **smaller unit of XTZ**. Simply a way to represent smaller amounts of Tezos. This will come in handy to defeat the new challenge coming your way. -You'll can use these `mutez_points` to buy power-ups from the `Market`(we'll implement the market in the coming chapters). +You'll use these `mutez_points` to buy power-ups from the `Market`(we'll implement the market in the coming chapters). -### Study time +## Study time Mutez is to XTZ(Currency of Tezos) what a cent is to dollar or what gram is to kg. To be more accurate - -`1,000,000 mutez = 1 XTZ`(1 million Mutez = 1 Tez(or XTZ)) +`1,000,000 mutez = 1 XTZ`(1 million Mutez = 1 Tez(or XTZ)) Similar to all other data types in SmartPy(sp.TNat, sp.TMap, etc) there are Tezos specific data types as well and one of them is [`sp.TMutez`](https://smartpy.io/dev/reference.html#_mutez). > #### Note - > In SmartPy, when a type is being specified - it's referened with `sp.T`. But when it's being called with a value - it's called with `sp.`. > Example - `sp.TNat` and `sp.nat(5)`, `sp.TMutez` and `sp.mutez(500)` -> If you're not familiar with data types, go through this [chapter](https://cryptocodeschool.in/lesson/chapter-08) +> If you're not familiar with data types, go through this [chapter](/tezos/academy/module-01/chapter-08) #### Difference between sp.mutez and sp.tez - When you write `sp.mutez(100000)` it's equated to `0.1 Tez(XTZ)`. @@ -143,7 +144,7 @@ Hence, when you're specifying a large number of tokens, it's better to use `sp.t Whereas, `sp.mutez` helps you express smaller quantities with much better accuracy. ### Show me an example -```python= +```python class Wallet(sp.Contract): def __init__(self, initial_amount): self.init( diff --git a/lessons/inter-contract-calling/02/02.mdx b/lessons/inter-contract-calling/02/02.mdx index dfc63f57..ea6b2be2 100644 --- a/lessons/inter-contract-calling/02/02.mdx +++ b/lessons/inter-contract-calling/02/02.mdx @@ -107,13 +107,13 @@ editor: scenario += test_bot --- -### Intro +## Intro Calibrating our plasma cannons for the next wave of aliens - what better way than to make your script a teeny bit better? Right now, we're using `sp.address` to give a `bot_manager` address to our `Cryptobot`. But, SmartPy has a special function called `sp.test_account(seed)` which we'll use to improve upon this. -### Study time +## Study time `sp.test_account(seed)` takes a random string as an argument and generates several properties based on this `seed` value. A test accounts has the following fields - - `address` @@ -121,10 +121,12 @@ A test accounts has the following fields - - `public_key` - `secret_key` +
+ Don't worry about what all the fields mean. We only need the `address` for our purpose :D ### Show me an example -```python= +```python class Wallet(sp.Contract): def __init__(self, initial_amount, owner_address): self.init( @@ -142,11 +144,11 @@ def test(): Building on our example from the previous chapter, here a new field has been added in contract storage, `owner`. Inside the test, we generated a test account using `sp.test_account("Wallet Example Account")` and passed in the address to wallet using `account_owner.address`. -### #buidl-ing time +## #buidl-ing time -#### Let's refactor! +### Let's refactor! Now you know about `sp.test_account`, use it instead of `sp.address` in our `Cryptobot`. -#### Step by step walkthrough +### Step by step walkthrough 1. Replace `my_address` variable with `my_account` and assign and invoke it with `sp.test_account` with the `seed` of `"Cryptobot Owner"`. 2. Replace `my_address` in the Contract initialization with `my_account.address`. \ No newline at end of file diff --git a/lessons/inter-contract-calling/03/03.mdx b/lessons/inter-contract-calling/03/03.mdx index ca60e612..9bab6ed1 100644 --- a/lessons/inter-contract-calling/03/03.mdx +++ b/lessons/inter-contract-calling/03/03.mdx @@ -113,7 +113,7 @@ editor: scenario += market --- -### Intro +## Intro In battle, lists are important! How else would you keep track of all the powerups you can buy!? @@ -122,11 +122,11 @@ In this one, let's learn how to use the **list** data type in SmartPy. Later in this chapter you'll also start working on a new smart contract, `Market`, which will allow you to get powerups in your final battle 🚀 Let's go! -### Study time +## Study time List type in SmartPy is represented by `sp.TList`. It can be initialized by using either `[]` or `sp.list()`. -```python= +```python self.init( history = sp.list() # or [] ) @@ -140,12 +140,12 @@ Unlike lists in Python, a list in SmartPy can't hold data of differ data types. > #### Note > Not all python lists functions are available for lists in SmartPy. -> Check the reference [here:scroll:](https://smartpy.io/dev/reference.html#_lists) to see a detailed list of functions available. +> Check the reference [here 📜](https://smartpy.io/dev/reference.html#_lists) to see a detailed list of functions available. ### Show me an example We're going to build on top of the `Wallet` example from the previous chapter. -```python= +```python class Wallet(sp.Contract): def __init__(self, initial_amount, owner_address): self.init( @@ -163,9 +163,10 @@ def test(): scenario.verify(w.data.amount == sp.mutez(1000)) ``` + Notice a new `transaction` state variable? It's a list. Now, we're going to add a new `entry_point` to this smart contract. -```python= +```python @sp.entry_point def add_transaction(self, amount): self.data.amount += amount @@ -174,20 +175,20 @@ def add_transaction(self, amount): Take a look at the `entry_point` right above, it uses `.push` which is a method you can use to add items to the top of the list. **Now to test this code(coz you know, testing is a thing) -** -```python= +```python scenario += w.add_transaction(sp.mutez(500)) scenario += w.add_transaction(sp.mutez(300)) scenario.verify(w.data.amount == sp.mutez(1800)) ``` -### #buidl-ing time +## #buidl-ing time -#### New feature request! +### New feature request! You're the smart contract expert in town. The Cryptoverse `Market` has tasked you with writing the smart contract, `Market`, for it to interact with your `Cryptobot`. -#### Step by step walkthrough +### Step by step walkthrough 1. Create a new smart contract, `Market`. 2. Market will have a contract storage variable - `powerups` which will be equal to `["time_freeze", "one_shot_kill"]`. 3. Inside test function, initialize an instance of the `Market` contract and store it inside `market`. diff --git a/lessons/inter-contract-calling/04/04.mdx b/lessons/inter-contract-calling/04/04.mdx index e4d1d7ed..645e315d 100644 --- a/lessons/inter-contract-calling/04/04.mdx +++ b/lessons/inter-contract-calling/04/04.mdx @@ -122,27 +122,27 @@ editor: scenario += market --- -### Intro +## Intro Right now, the system is broken. You can't afford broken systems, you've got the threat of aliens looming over your head in case you forgot! You've stored `powerups` in the `Market`, but we've no idea how long a `powerup` lasts. Let's fix this with data type provided by SmartPy - [record](https://smartpy.io/dev/reference.html#_records) -### Study time +## Study time Records are the kind of structures that seem not of much use at first but turn out to be extremely crucial on taking a closer look, it's the underdog of types 🐶 A record can hold multiple variales of different(or same) types under one namespace and it's represented by the type `sp.TRecord` in SmartPy. Confused? Take a look at the snippet below ⬇️ -```python= +```python money = sp.record(amount = 1000, currency = "$") ``` As I told you before, a record is just multiple variables gathered under one. You can access `amount` and `currency` through the following - -```python= +```python money.amount money.currency ``` @@ -165,7 +165,7 @@ This won't be a problem with records because they're designed to hold multiples ### Show me an example Following the lead from previous chapters, this example is also building on top of our `Wallet` smart contract. -```python= +```python class Wallet(sp.Contract): def __init__(self, initial_amount, owner_address): self.init( @@ -194,7 +194,7 @@ def test(): ``` Using records we've revamped the `add_transaction` entry point. Let's take a closer look. -```python= +```python @sp.entry_point def add_transaction(self, transaction): sp.if transaction.action == "sent": @@ -209,19 +209,19 @@ If the `action` is `sent` we deduct the `amount`. But, how do we call this entry point? Look at the snippet below. -```python= +```python scenario += w.add_transaction(sp.record(amount = sp.mutez(500), action = "sent")) ``` Passing `sp.record` with the fields inside it to `add_transaction`. Records seem simple now, don't they!? -### #buidl-ing time +## #buidl-ing time -#### New feature request! +### New feature request! In the last chapter, we successfuly defined the smart contract for `Market` but we forgot that powerups don't last forever! We listed out the `powerups` in the list but didn't mention the `duration` for them. It's time to fix it 🔧 -#### Step by step walkthrough +### Step by step walkthrough 1. Edit the `powerups` list inside the `Market` contract to hold two records, both of them will have a `power` field and a `duration` field - diff --git a/lessons/inter-contract-calling/05/05.mdx b/lessons/inter-contract-calling/05/05.mdx index d38f8fdb..9abc1fb6 100644 --- a/lessons/inter-contract-calling/05/05.mdx +++ b/lessons/inter-contract-calling/05/05.mdx @@ -183,13 +183,13 @@ editor: scenario.verify(test_bot.data.mutez_points == sp.mutez(2000)) --- -### Intro +## Intro How do you plan on winning the war if you can't order `powerups` from the Market? **Inter-contract calling** is here to save us. It can make your smart contracts go *super saiyan* 🔥. -### Study time +## Study time Inter-contract calling is simply the method of invoking the entry point of a contract, from another smart contract. This means, your `Cryptobot` will be able to call an entry point that exists in `Market`. @@ -198,12 +198,12 @@ Inter-contract calling not only **helps two contracts talk to each other** but a > Note - You can learn about oracles through this [article](https://academy.binance.com/en/articles/blockchain-oracles-explained). To implement inter-contract calling, you need to understand `sp.transfer` first. As the name suggests it transfers some data and amount to a destination contract(this is what calls the desired entry point). -```python= +```python sp.transfer(data_to_be_sent, amount_of_tezos, destination_contract) ``` It calls the destination contract with `data_to_be_sent` as a parameter while sending the specified `amount_of_tezos` to it. `destination_contract` needs to be of type, `sp.TContract` created with `sp.contract`. -```python= +```python sp.contract(t, address, entry_point = "") ``` Don't worry if it looks overwhelming at first glance, we're going to break it down :) @@ -215,7 +215,7 @@ Don't worry if it looks overwhelming at first glance, we're going to break it do The result of `sp.contract` is passed to `destination_contract` in `sp.transfer`. -```python= +```python @sp.entry_point def send(self): @@ -277,30 +277,29 @@ This is a bare-bones example, we covered the `send` function in the section abov 3. `recieve` entry point simply assigns `msg` the value it's being sent as the `payload`. -### #buidl-ing time +## #buidl-ing time -#### New feature request! +### New feature request! It's time to build the functionality of buying a powerup from the `Market` finally 🚀 Let's give our `Cryptobot` the ability to buy a `powerup`. -#### Step by step walkthrough +### Step by step walkthrough 1. Accept `market_address` as an arugment for `Cryptobot` and initialize the `Cryptobot` with `market_address` equal to `market.address`.(Look at the example above to see how we store `target_address` inside the `Sender` contract.) 2. Add `active_powerup` to `Cryptobot`'s contract storage and initialize it to be a record which holds - - 1. power which is an empty string - 2. duration which is equal to 0 - - -5. Implement `buy_powerup` inside `Cryptobot` + * power which is an empty string + * duration which is equal to 0 +3. Implement `buy_powerup` inside `Cryptobot` - Define `data_type` as a record which holds a variable called `powerup` of type string. - Define the `market_contract` using `Market's` address that is pointed at the entry point `send_powerup` and accepts a data type of string. Don't forget about `.open_some()` - Reduce 3000 mutez from `mutez_points` in `Cryptobot` as each `powerup` costs 3000 mutez. - Define `data_to_be_sent` which is a record inside which a variable `powerup` is to be set equal to the parameter accepted through the function. - Finally, send the `data_to_be_sent` to the Market(`market_contract`) using `sp.transfer` along with 0 Mutez. +
> In the coming chapters we'll implement `send_powerup` in `Market` and `recieve_powerup` in `Cryptobot`. -#### Testing our code +### Testing our code - Invoke `buy_powerup` with `"time_freeze"` as the argument and add it to the scenario. - Use `scenario.verify` to confirm whether `mutez_points` in `Cryptobot` are equal to 2000 mutez. \ No newline at end of file diff --git a/lessons/inter-contract-calling/06/06.mdx b/lessons/inter-contract-calling/06/06.mdx index b519d52d..21a8f164 100644 --- a/lessons/inter-contract-calling/06/06.mdx +++ b/lessons/inter-contract-calling/06/06.mdx @@ -210,20 +210,22 @@ editor: scenario += test_bot --- -### Intro +## Intro We'll take a short detour from inter-contract calling to learn and explore a few other topics that will help you build the `Cryptobot` of your dream to absolutely dominate the war against the aliens 🤩 In this one we'll cover a slew of different topics including `sub_entry_point` and `sp.for`. -### Study time -#### 1. Sub entry point -Sub entry points allow you to define functions in a smart contract that can **ONLY** be called from other entry points of the same contract. +## Study time +### 1. Sub entry point +Sub entry points allow you to define functions in a smart contract that can **ONLY** be called from other entry points of the same contract. But why would you even need something like this? 1. **Modularization** - Break down your code into different pieces to keep the code in your entry points clean and to the point. Makes the code easier to maintain and more readable. 2. **Re-usability** - Once implemented, you can use them where ever needed. I think of them as **utility functions** that play a role in the success of other functions but aren't of much use indepedently. +
+ Here's how you define a sub entry point - -```python= +```python @sp.sub_entry_point def double(self, x): sp.result(x * 2) @@ -231,7 +233,7 @@ def double(self, x): Notice, **`sp.result`** is used to return from a sub entry point instead of `return`. And it can be invoked like this - -```python= +```python @sp.entry_point def update_result(self, num): # Assume double is a sub entry point already implemented in the smart contract. @@ -239,19 +241,25 @@ def update_result(self, num): ``` Sub entry points can access the contract storage - if your function doesn't need to access the contract storage, you should use [`sp.global_lamba` ](https://smartpy.io/dev/reference.html#_lambdas). -**2. Looping with `sp.for`** +### 2. Looping with `sp.for` + +
+ Remember how we needed to use `sp.if` instead of `if` in SmartPy? Similarly, `for` and `while` have their SmartPy counter-parts as `sp.for` and `sp.while`. -```python= +```python transfers = [-12, 15, -10, 20, 30] sp.for transfer in transfers: self.data.total += transfer ``` You need to use `sp.range` instead of `range`. -**3. Local variables using `sp.local`** +### 3. Local variables using `sp.local` + +
+ You can define local variables in SmartPy using `sp.local` - -```python= +```python total = sp.local("total", 0) ``` But why not just define a normal python variable like - `total = 0`? @@ -259,8 +267,10 @@ Because normal python variables can't be updated during execution of a smart con - First argument to `sp.local` is the name which will be used to refer to the variable in error message. - Second argument is the initial value. +
+ **Value of a local variable is accessed through `.value`** - -```python= +```python x = sp.local("x", 0) # now to access or modify the value of x, you need to use `x.value` x.value = 2 @@ -272,7 +282,7 @@ This is mostly helpful with loops wherever you need to keep track of something. Don't worry, we'll use this in our `Market` smart contract. That'll bring more clarity. ### Show me an example -```python= +```python @sp.sub_entry_point def add_to_total_received(self, amount): self.data.total_received += amount @@ -287,14 +297,14 @@ def calculate_received(self): Imagine this as a part of a `Ledger` smart contract. We've got an entry point `calculate_received` that loops over the transactions, if the transaction was received - it adds the amount to the total through the sub entry point `add_to_total_received`. -### #buidl-ing time +## #buidl-ing time -#### New feature request! +### New feature request! We'll have to help the `Market` peeps find which `powerup` we want before they can send it over to your `Cryptobot`. Let's put our knowledge of sub entry point and loops to use 🚀 -#### Step by step walkthrough +### Step by step walkthrough - Implement the sub entry point `find_powerup` in the `Market` contract. 1. Define a local variable called `powerup_to_send` which should be a record which holds a variable called power(equal to an empty string) and another variable called duration(equal to 0). 2. Loop through the `powerups` in the contract storage. diff --git a/lessons/inter-contract-calling/07/07.mdx b/lessons/inter-contract-calling/07/07.mdx index 5c954187..3e86d76f 100644 --- a/lessons/inter-contract-calling/07/07.mdx +++ b/lessons/inter-contract-calling/07/07.mdx @@ -117,9 +117,7 @@ editor: # test our code over here. - - - answer: | + answer: | import smartpy as sp class Cryptobot(sp.Contract): @@ -235,31 +233,35 @@ editor: scenario += test_bot.buy_powerup('time_freeze') scenario.verify(test_bot.data.mutez_points == sp.mutez(2000)) scenario.verify(test_bot.data.active_powerup.power == 'time_freeze') - --- -### Intro +## Intro + You've told `Market` which `powerup` you want, but don't you want to get the `powerup` back!? After all, `powerups` will help you destroy the aliens. -### Study time +## Study time + So far, we've implemented only one inter-contract call. But to complete the whole process of buying a powerup, we're going to need one more from `Market` to `Cryptobot` to send the real `powerup`. ![inter-contract call](https://i.imgur.com/JjgArPu.png) This in loose terms is called **cyclic inter-contract calls**. -- First contract calls the Second contract and then the Second contract calls the First contract. +- First contract calls the Second contract and then the Second contract calls the First contract. +
There's a last piece in the puzzle that you need to understand to implement the full functionality - `sp.to_address`. `sp.to_address` accepts a contract(`sp.TContract`) and returns the address(`sp.TAddress`) of that contract. It can be used in combination with `sp.self` to generate the address of the currenty smart contract inside an entry point. + > Note - `sp.self` refers to the contract it's being used inside. -```python= + +```python sp.to_address(sp.self) ``` @@ -267,29 +269,30 @@ Super useful for our case because the `Cryptobot` needs to send its own address Puzzle clicking together now? 🔥 -### #buidl-ing time - -#### New feature request! +## #buidl-ing time + +### New feature request! + We're going to have to **buidl** a lot of stuff in this one. Let's go and complete our whole system so that you can finally use the powerups to blow the nasty alien to pieces +### Step by step walkthrough -#### Step by step walkthrough 1. Modify `buy_powerup` in `Cryptobot` - 1. Modify `data_type` to also include `cryptobot_address` which is of type `sp.TContract` that accepts a record of string `power` and nat `duration`. - 2. Define `self_contract` - it's the contract that holds the details to `receive_powerup` entry point in `Cryptobot`. - - accepts a record of same shape as `active_powerup`. - - address points to `Cryptobot`( use `sp.to_address`) - - points to `recieve_powerup` entry point. - 3. Modify `data_to_be_sent` to hold `cryptobot_contract` as well, which is equal to `self_contract`. - + * Modify `data_type` to also include `cryptobot_address` which is of type `sp.TContract` that accepts a record of string `power` and nat `duration`. + * Define `self_contract` - it's the contract that holds the details to `receive_powerup` entry point in `Cryptobot`. + * accepts a record of same shape as `active_powerup`. + * address points to `Cryptobot`( use `sp.to_address`) + * points to `recieve_powerup` entry point. + * Modify `data_to_be_sent` to hold `cryptobot_contract` as well, which is equal to `self_contract`. 2. Implement `send_powerup` in `Market` - 1. Define `powerup_to_send` as the result of `find_powerup`. - 2. Make an inter-contract call to `cryptobot_contract` and send to it the `powerup_to_send`. + * Define `powerup_to_send` as the result of `find_powerup`. + * Make an inter-contract call to `cryptobot_contract` and send to it the `powerup_to_send`. 3. Implement `receive_powerup` in `Cryptobot`. - - Set `active_powerup` equal to the `poweup` being received as the parameter. + - Set `active_powerup` equal to the `poweup` being received as the parameter. + +### Testing our code -#### Testing our code 1. Invoke `Cryptobot.buy_powerup` inside `test` function with the parameter `time_freeze`. 2. Use `scenario.verify` to check whether `mutez_points` held by `Cryptobot` is equal to 2000 mutez. -3. Use `scenario.verify` to check wether the `active_power.power` of `Cryptobot` is `"time_freeze"` or not. \ No newline at end of file +3. Use `scenario.verify` to check wether the `active_power.power` of `Cryptobot` is `"time_freeze"` or not.