diff --git a/lessons/inter-contract-calling/05/05.mdx b/lessons/inter-contract-calling/05/05.mdx index 75718921..a5bd5280 100644 --- a/lessons/inter-contract-calling/05/05.mdx +++ b/lessons/inter-contract-calling/05/05.mdx @@ -3,7 +3,7 @@ title: Inter-contract calling, part-1 chapter: Chapter 5 slug: chapter-05 filterBy: module-02 -isCode: true +isCode: false editor: language: python startingCode: | @@ -91,7 +91,7 @@ editor: # test code over here. - answer: | + answer: | import smartpy as sp class Cryptobot(sp.Contract): @@ -113,7 +113,7 @@ editor: # add market_address over here. market_address = market_address, # add active_powerup here. - active_powerup = sp.record(power = '', duration = 0) + active_powerup = sp.record(power = "", duration = 0) ) @@ -139,7 +139,7 @@ editor: # 4. Define data_to_be_sent - record that holds a variable powerup which is equal to powerup accepted in the parameter. # 5. Call the market_contract with powerup and 0 mutez. data_type = sp.TRecord(powerup = sp.TString) - market_contract = sp.contract(data_type, self.data.market_address, 'send_powerup').open_some() + market_contract = sp.contract(data_type, self.data.market_address).open_some() self.data.mutez_points -= sp.mutez(3000) data_to_be_sent = sp.record(powerup = powerup) sp.transfer(data_to_be_sent, sp.mutez(0), market_contract) @@ -179,17 +179,18 @@ editor: scenario += test_bot # test code over here. - scenario += test_bot.buy_powerup('time_freeze') + scenario += test_bot.buy_powerup("time_freeze") scenario.verify(test_bot.data.mutez_points == sp.mutez(2000)) --- ## 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* 🔥. - +It can make your smart contracts go _super saiyan_ 🔥. ## 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,20 +199,25 @@ 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 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 sp.contract(t, address, entry_point = "") ``` + Don't worry if it looks overwhelming at first glance, we're going to break it down :) -`sp.contract` takes three arguments - +`sp.contract` takes three arguments - + 1. `t` - it's the **type** of data that the contract is accepting. `t` has to match the type of `data_to_be_sent` in the `sp.transfer`. 2. `address` - this specifies the adress of the contract inside which you'll be calling an entry point. Needs to be of the type `sp.TAdress`. -3. `entry_point` - this is to specify exactly which entry point you want to call in the contract. +3. `entry_point` - this is an optional parameter which specifies which entry point do you want to call. The catch is, you don't need to specify the entry point if the contract only has 1 entry point (like our `Market` contract). The result of `sp.contract` is passed to `destination_contract` in `sp.transfer`. @@ -219,13 +225,12 @@ The result of `sp.contract` is passed to `destination_contract` in `sp.transfer` @sp.entry_point def send(self): - target_contract = sp.contract(sp.TString, - self.data.target_address, - entry_point = "recieve").open_some() + target_contract = sp.contract(sp.TString, + self.data.target_address).open_some() data_to_be_sent = "This message should be sent!" - sp.transfer(data_to_be_sent, - sp.mutez(0), + sp.transfer(data_to_be_sent, + sp.mutez(0), target_contract) ``` @@ -233,31 +238,31 @@ def send(self): - `.open_some` chained to `sp.contract` simply checks if the specified entry point in the `target` contract is accepting a string(the specified data type which is the first argument to `sp.contract`) or not. - Look how the type of `data_to_be_sent` matches the type specified in `sp.contract`, this is mandatory. - -The full example below will clear up things even more :dart: +The full example below will clear up things even more :dart: ### Show me an example + ```python class Sender(sp.Contract): - + def __init__(self, target_address): self.init(target = target_address) - + @sp.entry_point def send(self, payload): data_type = sp.TRecord(payload = sp.TString) - c = sp.contract(data_type, self.data.target, entry_point = "recieve").open_some() + c = sp.contract(data_type, self.data.target).open_some() data_to_be_sent = sp.record(payload = payload) sp.transfer(data_to_be_sent, sp.mutez(0), c) class Target(sp.Contract): def __init__(self): self.init(msg = "") - + @sp.entry_point def recieve(self, params): self.data.msg = params.payload - + @sp.add_test(name = "Test") def test(): scenario = sp.test_scenario() @@ -266,7 +271,7 @@ def test(): test_sender = Sender(target_address = test_target.address) scenario += test_sender scenario += test_sender.send('this should be sent to target.') - + scenario.verify(test_target.data.msg == 'this should be sent to target.') ``` @@ -276,24 +281,27 @@ This is a bare-bones example, we covered the `send` function in the section abov 2. Inside the `Sender` contract, we're calling the `receive` entry point present inside the `Target` contract. 3. `recieve` entry point simply assigns `msg` the value it's being sent as the `payload`. - +> Note: If the `Target` contract had more than one entry point. We would also need to specify the entry point in `sp.contract` + ## #buidl-ing time ### 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 + 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 - - * power which is an empty string - * duration which is equal to 0 + - 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. + - Define `data_type` as a record which holds a variable called `powerup` of type string. + - Define the `market_contract` using `Market's` address which 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.
@@ -302,4 +310,4 @@ Let's give our `Cryptobot` the ability to buy a `powerup`. ### 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 +- Use `scenario.verify` to confirm whether `mutez_points` in `Cryptobot` are equal to 2000 mutez. diff --git a/lessons/inter-contract-calling/06/06.mdx b/lessons/inter-contract-calling/06/06.mdx index 21a8f164..2b87519f 100644 --- a/lessons/inter-contract-calling/06/06.mdx +++ b/lessons/inter-contract-calling/06/06.mdx @@ -25,7 +25,7 @@ editor: }, mutez_points = sp.mutez(initial_mutez), market_address = market_address, - active_powerup = sp.record(power = '', duration = 0) + active_powerup = sp.record(power = "", duration = 0) ) @@ -46,7 +46,7 @@ editor: @sp.entry_point def buy_powerup(self, powerup): data_type = sp.TRecord(powerup = sp.TString) - market_contract = sp.contract(data_type, self.data.market_address, 'send_powerup').open_some() + market_contract = sp.contract(data_type, self.data.market_address).open_some() self.data.mutez_points -= sp.mutez(3000) @@ -105,7 +105,7 @@ editor: test_bot = Cryptobot(manager_address = my_account.address,life_state = True, initial_mutez=5000, market_address = market.address) scenario += test_bot - answer: | + answer: | import smartpy as sp class Cryptobot(sp.Contract): @@ -124,7 +124,7 @@ editor: }, mutez_points = sp.mutez(initial_mutez), market_address = market_address, - active_powerup = sp.record(power = '', duration = 0) + active_powerup = sp.record(power = "", duration = 0) ) @@ -145,7 +145,7 @@ editor: @sp.entry_point def buy_powerup(self, powerup): data_type = sp.TRecord(powerup = sp.TString) - market_contract = sp.contract(data_type, self.data.market_address, 'send_powerup').open_some() + market_contract = sp.contract(data_type, self.data.market_address).open_some() self.data.mutez_points -= sp.mutez(3000) @@ -175,7 +175,7 @@ editor: # define a local variable called `powerup_to_send` # powerup should be a record which holds a variable called power(equal to an empty string) and another variable called duration(equal to 0). - powerup_to_send = sp.local('powerup_to_send', sp.record(power = '', duration = 0)) + powerup_to_send = sp.local("powerup_to_send", sp.record(power = "", duration = 0)) # loop through the powerups in the contract storage. # inside the loop, if it matches the powerup we're looking for set `powerup_to_send` equal to the powerup. @@ -211,34 +211,42 @@ editor: --- ## 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. 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 - +Here's how you define a sub entry point - + ```python @sp.sub_entry_point def double(self, x): sp.result(x * 2) ``` + Notice, **`sp.result`** is used to return from a sub entry point instead of `return`. -And it can be invoked like this - +And it can be invoked like this - + ```python @sp.entry_point def update_result(self, num): # Assume double is a sub entry point already implemented in the smart contract. self.data.result = self.double(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` @@ -247,29 +255,35 @@ Sub entry points can access the contract storage - if your function doesn't need 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 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`
-You can define local variables in SmartPy using `sp.local` - +You can define local variables in SmartPy using `sp.local` - + ```python total = sp.local("total", 0) ``` + But why not just define a normal python variable like - `total = 0`? Because normal python variables can't be updated during execution of a smart contract but variables defined using `sp.local` can be updated. + - 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`** - +**Value of a local variable is accessed through `.value`** - + ```python x = sp.local("x", 0) # now to access or modify the value of x, you need to use `x.value` @@ -282,11 +296,12 @@ 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 @sp.sub_entry_point def add_to_total_received(self, amount): self.data.total_received += amount - + @sp.entry_point def calculate_received(self): sp.for transaction in self.data.transactions: @@ -294,19 +309,21 @@ def calculate_received(self): self.add_to_total_received(transaction.amount) ``` -Imagine this as a part of a `Ledger` smart contract. +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 - + ### 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 + - 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. - 3. Inside the loop, if it matches the `powerup` we're looking for set `powerup_to_send` equal to the `powerup`. - 4. Return the value of `powerup_to_send`(remember to use `sp.result`). \ No newline at end of file + 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. + 3. Inside the loop, if it matches the `powerup` we're looking for set `powerup_to_send` equal to the `powerup`. + 4. Return the value of `powerup_to_send`(remember to use `sp.result`). diff --git a/lessons/inter-contract-calling/07/07.mdx b/lessons/inter-contract-calling/07/07.mdx index 3e86d76f..b67c0075 100644 --- a/lessons/inter-contract-calling/07/07.mdx +++ b/lessons/inter-contract-calling/07/07.mdx @@ -25,7 +25,7 @@ editor: }, mutez_points = sp.mutez(initial_mutez), market_address = market_address, - active_powerup = sp.record(power = '', duration = 0) + active_powerup = sp.record(power = "", duration = 0) ) @@ -50,7 +50,7 @@ editor: # cryptobot_address is of type `sp.TContract` which accepts a record that has the same variables as `active_powerup`. data_type = sp.TRecord(powerup = sp.TString) - market_contract = sp.contract(data_type, self.data.market_address, 'send_powerup').open_some() + market_contract = sp.contract(data_type, self.data.market_address).open_some() self.data.mutez_points -= sp.mutez(3000) # define self_contract - @@ -83,7 +83,7 @@ editor: @sp.sub_entry_point def find_powerup(self, powerup): - powerup_to_send = sp.local('powerup_to_send', sp.record(power = '', duration = sp.nat(0))) + powerup_to_send = sp.local("powerup_to_send", sp.record(power = "", duration = sp.nat(0))) sp.for p in self.data.powerups: @@ -136,7 +136,7 @@ editor: }, mutez_points = sp.mutez(initial_mutez), market_address = market_address, - active_powerup = sp.record(power = '', duration = 0) + active_powerup = sp.record(power = "", duration = 0) ) @@ -161,7 +161,7 @@ editor: # cryptobot_address is of type `sp.TContract` which accepts a record that has the same variables as `active_powerup`. data_type = sp.TRecord(powerup = sp.TString, cryptobot_contract = sp.TContract(sp.TRecord(power = sp.TString, duration = sp.TNat))) - market_contract = sp.contract(data_type, self.data.market_address, 'send_powerup').open_some() + market_contract = sp.contract(data_type, self.data.market_address).open_some() self.data.mutez_points -= sp.mutez(3000) # define self_contract - @@ -195,7 +195,7 @@ editor: @sp.sub_entry_point def find_powerup(self, powerup): - powerup_to_send = sp.local('powerup_to_send', sp.record(power = '', duration = sp.nat(0))) + powerup_to_send = sp.local("powerup_to_send", sp.record(power = "", duration = sp.nat(0))) sp.for p in self.data.powerups: @@ -230,9 +230,9 @@ editor: scenario += test_bot # test our code over here. - scenario += test_bot.buy_powerup('time_freeze') + 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') + scenario.verify(test_bot.data.active_powerup.power == "time_freeze") --- ## Intro @@ -279,15 +279,15 @@ Let's go and complete our whole system so that you can finally use the powerups ### Step by step walkthrough 1. Modify `buy_powerup` in `Cryptobot` - * 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`. + - 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` - * 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`. + - 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. diff --git a/src/templates/components/chapter/CodingInterface.js b/src/templates/components/chapter/CodingInterface.js index f0ef9fa0..9a9ee634 100644 --- a/src/templates/components/chapter/CodingInterface.js +++ b/src/templates/components/chapter/CodingInterface.js @@ -139,7 +139,7 @@ const CodingInterface = ({ error: [...res.error, compiledCode.error], success: res.success && compiledCode.success, }); - console.log(typeof res.error, res.error); + console.log('error from compiler', res.error); return; }