Programming with Vyper: New Tools and Features

EthCC[8] · 1 Jul 2025 · 40:23

Charles Cooper introduces recent Vyper language and tooling changes. The workshop examines features intended to help developers write safer and more efficient EVM smart contracts.

Speakers

Topics

From EthCC[8], hosted by Ethereum France.

Transcript

Um, this is a tool for working with Viper called Moccasin. It's basically a full framework for like testing and debugging. It even has a console um, dealing with Viper contracts. So the first thing we're going to do is just run mox install mox. Moccasin is a kind of snake. So all of our um names are like snake names. So uh snakemate is kind of like a standard library. Well, it's it's a third party standard library for Viper.

It's kind of like open zeppelin or salady or something. And so that installed everything in live. Um, and if you are super interested, you can be like, oh, like here's the files that I installed. So, just now I was saying that there's um all these files that aren't really visible, right? So, we've got my token. Uh, we have from like snakemate tokens. Like, this doesn't look like a token because there's a bunch of stuff missing. So, where is all the stuff that's missing? It's in sorry here sorry sneak name uh tokens ERC20.

So this is like the actual implementation. Uh it's a library and it has all these um awesome functions in it. ownership um mint burn yada yada. So um let's say we want to actually do something with this. So we've like taken our token, we've like uh initialized it, we like minting some stuff, and then the next thing we're going to do is like test it. So here's like some tests.

Cool, right? Uh, double check that the supply equals the supply. Um, this is actually really awesome code that was not written by a human. Um, so if we like run mox test, then it'll like test. Whoa, everything passed. That's actually incredible. So, um, is there anything that anybody would like to see this token do besides just like, okay, you can like transfer stuff custom minting function?

ERC2612. What is ERC2612? Oh, right. I think that actually might be available. So amazingly we're uh saved by the bell because snakemate has a permit function. So um what is in this interface? So, interestingly, if we compile this stuff and um look at this, it actually has a

permit function in it. Um it's in the AI. So, the next thing uh do you want to see anything about the permit function like you want to test it? Sure. How do we actually test the permit function? I'm going to delegate that to you for now so I can finish the rest of the because I don't want to test this on the fly. Exactly.

So the next thing we could do is so in the moccasin config we've set up this anvil network. So we're just going to run anvil here and oops mo deploy my token. So here crap. I think this should work. Oops.

There's something wrong here because Anvil wasn't even running. I think we can delete all of this actually. Where did this deploy to? Oh, we have to specify the network. Sorry. Okay. And then we have to like make a private key and all this stuff. Uh, Mox wallet generate fu save password fuar and then

since we're in moccasin Oops. And run private key fu. That's really not good actually. Can I just use the private key that we made here? Okay cool.

So now we've like sorry this is an unfunded account so everything failed but it actually like generated this like deployment. So, if it was like actually an account that had Ether in it or whatever. Um, and I could like choose one of these things here actually that probably has some money in it. Um, Oops. There we go. Um, that's interesting. There's some kind of API mismatch now. Um, but basically it's very cool because the token like deployed, right? So if we wanted we

could actually like spin up the console and um kind of interact with it. Um, but I want to get back to you guys. How is that permit test going? I am uh spinning up the console just the same as you. Okay. Um before I continue, is there anything that anybody wants to see? Um how how would I go about checking that the allowance spending logic is correct? Very common bug I see tokens is that when you spend the allowance, the arguments to the mapping are really I

mean I'm sure this is fine, but It is a basic thing I would check. Yeah. So that's in here. So basically um this is a test for the allowance. Okay. So and then you just check that the allowance here. That's true. Like the test and the implementation could like both be wrong, right? Um who will test the tests, right? Very philosophical question. Um but I mean it's it's quite straightforward because like after you like check that the allowance is there then you like actually run the transfer from function and then um yeah you check that the deducted

allowance is like actually equal to the amount that you transferred. Um so basically you would test it. Um and this this test is like all Python by the way. Do we have more questions or are you just kind of like interested to see where this is going? Um, we could completely switch gears and go into track two, which is like the optimizer. Uh, which is okay, great. Some brave souls here, which um, in my opinion is actually much more interesting.

Uh, so I had Claude write this, right? So the the track one it wrote in like five minutes all of this like amazing code that like happens to work. Um, and then it with the Venom stuff, uh, just to give you an idea how much more interesting or difficult it is took like the rest of the hour. So um, and I had to guide it a lot. So um, let's look here. So the first interesting thing is that we can uh take a contract a viper contract and spit out the venom.

Um so here are some interesting optimizations that we do. Um you know the first kind of pass of them. Um so obviously like these are kind of things that you might expect but maybe also not might not be obvious. So identity operations x plus 0 is x x * 0 is going to be zero. Um we have some weakening these are called weakening. So like and or um shifts are like cheaper on the EVM than like mole or mod which are like five gas or whatever three versus five gas. Um so where is this?

Okay so these are strength reductions. So these are nice algebraic identities. Let me spin up make sure I'm in the right virtual environment. Going to close this So right Viper version good. Uh

let's delete that. So this is what the Venom this is uh after all the optimizations run actually. So this is what the Venom code looks like. This is the entry into the selector table. Um it's super cool. You can read about it. We have a blog post about it. Um blog.org. Um they're constant time. So um entry into a Viper contract costs like I think under 100 gas if I am recalling correctly.

Um and it's like constant doesn't matter how many selectors you have because of amazing hasht magic. Um that which is right here actually. Um so anyways this is the kind of the body of the main of the different functions. So, this is the selector I'm assuming for I wish there were more comments here. Um, but what I'm going to do actually is going to turn off optimization so you can kind of see what it looks like.

Um, oops. Run passes. What can we get away with not running? Let's just actually print it before um running any optimizations. And this compilation is going to fail, but we're going to at least Oops. That didn't do what I wanted.

Okay, so this is the unoptimized code and if you compare with um the source code uh we're looking at let's see algebraic identities right so let's look for some exors That looks optimized.

Sorry, technical difficulties. Oops. Okay, maybe that works. What is going on here?

Yeah. Yeah. Okay. This is the unoptimized code. Sorry about that. Um so right um for example here we've got X is called data load 4 and then Um yeah here sorry is called data load 4.

So this is x x or x and um here is going to be like x x or zero somewhere. Sorry, I'm like hallucinating. Okay. I see.

I think maybe this example would be better if it were smaller. So, let's try to like just extract some of these things. turn C plus D. Okay, so this is a smaller example.

Um so right and then so if we turn on the optimizations or if we like examine what the optimizations look like before and after sorry what the uh the venom looks like before and after optimization it will look um a lot smaller. Sorry.

There we go. Okay. So, what Why does this look so unoptimized?

Oh, that's interesting. We found a um opportunity for more optimization actually I think. So I think what's going on is it's actually not running enough times. Um, Sorry, that's really um throwing me for

a loop. because like this um the reason I've been like so confused is because this add uh 0 to 38 should be being optimized out but it's not. Um so I think that's actually a bug um where the optimizer is being too conservative. Um I think we can take some other optimization passes though that will also kind of be interesting. Okay, so this is an example of dead code

elimination. Um, so here uh we generate a bunch of code for like this thing. Um so some of this is actually uh optimized a little bit in the front end. So we have this like constant expression uh which is 260 and then we do blah blah blah you know add subtract blah blah blah. Um so here like add 100 to this thing and then we like stored in memory.

Um but what happens after optimization is that all of that is like deleted and then at the end we just return 360. Um if we I want I'm hoping that this demo world is going to work. So here's another kind of optimization pass. Um so this is um this is the unoptimized code up here. We do all this stuff. Sorry.

Here we allocate all this memory. We do a bunch of like uh you know arithmetic. So we can actually find where this gets reduced. Um, add Yeah. So, this is like this one is actually folded in the front end. Um, but here is like x * 16.

Um there's going to be adding to zero which is this thing and then there's going to be um like this u modulo 8 which we can find here um and then we can find this like div 32 and then this whole experience is going to get a lot better if I actually print better things. Um, so that's the final bite code by the way. Um, so man, we have

so x 16 is going to turn into I think a shift left. So that's here and then let's see mod is going to turn into this and thing which is uh here and then the div thing is over is going to be turned into a right shift too. Yeah, this thing. Um, so these are kind of like um these are called algebraic optimizations because they're just like things that can be done symbolically and you don't actually need real values in

order to do them. Oh, I have 10 minutes. Okay. Um, I want to look at some actual Venom examples. So this is like what would it what it would look like if we took in straight um venom and optimized it. So these are like kind of actually more complicated. So SECP is like sparse conditional constant propagation. Um it basically does uh constant folding and dead code elimination at the same time.

So um I guess what people used to do is they just like did those in a loop. Um but there's certain kind of things that you can't reduce if you just like loop doing like constant folding and dead code elimination. Um and I think this is actually one of them. Oops. Yeah, this is one of them. So, this is like something where the basically the loop condition like depends on like the constant propagation at the same time.

Um, so if you like stare at this long enough, maybe you'll have an epiphany about like how you could um optimize this. Um, but we're actually going to use the Venom binary. Great. Um, workshop and Oh, shoot.

Okay, now we have to fix all the compilation errors. All these labels should in the syntax look like this. Right. So, this is like what it's supposed to look like afterwards. And we'll just comment that out.

Oh great. None of this is compiling. Sorry, this is a very bad demo because

it's like uh not compiling And I'm wondering if it's something that was introduced recently. Oh, let me see. Uh, M store 32I return 3232. There we go. So um if we actually print the thing after secp um it doesn't look like all of this. It looks like u much smaller

basically. um a lot of these branches have been like eliminated and um this is like actually kind of a non-trivial example. So you can like take it and um kind of work through it with pen and paper actually because it's like it kind of gives you an idea of what it does by like actually working through it. Okay. And I think uh we're about at time. Yeah. have question. I was gonna ask maybe a dumb question, but what's non-trivial about your example? Uh what what's non-trivial is if you like

keep uh propagating this constant. Uh let me see if I can actually like find where it is. Um I think the control flow graph is like too complicated because like um uh basically the thing where it gets Um okay so the so what I was saying is like you do uh constant propagation and dead

code elimination in a loop. So if you do that here you can't like eliminate the code where it gets assigned something else. So oh sorry so there's some variable which gets assigned something different in two different branches. Oh and if you like yeah do it in a loop then you can't like eliminate the branch where it gets assigned something else. Okay. So then like yeah so by doing them at the same time basically uh or by following the SECP algorithm it like how do you explain it? It like does the evaluation in parallel. It like evaluates the values symbolically but it

also does dead code elimination at the same time. So it like sees that you can't like uh recurse into the branch that's not taken. So then uh the J or whatever uh never gets assigned the other value. So it it can prove that it's always a single value rather than like it takes different values in the branches. Have any questions? Christian. Thank you for the workshop. Um, you mentioned before that you have constant access time to the selector table. Yes.

How? Um, do you want the long answer or the short answer? You choose. Um, so I think everybody knows how solidity does it, right? It's like a branch log 2 or n login or whatever. Um, it's a binary tree. Um, and that's like not the only way to traverse uh data, right, that we know. Uh, there's also like hashts. So, uh, I looked into this a long time ago. And the basically the problem with hasht is like you you end up having to loop, right? So, if you think about like evaluating this hash table, you have some the okay, the

traditional way would be like you you have some data in memory, right? And then you have the query the key and then you like uh look at the bucket where it is and then you loop over the bucket and probe into it. And the problem with that is like uh jumps like basically suck uh you know loops in on the EVM suck. So if you do that then and you're like reading this thing from memory in a loop then it's actually really inefficient. Uh so it's like 01 but with a really high constant factor. Um, so there's a couple tricks that uh we do, but the main thing is like we we transform this hash table into a a code data structure. Um, so uh

the bucket is a location in the code. Uh, and then instead of like traversing code, you traverse uh sorry, instead of traversing data like the thing in memory and load and loop, you traverse the code. So, what it ends up looking like is um the ERC20 example might actually be a good example. Um I'll do the I'll do both IRS and see which one is easier to keep track of. Sorry.

one uh source token. So if we go all the way to the top where the um so you jump to these buckets which are actually represented in the code. So if we look at what's in bucket one, oh of course um it's just a sequence of if statements actually.

Yeah. So like normally you would have the method ID in like memory and then you like probe and check equality to this method ID um every iteration of the loop. But instead of using the the initial um hash to look up a bucket, you use it to look up a section of code and then you just traverse through the code and then the code there is very simple. It's just a sequence of of if statements. Um I don't know if that answers your question, but basically it uh converts the uh data data structure into a code structure.

Okay. So in the end you have less if statements instead of Yeah. And there's some tuning too. Uh so we like simulate a whole bunch of um possible uh code layouts for the selector table and then pick the one that has the lowest variance in the probe depth. Okay. Okay. Yeah. And so the average probe depth is like one or two if statements. And in very uh like weird very uh what is the word pathological cases it can be like three but um I did a lot of tuning of this uh the probability of that is very low.

Um we choose a we uh basically iterate through a bunch of hash functions uh where the hash function is basically defined by a number that you have the initial um starting modulus from basically. Thank you. Yeah. Yeah. Any more questions? Thank you for bearing with uh incorrect format talk.

No, you try too. You try too. It's important. Yeah. Yeah. Yeah. Thank you for that. Yeah. Anybody uh who wants to come talk to me or like actually go through the workshop like interactively please uh my telegram and Twitter are big tech sucks sux um or the official viper lang Twitter viper l a n g v y p. Let me actually just pull that up.

That's how you know your family meas Yeah, I think for the record and I think like um when you do Matt in general uh on chain that cost you a lot and Viper um like really important uh vision important library for every like defy and mathematical community. So thank you

for what you do in general. Yeah. And one thing we're working on is like uh getting more D5 building blocks as libraries. So like if you want to build a lending market or a DEX, like it's kind of uh there's some source code available and you can just like adapt it. Yeah. Great. Thank you, Charles. Okay. Yeah. Thanks. [Applause] Thank you very much.