Learn Huff to become an EVM chad by Clement Lakhal | Devcon SEA
Devcon·Tue, Oct 7, 2025, 12:00 AM
Speaker
Become an EVM chad by learning Huff, a low level assembly language for the EVM! On top of being able to write super duper optimized smart-contracts, Huff will teach you how the EVM works under the hood and will let you master high level languages like Solidity or Vyper. Speaker(s): Clement Lakhal Skill level: Intermediate Track: Developer Experience Keywords: Tooling, Languages, Open Source Software, Best Practices, programming Follow us: https://twitter.com/efdevcon, https://twitter.com/ethereum, https://warpcast.com/devcon Learn more about devcon: https://www.devcon.org/ Learn more about ethereum: https://ethereum.org/ Visit the https://archive.devcon.org/ to gain access to the entire library of Devcon talks with the ease of filtering, playlists, personalized suggestions, decentralized access on Swarm, IPFS and more. Devcon is the Ethereum conference for developers, researchers, thinkers, and makers. Devcon SEA was held in Bangkok, Thailand on Nov 12 - Nov 15, 2024. Devcon is organized and presented by the Ethereum Foundation. To find out more, please visit https://ethereum.foundation/
Transcript
All right. Oops. All right. Good afternoon, everyone. I'm super excited to be here with you today.
Uh and I hope that you're as excited as I am. Uh so, my name is uh Clement or Clement with the French accent. Uh and today we are going to talk and actually we are also going to write some Huff. So, uh first I would like to ask you whoever or first like who knows what Huff is? Okay, so that's pretty nice.
And whoever like tried writing some Huff already? Okay, so we have a lot of beginners. That's perfect. Uh one last question like are you like knowledgeable? Do you know how blockchain works?
Are you like a developer? Uh what would be like uh do we have like many beginners in blockchain development here? Oh, like okay. Intermediate maybe? Experts?
Oh, okay. I'm impressed. Okay, now I have a lot of pressure. All right. So, yeah, so now you might be wondering like what the hell is Huff.
Maybe you know a little bit about it. Maybe you already wrote some Huff contracts. Um well, we are going to start with like uh the basics with the definition that you can find on the website. So, basically Huff is a low-level programming language designed for developing highly optimized contract that run on the EVM. So, well, since you guys are experts, you know exactly what this means.
But maybe it would be a bit obscure or esoteric for some people. So, we can have a look like a deeper look. So, when it comes to smart contracts development, you have like many different choices. You can use like the most common ones like Solidity or Viper. They're like the the usual languages that people are going to use, but there's a bit more to it.
You can use for example like inline assembly. So, just like adding some assembly like this like on top of your Solidity code. You can use like Solidity standalone assembly called Yul. You can use Huff. So, we're going going a bit deeper in the iceberg.
And if you're like a crazy person, you can write a mnemonic bytecode directly, but I wouldn't recommend it. So, obviously you guys know this is just like a very simple Solidity smart contract. Very basic. We just have like one value. We can read write this value and then we can read this value.
Pretty high-level. Very simple to understand. We have like the equivalent in Viper. Same thing. Kind of high-level.
Then here we have something a bit more interesting. So, here we're using inline assembly. So, we are trying to double a little bit with the EVM. Pretty straightforward also. Just some different ways to to do things.
This will be the complete um assembly Yul. So, it's like the standalone assembly version. So, it's We have a bit more code, but things are still like a bit simple. Then yeah, if you want to have some fun, you have like the mnemonic bytecode. So, so just like all the instructions with some hexadecimal values.
And this is just like what the compiler will output. You can also write this by hand, but it might take some time. So, now you you might be wondering like why have why should we use have? Because we have many options. They seem to be quite reasonable.
They seem to be quite flexible. We can do like most of these things with them like most like Uniswap is written in Solidity. We have like Curve and Viper. We can do pretty much anything. Well, we have to go back a little bit into history and basically Huff was created at first by the Aztec team.
It was in 2018 and they were working on like a smart contract called bear with me wires trundle. I don't know what this means, but that was the name of the contract and basically just like elliptic curve something similar to Zcash. And they they had they wanted to write this in Solidity. They tried it, but the results were not convincing. They tried to use some assembly, but still it wasn't there.
So, they started to think about making some kind of way to be able to write assembly, but with extra function extra features. And so, this is how they came with the idea of writing Huff of making Huff. So, this is like the I think the first Huff code ever written. So, you can see it's still it looks like a bit what we have now. Some stuff were removed I think like yeah, like template we don't have this anymore, but most of the the things are still there to up to this date.
But when Aztec decided to create Huff, they had like very different intentions that what we have now. And like I think I took this code from the readme actually. So they said like Huff was designed with a complete disregard for semantics, safety, or basic consistency. So any similarities to production code or purely incidental, and Huff should on no account be used by anybody. So yeah, this is more or less what they said about Huff.
They just wanted to build this tool for them, and the goal was not to really to spread it. It was open source, but it was not meant to be like shared. But what happened? So we know that obviously if you hear today, uh like the the story and like the road that that was like taken is quite quite big, and actually Huff evolved a lot since then. Uh one day like some guy decided to write to take the code and write like a new compiler in JavaScript, and some people decided to write then a new compiler in TypeScript, and more people came and they decided to write a brand new compiler in Rust, and then more people came and they said maybe it's time to write like a new compiler in Rust again like from scratch.
So we have like many different people, many different contributors. Uh I just took this picture from GitHub. I think many of them are missing, but this like maybe the main contributors uh that contributed to the core. Uh many other people contributed to other things like writing libraries or like uh making I don't know like writing articles or making presentations to Huff, but this is more or less like uh what all the people that contributed. And this is what I showed you earlier in Solidity or in Viper, and this is like the same code in Huff.
So as you can see, it's not that big. It's it's maybe a bit scary, but we don't have much code actually. It's kind of simple. We are going to go through it in a bit, but first let's answer this question. So like really why the hell should I use Huff?
I think that's an honest question and yeah, let's answer this question. So first I think what's really nice when you're using Huff is that you have access to like all the up codes. It's not the case when you're using inline assembly. Even if you're using like standalone assembly, you cannot choose like all the up codes. You cannot like manipulate the stack for example.
You have like many restrictions. When you are using Huff, you have access to pretty much anything that that you want. That's the the first thing. Also we've been talking about gas costs. So this chart might be it's not very like precise.
It's maybe a bit outdated. I took it 1 year ago I think. Patrick Collins shared it on Twitter. So I just like been reusing it, but it gives you like an idea. Like this is like the we're comparing the cost to like create this contract to deploy a contract.
And here we're just like comparing the cost to read and write like read and write operations. So using Huff, Viper, Solidity, etc. So it's not exactly but it can give you like a rough idea of how we can optimize the code. Obviously, there are some stuff that are in the Solidity and Viper code that we don't have, but yeah, more freedom. You can do whatever you want.
If you want to remove many safety features, you can do it. So you can make your code like more optimized. So some very specific use cases. If you're into MEV, if you want to write bots, if you want to do like very specific smart contract, you can use Huff because it will be like uh uh purely optimized to exactly what you want to do and you can like reduce the gas cost like uh in a interesting way. Uh yeah, you can also do some crazy things like this guy, for example, wrote Uniswap V2 in Huff, which is quite impressive, actually.
Uh I remember some people wanted like to deploy uh DEX uh that was purely written in Huff. I don't know if this ever happened, but that was like a crazy idea. Uh we have this also uh Huffinity, which is like a way to run uh Huff code inside of Solidity by injecting the code. Yeah, it's a bit esoteric, exotic, I don't know. You will call this uh the way you want, but this is like uh at the boundary of uh of the the what what we can do and maybe it's not a good idea to do this, either.
But uh I think like the best uh use case for uh Huff, basically, is just to teach you how the EVM works. So, you can become the EVM Chad. Um yeah, because what we have been seeing is that uh since Huff has been created or revived, we can say it this way, many people like me got interested into Huff and we can learn a lot about the EVM and then we can get more familiar with it and just become a better developer. So, when you will be writing Solidity code, you know exactly like what the code is doing. Uh you can maybe write some optimizations in inline assembly or if you're debugging something.
So, it will give you like a better understanding of like how the EVM works, how under the hood everything is happening. And yeah, like today, uh I mean, it's been a while already, but I mean like nowadays, uh there are many tools like for example, if you want to write some Huff, you can use like Foundry to test your contracts. So, it's it's extremely simple. There's a template for that. And then, there are also like libraries like Huffmate.
So, if you want to write something then I don't know like an ERC-20, there are already like a template that was made. But, I think like the best use case for this library is to just go through all the contracts and try to understand how they work. I think it's like maybe has like a all the same contract as Soulmate. Maybe, I'm not sure, but many stuff like ownable, like many create three libraries, stuff like that. So, it's very impressive also.
So, yeah, I think now it's time I made like a small introduction. So, I think now it's time to maybe start going deeper into Huff. So, I think we're going to do this in two parts actually. First, I'm just going to go through like all the features that we have in Rust. So, you guys can get like a more like a better understanding of what we can do and how we can do it.
And then, we'll get to write some actual code. So, yeah, as I said, basically like Huff is like some kind of assembly language with many convenient features. And yeah, first I'm just going to go through like how the EVM works. I'm sure like all of you know, but maybe there's like one two people that are not very familiar with it. So, I I just want to be sure that we're all on the same page.
So, this is a stack. This is where most of the manipulations are handled. Like if you want to store values, if you want to compute stuff like everything will be happening into the stack. So, the way it works is very simple. You have here like a pile.
You're just like stacking values from like the top the bottom to the to the top. So, you're just like adding new values on top. If you want to remove a value, you will pop the last value that you just added. And what is going to happen is that let's say we have like A, B, C, and D. And then you want to multiply something.
So, you're going to use the multiply up code. Then what is going to happen is that the EVM is just going to take like the two latest values and it will multiply them and it's going to put them back into the the stack. Uh yeah, this is just like another representation of the stack. So, still the same thing. Um just be aware we have like plenty of space like 1,024 values.
Uh the thing is that we can only get like the three uh two first values because we have only like up codes. For now, we only have up codes to get value up to the 30 second value. This will change maybe with the EOF, but for now this is the way things works. Um and this is why we have like a stack too deep in Solidity also. Um then we have the memory which is like another area to save some values.
The memory is very simple. You have like an address and a value. Addresses and values they are using like 32 bytes. So, basically you can just store whatever you want uh wherever you want. You just have to follow the this pattern.
Uh the storage is following the same um pattern and we also have the transient storage which is also the more or less the the same thing. Uh and this is the call data. So, call data when we are referring to to it. It's just like a value that someone is passing to your contract when they're calling them. So, this is a swap on Uniswap V2.
Uh, obviously, if you don't know like um you might not know what are these numbers, but basically in your contract you're supposed to So, don't worry too much about that. But, yeah, basically we can select the difference bytes. It's just the signature of the the function. And then all the other values like after all the zeros, these are just like uh values like amounts for example that are passed around or maybe addresses. Um, yeah, just like a very cool website if you want to be or get more familiar with like the how the EVM works, uh, you can go on evm.
codes. Uh, there are many different sections. The first one is like opcodes, which is this is what I showed you earlier, just like a list of all the opcodes. It's just explaining exactly how that how they work. It's like a very very convenient.
Uh, and then you have the playground. So, you can write some Solidity code, uh, Yul code, I think also like uh mnemonic bytecode. And then you can just hit the the run button and you can see like what's happening step by step into the memory, the stack, the storage, the transient storage, the return values. So, it's it's extremely convenient and it's a great resource just to to use like to to learn how the EVM works. There's like a Huff um fork for this, but might not be updated.
So, I'm not going to to show it here. And yeah, I guess it's time to just go through like all the the things we have in Huff. So, first like in Huff you can like have um Um, you we have the interface definition, which is something very similar to what we have in Solidity or Viper or whatever. You can just like define functions, you can define events, you can define uh errors also. It's not there, but you can also do it.
Um, and then you just have to pass like some parameters. So, this would be useful in two cases, either to define like a function, so people can call your smart contract, or if you want to call like another contract let's say like an ERC-20, then you can define the transfer function, and then you will use this definition later on to call the contract. Uh, we do have some built-in functions in Huff. So, we have the function signature, the event hash, and the error function. Uh, these three functions works uh more or less the same way, and it's related to the interface definition.
Once you define, let's say for example, approve, and you want to call approve, then you will be able to use like function sig, and you put just approve um inside of the parentheses, and it will give you the signature of the function, so you can call it. The same thing for the event, if you want to emit an event, or if you want to revert, then you can use that for uh the error and get the the selector. We have also uh right pad, which is just like shifting a value from the left to to the right. And then we have like table start and table size. Uh, basically, it's like a way to write uh switch statements uh in Huff.
We'll get to that uh in a bit, though. And yeah, this is what I showed you like uh at the top. We're just defining like two errors, uh panic error and error, like uh that's very original. Uh, but yeah, then later on we want to revert, and then what we are going to do we can just do like uh {underscore}{underscore} error, and then we just put the um name of the error you want to use, and then this will add the selector inside of our code, and then we can just like uh in this case we are reverting with some parameters, so we can just like store these parameters inside of the memory. Then we just have to call the revert function.
So, another thing that we can define actually um constants. So, I think it's pretty straightforward. You have a number, you can just define like uh number, so it's like 0x uh 420. This is a an hexadecimal value, but you can also define um numbers uh using like decimal values. Most of the people you uh do it this way.
And then whenever you want to use the your constant, then you just have to put the name uh inside of some brackets, and then we'll just like uh input the the right value. Uh then we have jump labels. So, jump labels are defined within a macro or a function. We will see what they are a bit later, but basically it's like it's very simple. You have just like a piece of code like for example uh success here.
Uh success is just defined by this um instructions. So, like uh we we store something, and then we just return. And so, what is going to happen? If you look at the top, I think there's like a point to Yeah, if if you look here, basically we are doing something here, and then we say, "Okay, we want to jump to the success." So, we just have to call the label success, and we jump to it, and this piece of code will be executed.
So, it's quite straightforward also. You can also do it with jump E. So, you can add like uh a condition to to this jump. And then we have functions. So, functions can have like arguments that you can pass here.
And yeah, there is one weird thing here. So, takes and returns. So, this is something that can help you know what the function is expecting from the stack and what the function will left into the stack. So, basically what is going to happen is that this function is expecting like three values in the stack. And after its execution, it will left it will leave, sorry, like one value in into the stack.
So, as far as I know, this is not enforced by the compiler, but it's more like a way for you to just like know more or less what you should have, how you can manage the the stack. And yeah, so basically functions, so we have functions and macros. And like the big differences is that functions they are copied only once. The compiler is going to take the code of your function and it's just going to put it at the end of all the the bytecode. And whenever you're going to call a function, then in the execution of your code, it's going to jump to the where the function is.
And when the function has been executed, it's going to jump back and keep on with the execution of your code. Which is different from macros. In the case of macros, what is going to happen every time you're going to invoke this macro, then the compiler is going to copy the all code and directly put it in your bytecode. What was compiled. So, this means that if you're using like macros, then the size of your smart contract might be a bit larger.
But it might be cheaper gas wise because you will be like avoiding like jumping around back and forth. And also by the way, yeah, so we don't have it here, but basically macros they accept like parameters and you have also the text and returns indications. So we have like two important macros that you need to know. We have the constructor. It works the same way as Solidity actually.
So basically if you want to execute some code when you're deploying your contract, then you just have to put it into the constructor. And we have the main macro. The main macro is well quite simple. This is like the entry point of your smart contract. So whenever someone is going to call your smart contract, the main macro will be executed.
So this is where you want to do like the function dispatching or things like that. But we're going to see that in a in a minute. We have jump table. So it's pretty small and a bit long. So yeah, it's just a way to do like switch statements in Huff.
So maybe we can see that a bit later. So yeah, let's go. So I think it's time now to write some actual code. So yeah, we need I hope like you guys all have a laptop. Otherwise it's going to be a bit boring for you.
I'm sorry. So we are going to write some code. We are going to use the template that is using Foundry. So if you don't have Foundry, you can install it using these commands. I'll just give you like a few minutes to start installing stuff.
So, if you already have Foundry, you can install directly have like this is like the version manager I would say. So, you you can run this. Maybe I should have put this two into the same slide. I'm sorry. You just tell me if you guys all have the first step done, then we can move forward.
If you have any questions about half or about how to install things, you can just ask me now, I think. Yeah. Oh, Which version do you have? package Okay, is this like the Yeah, half up should be like the Okay, check your check your Wi-Fi. Cuz I know like the Wi-Fi is a bit long now.
It's good. Oh, Try again, maybe. warning That's that's pretty annoying. I'm I'm sorry. I just I don't I'm not sure how to help you here.
Yeah. Uh let's see. What is the repo you you opened? Oh. Yeah, it's a bit weird.
We're going to use Foundry, so it's just going to like uh do everything, but I think like the Yeah, yeah, it should be working. Try Yeah, try just like uh have uh C {dash} capital V, and then just to see if Yeah, I mean, it's saying it's saying compiling, so yeah. Uh it's you have the right version. Yeah, yeah. I think if you want to output something, there is like a command if you check if you try help, it will tell you, yeah.
There is something like an output, yeah, bytecode, stuff like that. Yeah, it's a bit it's a bit weird. No worries. All right, so if you guys have Foundry, we can move forward. Uh then you just need to install Huff.
And once you've done this, uh you can install Uh so, this is installing the package manager not the package, sorry, the version manager. Then you can install the latest version, and this should be working, so you should get like Huff uh 0.3.2, something like that, and Forge whatever, like it should should be working. Should be giving you like some outputs.
Yep. This one? Let me see if I can give you like all the commands. That would be easier. All right, it's not loading.
All good? Yeah. Do you have Now you have Linux? Okay. Oh, it's still installing.
Oh, Yeah, I hope it's not going to take too much time. Yeah, worst-case scenario, like I I still have some slides, so I can show you guys, but it would be better if we can just like code along. Yeah, all good? Nice. Yeah, installing, downloading.
Okay. All good over here? Nice. Uh it's half C. Nice.
Perfect. All good? All right, installing. That's nice. All right, I'm just going to give you a few more minutes because I see many people still downloading.
It takes a few minutes, I think, to install everything. Uh did you Are you you building? Okay. Oh, perfect. Nice.
All good. All good here? Yeah? Okay. Do you guys need help or you good?
Good? Yeah, thank you. Okay. Yeah, you have like both versions. Everything is working?
Uh perfect. All right. Yeah, let's move forward. Uh where's the clicker? Yeah, we're just going to be writing like two very simple contracts today.
I don't know how much time it will take. Like we have two hours, but yeah, since you guys are experts, I'm joking, but like I feel like it will be pretty straightforward. So, maybe it will not take like the whole the whole time. Uh yeah, if you do have up, you do have C uh {dash} capital V forge {dash} capital V, you have If you have everything working here, then uh what you can do, you can clone uh this repo. Just like a very basic template uh I've made uh using the actual foundry template.
So, you should be able to clone this. I just hope it's public. So, just let me know if it works. And when you have this, uh there will be like one um extension. If you're in VS Code, there will be one extension as this that is suggested.
Uh it's called like Huff Language by Huff Language. Uh and it will just give you like a syntax like uh colors, stuff like that. There is also debugger, but we're not going to use that today. So, yeah, just let me know if like uh Okay, perfect. Good.
I'm relieved. I see. Uh, it should be So, do you have VS code? If you open the repo in VS code, it should like pop up the suggested extension. Although otherwise, it's called like half language, I think.
Got it? Perfect. Yeah, it would be better to be using some having some colors otherwise, it's going to be a bit harder to see what we're doing. Uh, yeah, I just give you a few minutes because I think the slide just after this Yeah, like after this, we're just going to be cooking. So, I just want to be sure that everyone can follow.
Did it work? Yeah? It's the right extension. Ah, yes. I'm trying to install this extension from that.
The bugger to VS code. Uh, or you can just explain this. Nice, but I'm clean I'm right. That's perfect. Okay, good.
Yeah, it looks like we are all set. So, what we are going to do we're going to be writing our first half contract. So, I think there might be a source uh folder if maybe it's not there anymore. I don't know. But, you can just make like a CR SRC folder then you can write the first uh like create the first file you can name it the way you want compute.
half or whatever you want and then we are going to be writing some code. So, this is the first contract we are going to be writing today. It's uh extremely complicated. You will see. This contract is just going to take two values and multiply uh yeah, no, not multiply actually.
Add these values together and then just going to return them. So, as you can see it's extremely hard to understand. Um yeah, so let's just like follow along. If you guys have your setup already, you can code at the at the same time. So, the first thing we want to do with that we are just going to define a function.
So, here as you can see uh this is what we're doing here. Let's call it I don't like compute. You can call it add or whatever. Just it doesn't really matter. Um and so this function is going to accept two parameters.
So, we need like one you went 256 and why not another you went 256 and then it's going to return well, something very original one you went 256. So, this is just like the function that we define and this definition will be used by us inside of our health contract, but it will also be used by the people that want to interact with our contract. So, then we have this which is a macro here that we are calling compute. Um so, we can define this macro here just a way to organize our code. It will be also Another way would be just to shove everything into the main macro, but that's No, we we are like uh uh educated people, so we are not going to to do that.
Uh I'm going to go through what's in there in a second, but first I want to talk about the main macro which is just here. So, as I said earlier, the main macro is the first thing that is going to be uh called when someone is calling your contract. This is like the the the entry. So, in our case, uh yeah, it's pretty simple. So, let's go let's go through it.
So, okay, you guys can So, maybe you're writing at the same time, so I will slow down. I'm sorry. So, yeah, first I think the the easiest thing is just to write the first uh function definition on top and then you can go directly to this. Don't write this now. We we'll do it just after.
Yes. Yeah. Uh here? Oh. Yes.
Yes. So, why are we returning nothing here? We are not like leaving anything in the stack, it's because we are returning here and this return is actually uh the end of the call. So, we are when we are returning something in half, we are actually like returning uh values from the call. So, it's like the end of the call.
It's It's I know it's a bit uh the the names may be a bit confusing, right? Yeah, because we have returns with which is not actually returning, but just leaving stuff in the stack. So, that's true, that's uh it can be a bit confusing. So, yeah, I'll just uh Are you guys ready or not to go through the the main macro? All right.
Okay, let's go. So, now we are going to do what we are calling like function dispatching. Uh we have like a very basic implementation, but it works the exact same way, for example, in um Solidity or Viper. There are many different ways to do this, but this is like the most common way. So, basically uh what is going to happen is that someone is going to call our smart contract, they will send us some call data, and we just want to know, okay, what do they want to do?
Like, what is going to happen? So, what we are going to do is very simple. We say we want to load the call data, so all the values that were given to us, but we want to load it uh starting from like the the first the first byte. We want to load it from the start. And then I maybe you know this or maybe you don't know, but basically like uh function signatures, they only have like four bytes.
So, how does it work when someone is calling a contract in Solidity or like uh in the EVM like the the standards that when you're calling a smart contract, the first bytes the first the four first bytes are the function selector. So what you are going to do with that when you receive the call data you are like okay, I want to know what which function we should call inside of our contract. So I'm going to check in the call data what the guy wanted me to to talk wanted to to call. So we are going to load the old call data here and this like magic number the value is like 20 24 bits. So it's like 28 bytes and so what is going to happen here we put in the stack like the the whole like the whole call data.
So we have everything and then we say we want to move to the right like all the call data. So we are going to move everything to the right but we are moving to 28 bytes. So we are going to leave a value which is only well you can do like 32 bytes minus 28 and you have four bytes. So this is like the the function selector. And so yeah, we have a function selector.
So we know which function the sender wants to call but now we need to check okay, so do we have this function? Maybe we don't have it. Maybe it's a mistake. So what is going to happen here we are going to do exactly like the function dispatching. So we are going to load here our function signature.
So this is what we have compute it's here. This is what we define and this is what we are expecting. And then we're draw going to do like equals. So equal here is going to check if what we loaded here, what we sliced from the call data, the function signature function selector we have, is equal to this one, the the function signature that we are expecting. And then we say, "Okay, so if it's equal, then we'll have a zero here."
Uh no, sorry. We have a one. If it's not equal, we have a zero. And then we are just going to call the jump if up code. And the jump if up up code is very simple.
If this is zero, then we are just going to continue. If this is one, we are going to jump to here, compute, the jump label I showed you. I explained to you this earlier. So maybe this is a bit confusing. Just let me know if we need to slow down.
Okay, you have question. Go ahead. On the function signature what is it doing exactly there? Uh On the on the function signature, how is that Could you explain dive deeper into that? Yeah, sure.
So basically, uh this is uh the same thing as Solidity when you have like encoding something or if you define a function in Solidity, you can get like the signature, you can get like the four bytes. And this is the same thing here. Uh we define this function here. Like this is like our function. Oh, I see.
So it's actually computing the signature function signature from the compute. It's It's computing the hash. So the hash of this and then it's just going to slice and only get the four first bytes. Okay. Could you go back a little bit on the call data piece?
So is it just leaving on the stack the call the four bytes of the function signature? So basically here, we are going to It's a bit of because, like, you know, you have to add the value on the stack, and then you call the instruction. So, it's a bit hard to explain because I need to explain, like, uh, back and forth what the values are. But, basically, you're like, "I want to from the start, I want to load the call data." So, you will be loading the call data from the the first byte, from the byte zero.
Uh, but you are going, like, to load 32 bytes. What is going to happen is that this function is going to take, like, a slice of 32 bytes and put it into the stack. So, you will have, uh, so, 4 bytes for, uh, the function, uh, signature, but then you will have 28 bytes, which will be like, uh, The parameters. Yeah, you you will be In our case, it won't be nonsense, but it will be this, uh, the first parameter, but it even it won't even be like the whole parameter because this is like 32 bytes. So, yeah, maybe yeah, I should have put like a graph or something.
It's it's hard to explain this, uh, just like this, but Yeah, it would be helpful if you had, like, the stack on this on the right-hand side, too. I'll I'll see if I I can do something. Uh, yeah, I'll see if I can do something actually after. But, uh, yeah, basically, the the idea is that you're loading here 32 bytes of call data starting at the position zero, but in this case, we only want the first 4 bytes. So, we say, "Okay, let's just move to the right uh, this element in the stack, and we want to move it to 28 bytes."
So, we move it like this, and so, we are left with 4 bytes, which is the function signature. So, on the stack, all all that's left from the call data is a four the first four bytes, which is the function signature. Exactly. Got it. And after, we just check, "Okay, is this like a valid function signature because someone can just be like spamming our contract.
So, we need to to do like a proper check which function do they want to call. So, we are going Sorry. We are going to use to sorry, we're going to load our own function signature what we define here into the stack. So, basically the stack will will be their function signature our function signature on top. And then we'll just do like equal and both values will be removed and equal will just leave a zero if they are not equal if they are not like the same and it will put a one if like both signatures are the same.
I just want to Yeah, there is like that here duplicate one. This is not needed here so I'm not going to talk about it. We'll see that after but this is not needed here so don't worry about it. And yeah, so we are are checking here and yeah, like the the final thing to do is just to jump accordingly if this function signature is valid if we have something that we are expecting then we jump here to compute and in our case we decided to make things the proper way so we define like a macro for compute. The other solution would be just to shove all the code here but it's just cleaner to to do it here.
And yeah, if they don't have like the a valid function signature, we're just going to revert. We don't care. They they don't they're not like uh asking for the right function so we are not like reverting with any extra data. We're just returning zero value just reverting the transaction, but we could have been like reverting and say like anything you want like wrong function signature or whatever. Um All right, do you have any questions?
Yes, I'll give you the mic. I see by the looks of the function and the main functions you have a revert and return. It's all recursive inside the EVM or is just for showing they have a revert or return function. This are up codes. Yeah, I refer this uh the EVM is recursive when the when the codes.
Oh, do you mean like is this going like to fail the whole transaction or continue the transaction the execution until you put the return on revert or revert. Yeah, if you revert here, I mean it's the same thing in Solidity. You can revert here, but then the code can continue. It's the same infinitely until the gas is Oh, no, sorry. Okay, I understood it not the right way.
This is the end of the the transaction, but it will continue if there are like more things after other up codes to execute, but if you just if you reach like the end like in this case we are reverting, but it depends on like uh well, how you're writing your contract and who is calling your contract because like if you I don't know like uh I mean it it it it it depends. I don't know exactly how to answer this, but yeah, like basically it will consume gas, but if you reach the end of the goal, then it will just stop consuming gas. Because it's only consuming gas when it's like executing operations, but if there is nothing left to execute, then the transaction will just stop. Okay, so if I remove the return or or the revert, it just stops completely. Uh if you do that, uh if you remove the return here, I'm not sure what it will do actually.
That's a good question. I think it will stop because uh this is here actually in like the the code. This will be compiled at the end of our contract. And then if you do this, then after the contract has ended, so I think it will just stop. But otherwise, you can if you forgot something, you can make a loop.
Uh if you put like here something, then it will jump here and go here and jump here. Like it will be a loop. It will consume all the gas and just revert with out of gas actually. Okay, perfect. Thank you.
Uh question about the 0x00 call data load. Uh yes. So, that sounds a bit heavy. Is that the most efficient way of getting the extracting the the selector? Mhm.
Okay. Cool. Yeah, because you can when you are using like call data load, you can only load like 32 bytes. You're loading like a whole piece of information into the stack. Then you have to move forward to um to get uh the the the actual function selector.
There is another way actually, and I think you can load like a single byte from the call data, but that that is not standard. So, you can do it, but it's not like the standard way. So, you you could be like loading I don't like the first uh you say, "Okay, this is like one, and if this is one, we compute, or we we go to something that will add. If this is two, then we can go to something that will do minus, uh subtract, things like that." But And this down way is like four four bytes.
Um yes, so we can continue. So, basically once you uh yeah, once you are going to compare here and then you have like as I said like two different uh cases, two different scenarios. Either you can revert, so we are just reverting like the the hard way. Or we we might be going to our macro here. And the macro is kind of simple.
So, we know that we have like two Uints uh 256 that we need to have into the stack because we want to add them together and return the sum of these two values. So, we are going to do the exact same thing as we did here. Um I mean, call the same function. And so, in this case we know that the four first bytes or the function uh signature, so we are going to ignore them and we say, "Okay, put into the stack." So, call data load, but put into the stack the call data starting at the bytes uh four.
So, ignore the first four bytes and then put uh the call data. So, this will take 32 bytes of call data and put it into the stack. Then, we just have to compute and we say, "Okay, we already loaded four bytes for the function signature. We already loaded 32 bytes for uh the first parameter, the first Uint 256." Then, it looks like it could be 36 bytes that we already loaded.
So, here's the value. 36. So, we are going to say, "Okay, you have to load into the stack uh the next value, which is located uh after 36 bytes. Um So, am I clear? I know this is a bit a bit heavy.
If you have any question, feel free to ask them. I don't want to lose any anyone, or maybe I already lost some of you, I don't know. So, uh back to the first a couple of lines inside main. Yeah, yeah, here. So, I I get that we're putting uh the the function signature on the stack.
Yep. And then So, at the end of the second line, is that uh if it's equal then compute jump or it or does it say if it's equal compute? I I guess I'm I'm getting confused a little bit on the on the naming conventions and like you've got, you know, the you're defining function compute and then you also have a label compute and so Yeah, don't worry. I'll explain. So, basically, yeah, okay, I I I understand what you mean.
Okay. So, yeah, the the naming was maybe a a bit wrong, but basically, here compute, we have our function. And this is only related to to this. This and this are related. That's it.
And then this compute is the jump label that we are defining here. So, these two are related, but that that that's it. There are no other relationship. Yeah. Um and so Okay, so sorry, one final thing on that.
So, where it's doing the the equals, uh does it know automatically to just pick the first one off the stack and then compare it to function and signature compute? So, because here we loaded like the function signature from the call data, so we have like at the top of the stack, we have one function signature, the one that the sender gave us. And then here, we are loading, we are putting into the stack our own function signature. So, when we are calling equal, it will say, "Okay, I need two elements from the stack, two values from the stack." And we'll just take like the two first values, which are the values we need.
And then, so we have into the stack like either one or zero, and we say, "Okay, we might want to go to the compute jump label, which is here." And then we say, "Okay, go for it, but only if we have a one. If you have a zero, then keep on reading the next code." So, we will just keep on reading the next code, which is just like reverting. And revert just say, "Okay, I want to revert.
Do you want to return some values from the memory?" But we say, "Yeah, return zero like zero value from the memory." That that's it. The return here is very very simple. Uh more questions?
Yes. Uh yeah, basically, yeah. Yeah. And so, this is like the most I think convenient thing when you are like uh writing stuff like this because if you want to try to write like mnemonic bytecode, basically, you can you you can write all of this without Huff, but uh instead of having like compute here and here, instead of having something that you can read, you will have to put like a value, and this value will be like a location inside of your code. So, you will you will say for example for example, sorry, "I want to go to like the the in my code to the location I don't like 148."
But if you add more code here, then you have to change this value, you know? So, this is like this is just for us to be able to do this like a very in a convenient way. Um Yeah, so we are jumping to compute, and as I told you, it's just like a macro, so it's very very simple. In this case, we are loading our two values here. We know that we are we have to avoid the first uh 4 bytes, so this is like the next 32 bytes.
This is the next 32 bytes after the first uh 36 bytes. And what is going to happen is that we have value A and value B inside of the stack. So, we just have to call add, and add is exactly what I showed you uh earlier. So, it it's just like uh it will with multiply, it's just taking like two values from the stack. It will add them together, and boom, they're all put back into the stack.
And what is going to happen here is that it's pretty simple, you'll see. We have one value into the stack, and well, we now we want to return it, because we we did all of this, but now we need to return our value. So, return here is very simple. Uh you can only return stuff from the memory. So, we have to put our uh results the the sum that we just computed into the memory.
It's very simple. We're going to use the MSTORE op code, and MSTORE takes one value here and one location inside of the memory, and then we just call MSTORE. So, what we've done here is that we are putting here um at the location zero the value of add. So, the value of add can be anything up to 32 uh bytes, obviously, but it can be anything. And yeah, we have like value in the memory.
Yes. So, why isn't it there a cost Uh wait for the mic. Sorry. Isn't there a cost for putting that value in memory? I mean, it's not like Yeah, obviously.
Yeah. But, why not why not return it from the stack? Because it's not possible. It's not possible. Yeah, the way uh you can see like I'll show you.
Okay, let me just go back a little bit. Um We are Okay, we are here. So, basically you can you can see like we don't have the return function here, obviously. Uh okay, but if you go on this website, it's evm.codes.
And you will see like all the opcodes are explained here, and you will see like stack input. So, basically, this is like when I was talking about the stack, this is like what is expected, and this is what will be left into the stack. So, in our case, we are taking like A and B, and we are adding them. So, we go from two elements uh from two elements to one element into the stack. And you can see like there is a description here.
And if you go down, let me share my screen, actually, cuz this is like a interesting question. Can you uh Yay. All right. All right, let me see. EVM.
All right. So, if you go down here, I'm not going to take like too much time on this, but basically Yeah, let's do a research. MSTORE here. You can see like um This is explaining how MSTORE works. And if you go to return, you will see like uh uh the explanation it will it will just tell you, "Okay, stack input."
Uh so, the definition is like the offset and the size. So, basically this means that uh we need to tell uh where we want to load the value from. So, it obviously inside of the memory and the size. That's uh that that's it. So, if you Can you go back to the Can you go back to the presentation?
Thank you. Perfect. Uh yeah, so it's just how it works. We don't have a choice in this case. But, I just wanted to show you the the website because it's going to explain to you exactly like all the like all the opcodes uh work actually.
It's pretty pretty interesting. And even if you are not doing like going to do like some crazy things with have if you just use like EVM that code and this uh um and have, then you can just learn and have some fun understanding how things work. Which is still quite uh quite interesting. Oops, I went way too far. Uh yeah, no, wait.
This is the second one. Uh this is the test. That's the one. Uh yeah, that's the right one. So, yeah, and then we have uh yeah, as I just just said like return.
So, return is expecting two values. So, we have the first value, which is the size uh what we want to return. So, in our case it's 32 bytes. So, it's like 0x20 in hexadecimal. Uh you will see like many have code uh written like all the values are in hexadecimal.
I guess because it's cooler, I don't know, but it's like a more by convention. So, you know that you want to return a you went 256. So, you have to return 32 bytes. And this is the location in memory. As you can see, we just stored it here at the zero, like like my beans.
And so, we can just like call return. And and that's it. We have our whole contract. So, if you guys have the code ready, you can try writing a test actually. So, this is how tests are working with foundry and have.
So, we have something called like have deployer and this is pretty convenient because it's going to take your contract, compile it for you, and then you can just deploy it. So, if you're familiar with foundry, you will see it's the exact same experience as writing regular tests. Very easy, very simple, very convenient. The only small difference, I think there might be a better way to do this, but we'll do it like this today. We just need to redefine our interface here.
So, we say this is our contract compute and then we just like copy-paste what we defined here. We just need to put it again here in the interface. I think there's a better way to do it, but I'm not going to to show it today because yeah, we might be running out of time. So, yeah, this is quite straightforward. You make like a a new test file, then you just have to put like compute test, is test, whatever.
Just like a storage value for your your contract. And then what is going to happen is that Uh, you just have to cast it. So, we define the interface here. So, you just cast it. Or you can keep the address as you want.
And then you just going to use the half deployer and you do like that. Sorry, you do like that. Deploy and you put the name of your contract. I think the name of the contract the contract is actually the name of the file. Um, yeah.
So, if you do this, the contract will be deployed and then you can write your first test. So, in this case we're just like expecting random values that will be first. And yeah, we say okay. So, the contract should return C and we we can just check that C is the sum of A and B. I'll give you a few seconds.
Do you have any questions or anything like that you are struggling with? Like I I know this is a lot of a lot of things all at once. Uh, it can be a bit tedious to set up everything. So, if something is not working, we still have like less than 1 hour, but we can take some time to to fix some issues. Can you just explain the math a little bit?
Uh, obviously, um, you've got unchecked there. So, all of these U and 256s can wrap. And yeah, just just explain the bounds on the is it just Yes, so I'm I'm just doing here, uh, unchecked because, uh, if we go here in our I'll go back to the next slide. I'm sorry for this copying the code. But if you go here like add we have no overflow check.
So if we are just doing like a third like the sum here and we have we don't have unchecked then solidity will do like overflow check and then the code will revert or we won't have the same result as our half code. But yeah, that's an interesting question because here in solidity now we have the overflow check, but we don't have it in in half. So maybe like something that you guys can do is a way to prevent the half contract from the sum from overflowing. That could be an interesting exercise. I think there's already a like a small library in half mate that can always you to do this, but it could be quite simple to to code actually.
Hey, sorry. One more question. Um, you mentioned that Oh, here. Bit of topic, but you mentioned that advantage of using half is you have complete access to all the up codes. Yes.
What is one use case that you've found where you can particularly exploit that to achieve something that you haven't been able to do in another language? Uh, it's so personally I haven't been like doing I haven't been coding half for production things. I was more as I said like in the beginning. I really wanted to learn how the EVM was working and actually just like writing some half was like the best way because writing resources a bit tedious. But otherwise like I've seen many people doing like um uh yeah yeah MEV bots, bots or things like that they're using have.
And yeah, I mean like you have more you have access to many things. And what what is interesting also is that you're not writing Solidity code, you're not writing like uh or even Viper. Um so you can do like as we we saw earlier like the function dispatching. If you are just writing your own bot for your own purpose, you don't care about that. So you can remove like uh a lot of the safety features from Solidity because you if you know exactly what you want to do, you can achieve it this way.
But uh yeah, like some some stuff also in uh like main difference is also you have access to more upcodes. I don't have like an exact example here, but I would say yeah, like it there are so many uh other cases, but for this one specifically, I'm sure we can find it, but I don't have it in mind. Yeah. Yeah. Yeah.
Could be a example, yeah. All right. So yep. Okay, let me see. Uh oh, you put like uh you went eight.
Yeah, just put like uh 256. Yeah. Yes. Yeah, I think yeah, if you have like failed, I think there is one step that we haven't been doing yet and it's just installing uh the packages. So, if you have this, obviously if you have the first contract and then you have this, then you can try uh just be sure to have everything installed so you can just run like forge install uh because now you might not have the have deployer module below or whatever it's called.
Uh and then if you run like forge test, it should be working. I hope so. I tried it in my machine. Same thing like uh here. You went eight.
Uh the result should just uh use like uh 256. Yeah. Let's see if it works. I hope you it will work. All right.
Let me know if it's working. Yeah? The test is passing? Hell yeah. Yeah.
You have the the mic. Uh is there a way to uh write the half codes like in line in Solidity? Yeah, actually there is one. I I This is something I showed earlier. Uh like there is something called the have hafiditi.
Uh I guess it's called this way. But this is very very experimental and like this is leading to many uh where is this? It's here. Yeah, so it works, but yeah, I don't think this should ever be used in production because like the way it works that it just injecting it's compiling your code, it's injecting your code. So I I think it I mean If you So if you really want to use half for something in production, I guess like something interesting would be just to have like a deploy maybe a library or contract.
So I don't like some kind of precompile just make a contract that is computing something. You deploy it and then you can call from Solidity. You can call this contract. But yeah, like this is highly experimental. It hasn't been updated in a year.
So I think it was more made for for fun that than something else. So are are all the tests passing? No? You forgot the unchecked. Sorry, I just I just saw this.
Yeah, if you because So basically you had the exact issue that I was explaining. So like here if you don't put the uncheck, then the test will revert because adding these values will cause an overflow and we still have like overflow checks in in the test. Any issues? Okay. All right.
So we covered the first contract. Yeah, I have another one if you guys are are interested in. We still have 45 minutes. If you want to suffer a little bit more. Failing tests, okay, let's see.
Failing tests? Okay, let's see. Uh Okay, did you put the unchecked? Yeah. Oh, I mean Yeah, yeah, yeah.
That's uh Okay, let me Okay, the code I think the half code looks great. Yeah, yeah, it it doesn't matter. Uh yeah, that's unfortunate. Okay, if So, if the tests uh are failing, uh you can still check uh if you open on uh You can open this uh like URL in your browser. And you can check or you can change the branch directly.
I've made another branch called finish. And you should have the first test. Uh this one, I mean, the contract and the test. I hope they will work. But, if they don't work, maybe there's a bug in my code.
I don't know. So, if you can find it, then that would be amazing. But, maybe I made a mistake somewhere. Yeah. So, it's passing.
So, what what I'm thinking now, maybe I don't know, maybe some values. Yeah. Found it? That's That's pretty funny. Do you have Yes.
Yeah, when you are returning something. Yeah. Yeah. You cannot return from the stack. You need to put it to memory.
This is the way return works. Return can only read from the memory. Where is your Uh try to rename this to source SRC. Yeah, here. If you put contracts, I think it won't work.
It's just naming conventions. Try try this and let me know. Uh go compute is the name of your file. Yeah. Yeah, you yeah.
Yeah, actually I think I know Maybe it works. Okay, perfect. Okay, let's see. What's the issue now? Uh country example, that's that's funny.
Okay, go back to the file. Yeah, uh Let me see. Yeah, yeah, no, the the problem is in the code now. Let me see. Call data, are you loading the right code?
Oh, you forgot add uh after call data. Uh no, no, before before. Uh yeah, yeah. Nice. All right, any any issues?
Still failing? Oh, gosh. Uh yeah, what what was the issue? Uh no compilation. Try to do like uh uh Uh yeah, try to run do like force test {dash} {dash} force.
Oh, Oh, It's It's Okay, one second. Let me just like a certain remove a certain file. What? Okay, it's talking about in here and then I That's That's weird. Why is he running a test if you don't have a a test?
Oh, it's It says reverts. Yeah, some like I think it's reverting here and now. Oh. Yeah, I'm I'm I'm not sure exactly. Check on the other branch.
Uh you can switch the branch. Go to the finish branch if you want. Uh yeah, if it doesn't work after I can I can look into. But I I think we're we're going to we're going to move forward because feel like you guys have the code working. Uh so, yeah, we still have like 40 minutes.
So, maybe we can go through another contract. Uh Yes, so this one is more less the same thing. Now, it's it's not exactly the same thing, but we're going to cover one extra uh one extra op code. So, now in this case, what we want to do is that we You will see it's very simple. We just want to be able to get a value from the sender and store this value.
And if the sender wants to read this value, then we're going just going to return it. So, once again, very very basic contract, but this will allow us to uh cover a few different things. So, in this case well, we're going to start by the interface definition once again. So, we're going to define two values. The first value is just uh two functions, sorry.
And the first function is just set value. So, in this case, we want value into 56, which is very original. And then we're just going to make like another function called get value. And in this case, we don't want to get we don't want to set something, but we want to return something. And then we are going to cover something else.
So, we are going to make a new constant called uh value location. And so, we are going to use this, which is like a yeah, some kind of built-in function that we haven't seen yet called free storage pointer. And basically, what this function does, uh it's very simple. It's just going to give you uh the location a location where uh the storage is free. So, in this case, if we call it now, it will be zero because the first uh location that is free is located at index zero, very simple.
If you call it again, it will be one because we have this value already taking the first slot, so the slot zero. And then after, we can take the slot zero, one, two, etc. Any questions now? All right. Um and then, we are going to go directly to the main entry point.
So, this is going to be almost the same code as we as we did actually. So, we are loading the code data from the start. We are shifting to the right uh 28 bytes. And what is going to happen here is that uh I told you earlier that we don't care about the uh duplicate one, the dup one, but in this case, we need it because what is going to happen here is that here, we have the function signature that we received from the sender in the stack. And we want to keep it for later.
So, we are going to duplicate it. So, what is going to happen is that we will have two times the function signature we received from the sender. Then, we're just going to be doing exactly what we did earlier. So, we are going to load uh for example, the first set value, the signature of the set value function. So, we want to check, "Okay, maybe the sender, they want to set the value.
Okay, let's see." So, yeah, we load the set value function signature and we do equal. And yeah, maybe it's equal, maybe it's not, we don't know. So, we said, "Okay, you can jump to set if the value that we just received is uh equal to set value. And then you you know the drill, it will do it will go here and then to the macro set value and it will go whoop here.
But if it's not the case, then what is going to happen is that well, jump e is just going to do nothing. And so, we will go back here. And in this case also, dump one uh here like a dump one, sorry, is not needed, but yeah, don't worry about it, but this means that here uh when we called equal, we we consume the first value that we loaded here. And we consume this value, too. So, luckily, we duplicated this value into the stack.
So, this means that we have uh value A, two times the value A, then the value B, and then they are consumed. So, we are left with the value A. So, then we can load the function signature of get value, then we have the value A and the signature of get value, and then we can do the same thing again. Equal, and if it's equal, we can jump to the get uh macro, and so we go here, and then whoop, we execute it here. It is clear or not?
No? I'm I'm sorry. I'm sorry. Do you Do you maybe have a question and you can answer like you you you have a specific point that you don't understand and maybe I can explain it like in a different way. Can you have a mic over here, please?
Thank you, Clement. So dup one is that duplicating the Yes. Okay, it is duplicating the stack. Exactly. The dup one is duplicating the first item of the stack on the stack.
So it's duplicating the call the the function signature. Of the sender, yes. So it's duplicating the function signature that we received. And so basically the dup one here is just a way for us to avoid doing this again. Because we could be doing this and then we do this.
We don't duplicate. But if it's not like if the sender is not willing to execute get value, then well we have to check if they want to execute get value. So we we need the function signature again. So we could be doing this again, but it would be costly. They would cost So then don't you have a function signature on the stack three times?
Uh Because you called duplicate one twice. Yeah, this one is an error. Okay. Okay. Sorry about that.
This one is an error because I just like copy pasted that that line and then I changed it. I mean there's no there's no harm because you're not doing anything after that, but you do have a function signature. This could be leading to some issues. In our case, we are just reverting right after, so it doesn't matter. But I can show you after like for example in the case of ERC20 or something like that.
But yeah, you can have like many different things so you will duplicate every time but on the last time it's not needed. You're you're right. Okay. All right, that makes sense. So, um a question So, when you do the equals, it's actually taking two values that's on the stack.
Well, no. Well, taking one value that's already on the stack and the other value is the one that's computed as part of that call. Uh it's taking like when you're doing Yeah, equal is going to take so uh this So, we have this value in the stack. Right. That's on the stack and then can imagine that here we duplicate.
So, this means that this value is here. It's like we are cloning it. It's actually equal. If you don't mind, I'm just going to interrupt you really quick because the question I have is the function signature that looks like a macro. Is that putting the value of that It's computing the the function signature of get value, right?
And is it putting it on the stack? And then the equals equal function is computing the equal between those two values that are on the stack? Okay. Thank you. Because So, this is exactly what you said.
Here equal is going to take the first element of the stack and the second element of the stack. So, that was duplicated from this. So, we have like uh here our stuff that was computed and added to the stack and then the stuff we just computed ourselves. Perfect. Thank you.
Uh yeah, and then it's kind of simple here like uh to set the value. Well, we just go to the macro here set value and well, this is exactly what we've been doing earlier. We know that we need to avoid the first four bytes because this is the function signature so we don't really care about it. So, we just do okay, we want to load 32 bytes starting after the four bytes and then we are going to use a different opcode that we never used called Sstore. So, you can see like previously we've been using Mstore, which is very well, explicit memory store.
And in this case, we want to store in the storage because the user is setting a value, so we want to keep it for a long time. So, we are going to call Sstore, and Sstore works in very similar way to Mstore. It takes like one location and one value. And so, what we are doing here in this case, I showed you this earlier when we talked about constants. We are just going to use like within brackets.
We are going to call value location, which was defined by free storage pointer, which should be zero. So, this means that we want to store store in the storage at this location the value that is starting at the call data after the first four bytes. So, kind of simple. It's just weird that I think the weirdest thing here that you're just doing things in reverse. You have to put element in the stack, and then you have to call a function that will take all the elements in the opposite direction.
So, it's a bit weird to think that way, but you get used to it. And yeah, like you mentioned like many times like the the stack how it works. And so, like a convention, some people are doing and actually I think there's a tool for that. Some people here like add comments, and within the brackets they just put what is in the stack. So, they will say, "Okay, here we have a value here."
So, because we loaded this value, and then they say we have a pointer here, so the stack is like the pointer and the value, and then they say, "Okay, we are calling uh storage uh store, so it's going to use two values, so then the stack is empty." So, it's like also a nice way to be able to track what you're actually doing. Question? Yep. Uh so, um on the stack, if what is the first argument?
Is it the one at the topmost? And then the second argument is the one below it? Yes. So, when you're calling a function, you will take like the one at the top and it will go like uh it will remove them one by one, so it will always take what is on top. Okay, so the topmost one is the first argument in the function signature, and then the second Yeah, in this case, yeah, I would first use like the function signature.
So, if you are doing like minus, you will do this uh minus this. Um yeah, so this function, this macro, sorry, is kind of simple, and then uh ch- I think I think there might be an issue actually with the code. Yeah, okay, let's let's see how it how it works. I wrote this. Uh the test was passing actually, but I think there might be an issue uh from what you were saying earlier.
So, let's see. Uh then uh the get value macro is kind of similar to what we've been doing, but yeah, we're just going to use like a new upcode called uh storage load. Uh and it's it's very simple. You just say, "I want to load into uh the uh the stack. I want to load uh the uh sorry, I want to load into the stack the value that is stored at this location."
So, we're just going to use the our value location constant here. We put it into the brackets. Then we just say, "Yeah, I want to load this value." And the value will be put into the stack. And then same thing as before, we put this value at the position zero into the memory, and then we call return and we say, "You can return 32 bytes starting at the position zero from the memory."
And it will return the value. So, kind of straightforward, yeah. Just a different kind of question here. Uh if I if there's a smart contract that's on the that's been deployed, but the code was not published, can you um decompile it into Huff? Uh I think there's a decompiler, yeah.
I'm not I'm not sure if it's really uh powerful, but I think there's one, yeah. There's one. Because I was just thinking in terms of reverse engineering the smart contract, right? Yeah, you can use it, actually. Yeah, that's pretty pretty nice.
And more convenient that reading the the bytecode directly. Um yes. So, I think that's it for this contract. It's kind of straightforward. We already saw like the function dispatching.
Uh and like to store into the storage or to load from the storage, it's very simple. Um yeah. Do you have any questions so far? Uh yeah. I re-heard ourself.
How you put a stop? I'm not sure. Yeah, I think it's needed. I'm not sure if it's needed or not. And why YUL?
Oh, you open the door. Let's let's see. You can check with the other branch. Uh go to the finish branch. That is the same.
I'll let you check and I'll be back after. Uh any extra questions? Yes. How does um Huff compare to Yul? Uh well, I think like well, the main difference is that uh as we were saying like earlier, you have more uh power in the sense that even in Yul, you cannot manipulate the stack, I think.
Uh there are a few things that you cannot do. Uh in Huff, you can like you're you can like duplicate elements in the stack. You can like swap them. Yeah, you're free to do whatever you want. So, you you can do like more optimized things.
Um I would say that's about it, but uh yeah, I guess it also depends on the use cases, but yeah, I'm not aware of many contracts that were written in pure Yul. But uh yeah, if you're using like Yul like inline assembly in Solidity, then I mean the the the obvious reason would be just to use to be optimizing very small uh portions uh snippets of of code. Uh if you want to Oops. Yeah, so this is the test for the contract uh that we just wrote. So, still very very simple, straightforward.
We're also using the Huff deployer. And yeah, I I did some console log just for the the sake of it, but basically uh still uh quite straightforward. I'll just give you a few minutes if you want to write the the test and try out. Yeah, just let me know if the the tests are passing or if you're having any any issues. How is it going?
All good? It's uh, oh you added more things? Yeah, I did. Nice. Okay, cool.
All right. Yeah, that that's uh, I don't have another contract after that. So, if you want to we we can just be like uh talking if you have more questions or if you want to I don't know, add something else into the code and you want me to let you know how we could work. Feel free to Yep. What what's uh, the issue now?
Failing? I'll switch on my phone. Fail? increment by two What is doing increment? Yeah.
Oh, okay. You want to Oh, I see. Nice. Okay, cool. So, yeah, you are loading the cool data, then you are loading Uh, it's good actually.
It should be working. It's a Yeah. Yeah. To be honest, try try adding like uh, return. I think that might be the the issue.
I'm not sure. Here we are not adding it. Yeah, I'm I'm just I think we might need it. Uh, Yeah, I could be paste the just uh, return nothing just to see. This will return something.
So, just uh, Yeah, so what what you need for example, if you put like uh, zero zero return, it would just end the transaction. So, you you don't have to return something. You can just like uh, put uh, this to return transaction. Uh, to yeah, to stop the transaction. And if uh, are you familiar with foundry?
Read? Okay. Oh, it works. Perfect. Okay, that was it.
Nice. Okay, all good. Yeah, if the tests are failing, you might want to add uh, here I think it would be better, especially if you change the code. Here you can do like you can add after that line return. So, like this, but instead of having like 20 here, you can just like put 00 return.
So, here you can just like return nothing. So, this will just let know that after calling this macro, then you just have to end the transaction. Cuz otherwise, what could happen is that set value is executed, and then you go here to the jump label, and then get value is executed also. So, you have some weird scenario. So, I think it would be just better to do like add return here.
Just return nothing. Just 00 return. This should fix things. If you If you have this If it's not working, try to do what I just said. Yeah.
Uh in your function, just like return nothing. Yeah. Cuz it it fixes the issue for the Yeah. for him. Yep.
Awesome. Another thing you can do is you can just do Yeah, stop also works. But I'm I'm not sure about the gas cost. You can You can just stop. Yeah, you can stop also, but I'm not sure about the gas cost.
You We should check because sometimes if you stop, it's just like consuming the the rest of the the gas or things like that. So, what the Yeah, you can Yeah, you can just research and see like uh halt execution. Yeah. You can If you click here, you have more uh oops details. Yeah, successfully.
Yeah, you can Yeah. It will It works with You can also add stop. Yeah, that's another way to just uh uh end the execution of the macro safely. Yes, sure. How does a queue signal which set value you're referring to if you have multiple with different arguments?
Uh have multiple set value with taking different number of arguments. Yeah, if you're like overloading, you mean? Uh I think you That's a good question. That's a good question. I need to check, to be honest.
Uh I have never done it in half. So, I I don't know, but uh That's uh I I don't even know if it works, actually. Let me Let me check, but I That's a good question. Yeah, I don't know. I have I don't have the answer now.
But uh All right. So, we have like 10 minutes left. 12 exactly, but uh Yeah, I think maybe you had enough. Uh as you want. If you have more questions, feel free to ask them.
I would be happy to answer them if you want to go like a few more minutes, but otherwise uh well, I just want to say thank you guys for I lost the clicker again. Uh thank you guys for attending this workshop. I was pretty excited to see many many people, and I was happy to see that you guys were staying until the end and working and building the the contracts and even adding more more stuff. So, that's pretty pretty cool. So, yeah, that's it.
You can if you are interested, you can follow Huff on Twitter. Uh there's the website. There's the Discord. Um we are working on Huff 2. Uh the new compiler is being uh the compiler is being re- re-written uh from scratch actually.
Uh we are going to be working also on the EOF support and many other uh things. So, yeah, feel free to follow for for more good stuff.
Automatic transcript — names and jargon may be misspelled.