Solidity 101 | Session 3 (Khawla)
Solidity 101 — dev3pack & Cyfrin Updraft · 59:32
A Solidity lesson uses a FundMe contract in Remix to explain payable functions, msg.value, Ether denominations and transaction reverts. It introduces the oracle problem, decentralized data feeds and Chainlink’s AggregatorV3 interface, then closes with a quiz on the concepts.
Speakers
Topics
From Solidity 101 — dev3pack & Cyfrin Updraft, hosted by dev3pack.
Transcript
[Music] Wow. Um tech. All right. Okay. Just remove whole AI noteaker as usual. And yeah.
So, I'm going to put a message Hello. Sorry. Hi. Hi. How are you? Great. It's like a sunny day uh on my side. So, yay. I think winter is over. No. Um yeah, I think so.
Okay. I think so. Are you going to eat CC? Yes. Okay. And you No. Why? I don't know. Maybe just dev connect but not easy. Yeah. Everyone's going to to def connect. Yeah. But it's too far for me. I don't know. Argentina.
Yeah, I know. Very far. Yeah. And you have to deal with um visa process or not. Yeah, exactly. I have to apply for a visa, but I think it's easier than like let's say the US. I mean, the US is horrible now for sure. Hello. Hello everyone. Just put a message. All right, we going to wait 2 minutes. Something like this, I
[Music] guess. Let's see. I know some some members will fly we fly from next week in London to participate to the avalanche alatan. So that's nice. Oh yeah. Woohoo. Congratulations. And I heard something about more account itself is like actually organizer organizer um stuck to to to really attract partners just because
um it's too much too much farmers uh into the Eteram ecosystem. them. Yeah. Um really yeah too too much bunts and so on and so basically they didn't they didn't find uh any uh return on investment for the moment. So yeah I heard about it today um that uh the EVM algatan are starting to do to go like this. No way. Yeah.
I didn't know that. That's crazy. Yeah, but you know uh foundation didn't put any efforts um to on board new people. they are just focused on the tech side and then that's why like I think from next months I will I will try to push them um to to really understand that because otherwise um like some people are going to for example Solana and so on but yeah it's a missed opportunity.
Yeah. Yeah. Exactly. But let's see this this your um that s for them. Sad. That's sad for them. Yeah. Exactly. I see a lot of talks on Twitter about this, but I don't know where it started from.
Uh from the leadership, the term foundation leadership. Yeah, they they posted something. Um yeah, it was on December something like this and then that's why they changed the leadership. Yeah. But let's see. something will happen. Um, but I will I will talk with them later. Yeah, that's pretty sad.
All right. So, I guess let's start. Um, so, uh, I I put I put like Wait, wait, wait. Telegram. Where is it? Uh, can wait. I think I'll turn the AC on. One minute. [Music] Uh yes, I put a message like a pool. Yes, a poll on um on Telegram uh asking if you have completed the section one of um of Cipher and don't hesitate to reply to it and then it's it's great to to
follow up everyone and then if you have any issue don't hesitate to ask question too. All right, I'm back. You were talking to me. No, no. Okay, no worries. All right, let's start then. Yeah. So, to precise, um, Rola is really specialized uh into this area. Yeah. Oracles.
Yeah, I guess so. So if you have any Oracle questions, hit me up. Let's go. Um so today we are actually going to do the fund me project and then at the end we'll talk about oracles a little bit. So um I think section one and section two were covered. Um yes, in the last two sessions. Yes, exactly. Exactly. So now today we're going to start with the fund me section. Um and we're going to look into the fund me project um and
wait sending you through the function. Maybe I skipped this section I guess. And then we'll look into solidity reverse and also an introduction to oracles. Did someone say something? No, you're just sending. Okay. So um let's start here. We want to build a project in solidity which is like a web3 um crowdsourcing application. So you want people to like you want people to fund your project just and this contract will be a way for you to raise
money. So, oh by by the way uh during a I saw a lot of project doing this kind of things. Um so it's it's clearly too common. So don't do do this kind of of doing the academ because uh it's too common. Yeah. Well, okay. That's a good uh that's a good thing to take care of. And yes, so then what we want to do is to allow users to send the native cryptocurrency of the blockchain to the contract. However, um you want to say
that the minimum fund should equal to $5. So now there are some questions or challenges that you might have when you're trying to set up a project like this right? So what are the questions? First of all, I want people to send me money. Um, but then how do you send money to a contract? How do you send ease to a contract or any native cryptocurrency? Um, and then if somebody sends me money, how do I access that value? Where is it going? And then yeah, like how how can I use it?
And then how do you And then one of our requirements for the project was to um accept a minimum of $5, but then how do you translate that? How do you how do you like convert Ethereum or ETH to dollars and then figure out the calculation from there, right? because they're going to send you the because the contract only accepts the native currency um and sometimes tokens like it does accept tokens but let's say that the contract that we will set up will accept
ETH it will take ETH and then you're just not sure how to check the price of ETH in terms of dollars so this is where oracles come in and which we'll talk about Um, and then let's say they don't send the right amount to you when they're trying to fund your project. Uh, what can you do in this case? How can you um not take money from them? How can you stop that process and revert or um just not like you don't allow the function to continue executing. Um, so these are the kind of challenges or questions that you might
have when you're trying to set to set up a FundMe project, right? So let's see how we can do that in Remix. I'm going to open up Remix now. I'm sure by now everyone's familiar with Remix. That's a good thing. Okay, I have my remix open and I hope everyone also does. Let me delete this.
Now if you remember you start by creating you you create a contract by starting to create a file like you you initiate a file and then you call it fundme this dossole extension and then you need the license the pragma um or like the legacy compiler version and then the contract keyword which should match uh the contract keyword and the name of the contract which should match the name of the file that you have here. So let's do this. We'll say I'll use this from my previous
contract. Um this is the license identifier. This is a solidity version. Again, we're saying that this contract can be compiled using Solidity Compiler version 0.8.13 and above. So, if they're rolling out a 0.830 compiler, you can still use that to compile um this contract. And then you say contract and then you call it fund me.
And this is where it starts to get interesting. I hate when AI starts suggesting stuff like please, no one asks you for anything. Um let's say um where do we start? Okay, let's start with declaring the function fund. This function will not take any variables. It will not it will not have any parameters and it will be public. And now this is the interesting part is that you can mark it as payable.
This is a payable modifier. And what this means is that this function can receive ETH. It can receive money like you can transfer stuff to it. Um so payable allows the function to receive ether together with a call. So you call a function fund and you also pay for it at the same time. Um and then you can use this to either uh for example one of the use cases for pay payable is let's say you want to charge someone um a fee for calling this function
uh for again in terms of oracles let's say you are requesting for the current price of bitcoin in USD so then if it's um if it's a special type of oracle. Sometimes you'll have to pay fees to fetch that price. Um, so this is one way of using the payable modifier either for people to like fund your project for example or for example for charging people um in using your services for example that because an Oracle is kind of a service. Um and
then let's see so this is payable right and then we are trying so so we want to say that we wait how do I okay let me maybe we can start with testing the function and then we can talk about the require statement But before we get into required, let's see how this function would work. For now, I will just say new int 56 my value and then it will
just do anything for now. It will not let's say let's say it will assign one to my value but it's not doing anything. I'm just I just want to test how this function will receive ether. Now you compile this contract and you deploy it using remix VM and here you have this function. So now this function is marked as payable.
But how do you pay through remix now? So one thing I like to talk about is the color codes in Remix IDE. If you see here, when it's marked as red, when a function is marked in red, that means it's a payable function. When it's marked in orange, that means it's not a payable function, but it's a setup function. And it's in marked in blue. That's a getter function. So it only reads values and display them to you.
But an orange function is a setter function. It changes um it it updates the state variables essentially. Um okay. So now this is a function called fund and it's payable and I want to pass some ETH to this function. So, how do I do that? If I just call it like this, let's see what's going to happen. Um, it will get called even though you didn't pass any amount. Why is that? Because you don't have any conditions set here. You're just calling it payable. But you can pay zero ETH and
it will be invoked. Um, actually, let's do public. Let's do this as public so that we can get a getter function which we can access this value through and read and then let me clear my terminal. Okay. When I compile fun we'll redeploy and then let's see what happens. You call my value. It's going to be zero, right?
because we didn't do anything with this variable yet. But now, let me call fund without passing any ease. And like we saw um a few minutes ago, I was able to call the fund function even though I didn't pass any e. And then if I read my value, is it going to be one? Let's see. Yes. So, it got updated and now my value is equal to one. And so just because we marked a function as payable does not mean that you have to pay for it because it can be zero ETH. So then how do you put um a condition there that says no you
can't give me zero ETH. It has to be non zero for example or it has to be um it has has to be greater than one e like I need at least one e or not even at least like above one e. So how would you say something like that in your function to avoid people sending zero e to you? So the way that you would do that, oh, but before we go there, let's see how we can pass um how we can pass E to this function.
You're going to go here to this value field and you're going to switch to ether and you will pass one one ether and then you click on the function. So you set how much you want to pass and in which um in which unit and then click on fund to see I'm not sure if it shows you. Yeah, it shows you there's a value that has been passed to this contract and it's this much of way. And now you wonder what is we what is ETH? What is guay? So
let's talk about that. Those are the different Ethereum units. So, because ETH is so big, um like right now one ETH is like what $2,500 I guess. Um ETH is like a big big number and you don't always deal with values that are this big, right? like sometimes it's only um a 0.00001 ETH for example that you're dealing with. So in order to represent smaller units of ETH you have these Ethereum units. Um so one ETH let's
see look here one E is equal to um what is it equal to 10 to the power of 9 guay and then one and then 10 to the power of 18 we so we is the smallest denomination of ether or the smallest unit and then guay comes um before we and ether is the largest unit. Um usually we is the unit that is being used in the smart
contract. That's what we deal with. Um and then guay is used for gas. So if you look at a random transaction on Ethereum, for example, this one, you will see that the gas price, the gas fees um are all in guay. So usually gas prices um are u so usually guay is guay is a unit for gas prices and then when you're writing smart contracts you deal with way um yeah so then we see here we were able
to call the fund function we were able to pass a value or a money or an amount to uh the fund function just by giving it a payable um modifier. And then we were also able to see that even if you send zero ETH, you can still execute this function because you don't have any conditions on the amount. So then now the next step becomes um how can we put a condition um that says hey I only accept this amount of money and if you don't give that to me then you're not allowed to update the
state variable my value for example. So to do this we will use a require function. So let's talk about validations. So there is um it's not a function. It's is it a function? No, I mean yeah. So it's like a validator that you call required and then you can either pass a condition um no like you can sorry you can define the condition and if that and that condition can be either true or false.
It can be boolean and then based on that the um it will abort the execution of of the function call and it will revert the state changes if the condition is false. But sometimes you also want um to abort the execution of the function while also printing a message that can show up in your terminal and maybe like explain what happened and why it failed or why it reverted. So that's something that you can do. There are two ways to use um required here. And then there's also
revert. Revert um does not uh there's no condition that you can pass to revert. So that's the difference between require and revert. Uh revert will just revert like immediately like you can for example use it in an if statement. You say if something then call revert. Um but but with require you don't need to set up an if statement. for example because like you can just put the condition inside it. Um and then revert can also take a parameter which is the message. That's the only thing that it can take and they both um abort the
execution and they both revert the state changes. However, require takes a condition. So let's see how we can use that here. Um let's say with every call I want to increment. Um I think just so that we can observe what happens to the state changes. We'll do my value + one every time the fund function is called. And now we will introduce require statement here. And the require statement will use something or access something called message. And it will say that the
message do value um and because we're passing uh we're passing one ETH and that is the smart contract deals in way. So we're saying it should be larger than one ETH. So that means 1 E18, right? 10 to the^ of 18. And then the message will be you didn't send enough ease. Okay. Um so message value is um so like in a transaction in a function call right you will have like you you will have a message
object and within that message object you can access different things. So we will use that we will use message and then we'll message object and we'll access value and that will show you the um amount of way that that is being sent when somebody is calling your function and this is a globally accessible variable. So that means you can use it anywhere um in your contract. Um you can access it from anywhere in your contract. So that's what we're doing. So we're saying hey look at this function call fetch that value uh which will be available in the message object fetch
the value that they're passing to my contract check if it's larger than one um e remember 1 e is equal to um one e18 which is equal to 10 to the power of 18 way Okay. Um and then if this condition is true, if it's larger, then it should continue executing and everything is fine. But if it's false, then print this message didn't send enough E and cancel the whole um state variable update. So
what does that mean? That means that if um my value uh yeah so if you are updating my value and you go into this function you say my value is equal to my value + one and then it comes here it checks that you didn't send any ease it will cancel this state updates here it will cancel the changes that it made in in in in in in this part. Yeah. So if you're incrementing it by one, let's say if it was at, if it was my value equals to one and then it enters this function and then now it becomes two and then it checks uh the condition in the require
statement and it's false. So then my value goes back to one. So let's see how that looks like um uh equation. Yes, if it's not bigger than what? No, it will it will revert and it will show this message. Didn't send a fee. Let's try it together. Deploy the contract and my value is at zero now.
And we will pass. How much should we pass? That's fast. Zero E. Yeah. Can we do decimals? I don't know. 0.1. Yeah. No, you can't. What if I want? Can we wait for that? No. Anyway, let's not complicate things. So, let's say I'll pass one E. No, let's Yeah, let's pass one E because in the condition, I'm not saying greater than or equal. I'm just saying greater. So then I'll call it a reverted. So it says didn't send enough E which is exactly the message that we
told um the function to throw when this condition is not satisfied. So then let's try sending two E. Is it going to work? Oh yeah. Oh. Oh, actually let's see my value. My value is still at zero. You see? So even though it started here, right? It starts with adding one to my value and then it comes and checks it. But no, everything that you've done within this function will get reverted, will be cancelled, and it will go back to its original state. That's the whole uh purpose of a require statement.
Um yeah so let's pass two ETH let's fund uh and or like let's pass um two ETH as a value and then I'll call fund now and you can see the balance here also this whatever uh ETH that you're receiving goes into your contract so even your contract itself can hold money um sometimes I guess Yeah, I guess not sometimes, but it's a it's a good practice to have a separate address um where let's say your funds will go to like don't store don't store funds on a
contract like put them in a separate wallet. Um so as you can see here my balance is now at two E that means it got accepted. So then if I call my value it should be one. A it's at one. Let's go. So then yeah. So this is how a require statement works so far. Any questions? Don't see question. Okay.
Cool. Nice. All right. So, so far we spoke about um message value and the payable modifier. Um you can also check here. Wait, what's that? Let's see. You can see all of the globally accessible variables in Solidity. it. There's a bunch of things you can you can access. Message data, message sender, which we use a lot, message, transaction origin, block number. So, these are all globally accessible
variables that you can use within your contract. So, let me share this with you. You can go chat. Okay. Now um we spoke about Ethereum units. We spoke about um the different validators require versus revert. Now let's talk about oracles. Woohoo. Um so oracles. Yeah. So the openness Yes. In Dubai, you need
to to drink, right? Yeah. The weather. It's insane. But um Yeah. So, let's talk about the oracle problem. And I took this quote from him from Patrick, right? How did I forget his name? Wow. Um, shout out to Patrick. You're so cool. If you see this. Yeah, Anthony. Okay, that was funny. Um and so the oracle problem says that smart contracts are unable to connect with external systems, data feeds, APIs,
um existing payment systems or any other off-chain resources on their own. Um so then like what that means is that let's see here this is even better. So blockchains are deterministic in nature. So that means what that basically is trying to say is that you have all of these nods and if they can all come to consensus about let's say a single value I think I need to to make a brief introduction to nodes.
Yeah. Okay. So like no nodes are um like if you have a blockchain it's a network and then within that network there are people that are running the same version of this network right and they're all connecting and syncing and then they are all coming to consensus about the state let's say for example in my contract my value is now at one all of those nods should have um all of those knots should have my value equals to one at the same time. So they should all have the same values replicated everywhere. All all
have the same states. So that's how that's how the a blockchain should be. And so we call it deterministic um because if you give it the if you give the same inputs you should get the same outputs all the time. But now let's say my let's say um one nod is trying to access an API for let's say weather data. another nod is trying to access the same API but then both of them would not be getting the same API the same uh weather uh the same weather value right so let's
say it's 35 um Celsius for one nod but then it the other nod calls the same API at the same time and they might get I don't know 34 Celsius for example so then this is not okay because they should all have the same states. They should all have the same values replicated. So that becomes non-deterministic which is not the nature of a blockchain network. So then who can help with this problem? Oracles, right? So then what oracles do is that they do the work. They go they check the weather. they see okay um on this
website on this API it says 35 there it says 34 it says 32 whatever let's take all of those um let's take all those data endpoints sorry all all those data inputs and then we aggregate them we get a single value and then that single value will be delivered to your contract so um that way everyone one will have the same um the same value of weather at this exact time stamp. That's what the oracle is going to deliver to you and everyone can access this value. Um and so
blockchains are um isolated, right? They don't know anything about the market data. They don't know what's happening um in retail payments, I don't know, bank payments like it says here. um they they have no clue what's happening in the outside world. So in this case you would need oracles to communicate that to them um and deliver that kind of data yeah to to your contract. Um so as you can see here uh another big issue with oracles is that you can't rely on a single person right uh to deliver weather data for you
like um it's not a good thing to just trust one person to deliver that data for you and and if I say oh I aggregated um I I looked into those several websites and I aggregated this data and I'm going to give it to you. You're you can't really trust me, right? Because it's just a single person doing this activity. So that's the problem with oracles. Centralization is a big problem and we know a lot of oracles have been trying to solve this and they are and so there are many different approaches for decentralization. Um so then right yes so
then even with chain link they have their own decentralized oracle network I think it's called decentralized oracle network dawn yes they have the dawn network and the dawn network um is essentially also multiple nods right it's like think of them as multiple people looking at the same data sources bringing that aggregating it and delivering it to you. Um, yes. So, that is how oracles work. Let's see. Yeah, it's it's a really crucial um aspect in repry to
get the outside information into exactly chain world. And then when you need to really be sync synchronized uh with for example a price or anything you need to to really rely on or for that. So it's really really crucial especially on defy by the way. Mhm. Exactly. Almost like a lot of defi applications use oracles. So it's not just that's why it's every introduction to solidity course you would see oracles being mentioned because they they are literally um a key uh piece in in in in in DeFi. So a lot
of DeFi applications rely on that to get the uh to get market prices yes of any asset. Um so this is an example of a Bitcoin USD price feed. As you can see, it says right now, Bitcoin in USD is at 100K, which is again crazy. Um, and this is um these are the these are this is the last update time. So, it will tell you, hey, the last time we uh updated this value and we fetched and aggregated the prices was 26 minutes ago. And then, okay, so when is the next update going to happen? It's showing you right here.
It's showing you the heartbeat in 33 minutes, I believe. At how much did you buy? I don't have BT. Wow. Bold of you to assume. No, I'm very broke. Oh, right. I think it's like the I don't know when you start in in Wall Street like it's the first thing you buy. Yeah. No, I didn't. I only bought like ETH maybe. Oh, okay. Yeah, I reby. It's like when it was at two two,000 I said
a no way. Yeah. When it's going like this, I'm the people who are going to to buy. Yeah. Oh my goodness. Anyone else also has crypto? I think it's a a really good way to always um try application because it's like this that you're going to be familiar with the ecosystem and also build um real um application on your side. So exactly have like I don't know $10 by month for testing.
It's use unis swap. I think like it's very user friendly and fun. Yeah, that's true. That's true. Um, yeah, maybe a little Yeah, just to show you that uh we're also working on blockchain oracles and just to show you the decentralization part. Um, we have uh for example this one, push oracle, we're using hyperlane here. Um I don't know if you know hyperlane but it's like so essentially like they produce um we have like data feeders.
The data feeders take um the prices from the from exchanges and different markets and then what happens they deliver it to like this uh what we call laseret which is a rollup and then after that um there's a hyperlane bridge which takes those values and deliver it. So just to show you that there are different uh ways to um decentralize your oracles and those solutions exist. So yeah, it's interesting. Look at the price feeds.
Look at these nods. Look at the responses. How everyone's contributing. That's very cool. Um it's a big big world. And then maybe lastly we can see we can quickly talk about the um we can quickly talk about the aggregator interface. Any questions so far though? Aggregator. No, no. I just want to mention that um on June we're going to have like a specific um mini school um about um more training for uh training about what chain link.
Yeah. Um amazing. Yes, they're running an academy and then it's the main actually I signed up. Okay, nice. Let's let's do a team. Yes. Um so it's the main um array call used uh into web three actually so if you will be familiar with it um you will find every time chaining into a katon so that's that's a great way um to right now get into it on June so yeah we'll keep you updated about it exactly I think you also formed a team for another hackathon I don't remember for bass I I think yeah yeah yeah for
basic academ okay um yeah so then this is the aggregator v3 interface we'll also I believe we're going to talk about interfaces at some point or maybe I should have but essentially interfaces are like the blueprint for your smart contract um I think we will dive into it in some later session but to use um to use waiting data feeds feeds. Um learn how to
read. Okay, nice. Open a remix. What happened? Yeah. So, see this is an example of a contract that is consuming um a chain link oracle. So, you can see here um it's passing. So every price feed let's say BTC, ETH, um they all get their own aggregator contract and you can see those list of contracts in the documentation. Then you can pass it to
the constructor and then you can call um and then you can call latest round data. Yes, you can call latest latest round data on this contract on these aggregator contracts which will give you the latest answer which means that's the latest value of Bitcoin in USD. So as you can see it's pretty simple. You can also get the timestamp and other parameters that you would need, but essentially it just needs to import the aggregator v3 interface and then um pass the aggregator contract address to that
interface and assign it to the state of heat value and then from there you can read. Um is it casting that you do? Um kind of like yeah similar similar concept. Yeah. So when you do this it allows you to access um the methods on the contract. I remember Ashley was pretty new uh like three months ago about solidity stuff and right now ask she was asking some question um yesterday she help um Rael
as well. So to see that yay share your advice. Yeah. So that's amazing. That's great progress. Wow. All right. So, I think we are done. So, try it out. Try different price feeds. Um, this one is on Sapoleia. Um, I know Seapoleia can be annoying sometimes, but there are like other networks. Um, not sometimes, all the time. And yeah, so this is what we covered today. Let's do a quick quiz.
Quiz time. Drum rolls. Test your knowledge. There are three questions ahead of you. Sorry. No, I said three question. Yesterday it was like eight questions or something. No way. Okay, let's start. What is the correct relationship between way guay and ether in Ethereum's unit system? Who can answer? One two three four five six seven eight nine.
A, B, C, D. They say D. Yeah, I also say D. Let's see. A, good job. Next question. Take like a be drum rolls. magician or magician. Yeah. And then what is the purpose of the revert action? A revert action allows you to undo the most recent state change on the smart contract when call or a revert action allows you to undeploy. That's wild. a smart contract or a revert action stops execution but keeps all state changes up until that
point or a revert action undoes all prior operations and returns the remaining gas to the transaction sender. Which one? You will see a lot of this kind of thing on your side. Yeah. We have people saying D, people saying C. How are we feeling about this? Okay, so we all agree that B is not correct. Like definitely it does not undeploy a contract. So then we're left
with A, A, C, and D. A revert action allows you to undo the most recent state change on the smart contract when called or it stops the execution but keeps all state changes. Does anybody agree with this that it keeps the state changes? Remember when we were testing my value and then we called my value when it reverted and my value was still at zero, right? So then no way that this could be possible. Oh I would say this one. You were saying this one?
No, you you get a a D on the test. Oops. Oh god. Okay. So then we're we're left with A and D. Okay. I see two people said D. And I also think Wait, a revert action undoes all prior operations. No, the thing is like I'm not sure about I think it's a because like the fact that the gas is returning to people is like I wish. Right. Yeah, I would I would be so happy. Yeah, I would break all of the functions just to get my money
back. So, yeah, I think it's a Let's see. Oh, no. All right. Wait. Okay. It's returned the remaining gas. I didn't know that actually. Yeah. Me too. Wow. Sunday. Thank you. Also, Ashley both said D. Awesome. Okay, I actually didn't know that it returns the remaining D. Maybe I need to go back to Saluzi docs. Good job. Let's see. The third question is, which keyword is used to
allow a function to receive native blockchain tokens such as ET? Which one? We spoke about this. Hey, [Music] correctable. Woohoo. Yay. Congratulations. This is the end. Congratulations to all of my solidity nerds.
Woohoo. We are done with the quiz. Um hopefully you got all three right. Don't mind me. Um and that's it. We are done I think for tomorrow. Uh we're going to do libraries. We're going to see how to fetch from chain link which is so cool. What else? I think I don't really remember but I need to to revise. Yeah, that's step number one. We all spend three hours on solid Disney dots. Oh god. On my side. I I think like I just did the first section or something like this. I was not going to like further.
Yeah. Yeah. I think so. Just this section. Uh yes. Okay. You still have um I Thursday and Friday. I was boot camp with an club before. So Oh, okay. Perfect. Yeah. So then you don't really need this. That is a great way. It's a great way to to go to to siphon also to to revise. Um and um yeah, sometimes change some change can happen. So yeah. Yeah. Exactly. I also forget a lot of things all the time. But you shouldn't. Don't be like
mem. Yeah. All right. Cool. We're done. Thank you all. This was fun. Thank you uh for your involvement this week with us. Yay. Of course. Hearts. Hearts. Yeah. ah something uh like I I will I will send your ex account. Oh yes, feel free to reach out on Twitter a bird app. How do you do bird noises? Maybe I shouldn't try it here on a live session.
What? Bird noises like a like a meow but like birds like how do you That's so funny. No, no, no. Right. That's not a bird. Yeah. Well, thank you for trying. I can do something else. I can Yeah, it's What did you do? Like for Yeah. Oh, you can bark. Yeah, it's a talent. My only talent. No way.
Hidden talent. Wow. We should do like a hidden talent session at the end. All right. Thanks again for everything and uh yeah um let's keep in touch on Telegram if you have any question. Um and revise everyone even myself. Yes. Me too. Guilty. Yeah. Thank you all. Thanks again. Bye bye. Take care.
Bye.