New Ethereum talks, every Monday. The week's conference uploads by event, in your inbox.

Loading player…

Intro to Rust Smart Contracts With Arbitrum Stylus - ETHGlobal Bangkok 2024

ETHGlobalThu, Oct 9, 2025, 12:00 AM

Join us for a workshop with Chris Cordle from Arbitrum titled, "Intro to Rust Smart Contracts With Arbitrum Stylus." Using Rust to build smart contracts gives you superpowers. Unlock 1000x more memory and 100x more compute with Arbitrum Stylus. We'll cover the basics of Rust and how to deploy and interact with your app. This workshops took place at ETHGlobal Bangkok, a 3-day hackathon held November 15 to 17 2024, that brought together the most skilled web3 developers, designers and product builders from all around the globe for a weekend-long adventure to advance the Ethereum ecosystem! ----------------- Follow us: https://x.com/ethglobal Check us out: https://ethglobal.com/ Email us at: hello@ethglobal.com

Transcript

In this workshop, I'm going to talk about how to do the basics of Rust . I will try to explain the simple parts of Rust so that you can feel comfortable while working on the hackathon project . Arbitrum is offering stylus grants worth $18,000 for this hackathon. Generally, these fields do not receive as many applications as other categories . So, if you submit something , you have a good chance of winning a prize .

This is a very useful skill. Even if you already know other languages ​​like Java or JavaScript but don't know Rust , I hope you can learn the basics needed to build something for this hackathon. This won't be too difficult for you . So, for this demo, we'll just look at the simplest parts of Rust . My name is mentioned there .

You can call me Krisco . On Twitter and Telegram I go by the name Krisco 512 . Feel free to message me (DM) . Yes. Sorry.

I'm sharing something. Yes, that's right. Yes, I...yes. Yes.

I'm going to change the slide . Sorry. Okay. Thank you. So, what is a stylus?

For those who do n't know , this is a parallel VM running on Arbitrum chains . It essentially acts as a VM equivalent to the EVM . That is, when a contract is compiled in Wasm and uploaded to the chain , a small header is attached to it and it runs in the Wasm VM or EVM based on the bytecode . It is fully compatible with EVM. This is not a separate operating environment.

It shares storage state with the EVM . So, you can store your data in the same places as other stylus or Solidity data . It is fully interoperable with Solidity , and as you can see, other languages are also supported are also supported . We're going to look at Rust here , but you can use Zig, C, assembly script, or any systems-type language that compiles to web assembly , and it will be very useful . But for now, we've only built the Rust SDK with our primary focus built the Rust SDK with our primary focus .

We are interested in supporting other languages ​​in the future . But for now, we only have the Rust SDK to use . The main advantages of Stylus are that you get 70 times more computational power and a thousand times more memory per unit case compared to EVM get 70 times more computational power and a thousand times more memory per unit case compared to EVM . That's because the Web Assembly VM runs close to bare metal assembly instructions. As a result, virtualization and similar functions are limited on Arbitrum nodes .

We provide that cache storage to developers and blockchain users . So, whatever you do that requires a lot of computation, the stylus will work better there. Storage fees are similar to Solidity fees. So if it is more storage- dependent or has some simple operations like addition and subtraction . This may not provide huge case savings compared to Solidity , but if you want to develop in other type- other type- safe languages ​​like Rust, it allows you to use those languages .

So it is also useful for writing more secure contracts . Yes, it supports alternative coding methods , helps connect Web2 developers, and we want to reach those 20,000 Rust developers , and we also want to bring in millions of developers in other languages . So, these are the reasons why we created the stylus at Arbitrum. Okay. To get started , your primary resource for working with Stylus is docs.

arbitrum.io, which will have a section in the sidebar called 'Write Rust smart contracts' or 'Write Stylus Rust smart contracts' . I don't know what it's called , but it'll be in the sidebar. If you click on it and go to the Quick Start section, you can follow it to install all the necessary prerequisites on your computer. You must have Rust installed.

You must have Docker installed on your local computer. And And Rustup is a CLI tool. There are a few CLI tools that you may find useful, but just follow the instructions in them follow the instructions in them . And it's very easy and quick to get started. Yes, there is a section in the documentation called 'run a local dev node'.

It explains how to set up a virtual arbitration node on your computer . Therefore, for faster implementations during this hackathon , it would be best to work locally using your local Stylus Dev Node or Arbitrum Dev Node . So, look for that area under the stylus section or somewhere else . Also, if you want to submit a prize for the purpose of the hackathon, you must upload it to Arbitrum Sepolia. Here are three faucets you can use.

These faucets are also listed on docs.arbitrum.io . So, if you need testnet ether or need more than what faucets give , contact us or come to our booth and we'll send you testnet . Let us know know .

Okay. Okay. Again, Rust's primary advantage over other languages is that it is a very strongly typed language. It is memory safe safe . It contains many high-level language features .

It feels like a modern language like Java or C , and although it has high-level features, it is still a systems- level language . Therefore, it performs at a speed comparable to C or C++ . It is very fast and efficient. For these reasons, Rust has been growing rapidly over the past few years . It has a very powerful compiler that will often clearly show you which line of code is wrong.

Therefore, it is a very useful compiler. It also has some cool features like pattern matching. Like I said, it's very fast. You can find out how to handle variables in Rust here. The variables you define are immutable by nature .

So when we say 'let x = 5' , it is a value that cannot be changed. But if you say 'let mut x = 5' , it now becomes a mutable value, and you can change it can change it . These are some of the data types available to you by default in Rust. These are unsigned integers integers . By default, Rust supports unsigned integers up to 128-bit .

But for the stylus, we use a library we use a library called 'alloy' . This came from the Foundry team . But we use it to support 256-bit integers as part of our SDK , because you need to maintain that Solidity compatibility . But this lowercase u refers to Rust's native types. So sometimes when you're working with the SDK, you may need to convert from native Rust types to Solidity types .

But I'll explain that later in this demo . These are just the native Rust variants you have access to . This is how booleans, strings, and tuples look like . A tuple is a collection of values and is like an array. This function looks like this.

It's very simple. F Main is in operation. You call a function using a print line . I repeat , this is very easy to work with functions. For hackathons and other things things , I recommend using basic functions to call other functions to keep your code simple and straightforward .

This arrow symbol, which you see in the plus one function below, indicates how to return a value . So, you can indicate that you are returning a value using that arrow symbol. This is a struct struct . You will use this when you set up a data structure . In Rust you will use strings quite often .

This is a rectangle with a 32 -bit unsigned integer for both width and height . This is similar to objects in OOP languages ​​like Java, but they are slightly different. Rust avoids inheritance as a design principle, so Rust often follows the ' composition over inheritance' approach . So, many times you will attach methods to strings and implement traits . But, I don't know if I'll talk about it much in this speech .

But just know that traits are like interfaces in other languages . You can apply traits to straight lines to create functions, such as calculating the area of ​​a rectangle . Yes, this is just an example of declaring a rectangle . There are several ways to do this. But, this is one of the default ways to declare a rectangle and create it .

Yes, let's look at the impl I mentioned earlier. So, here we are creating an area method on this rectangle . So, we have the rectangular stretch that we defined above , and then comes the imple rectangle . You can think of imple as implement , which is a type of implementation implementation . Um, this is how you attach methods to a struct.

You can implement (impl) and define your functions below . Where ' . Where ' self' is a reference to that rectangle instance . This will always be the first parameter. You would specify this as the first parameter of the method would specify this as the first parameter of the method .

Um, it's very simple. Multiplying self.width and self.height gives the area, which returns a U32 value . Rust also has a feature Rust also has a feature called 'enums' .

The spells in Rust are very powerful powerful . It is very easy to define these. You can implement things for the weak as well. Um, here, the inams are very powerful for pattern matching in Rust powerful for pattern matching in Rust . What you see here is an example of pattern matching.

It has a coin , which has a value of cents . We match that value , forcing Rust to handle all possible states of that enum . Therefore, you must specify each value directly or provide a default arm in the match statement ; For example, if you want to limit it to just Penny, you can use this . Well, this is an advanced control flow . You can say ' let config max = Some (3u8)' .

What this statement says is that if the config has a max value , this option type in Rust can be 'none' or 'some' . If there is any value in this, it will be a match in the 'sum' branch. Here we are matching config max , which we have already given a value of 3U8 . 3U8 is an 8-bit unsigned integer. If it is 'sum' , we will extract that value as 'max' and print the number three using the print line.

So, this is a slightly more advanced syntax. It takes some getting used to, but it's very neat to use when needed . But I strongly recommend that you learn pattern matching as you move to an advanced level in Rust recommend that you learn pattern matching as you move to an advanced level in Rust . As mentioned earlier, traits are like interfaces in OOP languages. So, this is how you define functions for structs or enums .

Here I have a summarize method with a summary trait , and I'm declaring the interface for it here . It does not take any parameters . It takes a reference to itself, but returns a string . So, that's the summary trait. Okay.

Here is an example of this using a tweet structure. This includes username, content, reply, and retweet. I'm implementing the summary trait for the tweet and using that method . This now provides that summary functionality for the tweet structure. So, if I have an instance of Tweet , I can now call TweetSummarize and print the username and content to the console .

That's basically what it does . Macros are a powerful concept in Rust. This allows program code to be generated at compile time . If you're new to Rust , this can be difficult to learn. For example For example , you wo n't be able to learn this this weekend, but you will use macros and see them in practice.

So, when you see an exclamation mark at the end of a print line , it means it's a macro . There are many types of macros, and the exclamation mark indicates that it is a macro, such as a function. So printline is what calls that macro function . When your code compiles, it will generate the code in the background, remove that line, and add that code in its place. So, you should keep this in mind when looking at macros : when your code is compiled, it will be replaced with the code generated by that macro.

Similarly, the brackets and the derived debug that come with the hashtag are also macros. If you see such syntax, it means a macro and the block after it. This is usually like an attribute macro . These are attached to functions or structures . These will often help you save time by avoiding unnecessary code that you have to write.

So, macros are very powerful powerful , and they are very useful if you are new. Um, just be aware that this is what's happening . But, if macros are completely new to you, it will take some time to understand them. We use macros a lot in our SDK , and I'll explain some of them now . Um, okay.

So, we wanted to do simple design methods with our Stylus Rust SDK. We use a basic library called alloy , which allows us to convert between solidity and rust values. I'll show it to you right now. When you work with a stylus, you'll want to use a cargo stylus . Cargo is a CLI tool for Rust, and after you install it, if you call 'cargo stylus new my first contract', it will create a basic counter contract locally, which I'll show you.

As you work on and revise your contract revise your contract , you should periodically call a 'cargo stylus check' to ensure you are staying within blockchain restrictions . Contracts must be less than 24 kilobytes . Since we do some compression methods , it might be a little bigger than that . To bring it down to 24 kilobytes, we enable on- chain compression . Running ' cargo stylus check' will ensure that your code is within range.

If you need more space than that , you will need to split it into multiple contracts . When you are ready to deploy , you need to call 'cargo stylus deploy' with the endpoint and private key , which will deploy to your local or remote chain . These are some primitive types. As I said before, you will use these alloy types when working with the stylus . So you would use uppercase U8 and uppercase U256 .

Remember that there used to be a lowercase U , which was Rust's native integers. These are a library. These are integers from our SDK, but they are created by Alloy . So these are the alloy types, here I define an 8-bit integer from the number one . This is how you should work with our Stylus SDK integers .

Sometimes you need to convert from one to another , like using 'U8 ::from (1)' to convert from a native Rust type to a Solidity type . Let's look at how to handle addresses. In Rust, you will use Solidity style addresses . You would use that address type, enter ' from' with a colon, and fill in all 20 bytes with one . This is a quick example, but you can fill in all of those 20 bytes if you want.

Here, these are local variables again. Yes, these are the different types of variables you use. Local variables that use memory, state variables that use state and on-chain, and global variables that are available in the VM. These are usually specified from within the SDK . You can take them as library values ​​and then reference them .

Okay, remember that hashtag macro type I showed you earlier . What you are now looking at is the Solidity Storage macro. This means that we are declaring a 'struct' type here . We set this up for how our smart contract state should look . That Solidity storage macro tells Rust to set all of this up in a way that is compatible with Solidity.

This is also going to be the entry point . Your smart contract should have exactly one entry point 'struct' , which is your top level 'struct'. If you think about it that way, that's the root level 'struct'. You may have other Solidity storage 'structs' , but only one entry point is required. So that will be the root.

Your storage will start with an 'initialized' variable, an 'owner' variable, and a 'max supply' variable . It contains a boolean, an address, and a U256 . These are the on- These are the on- chain storage states. Okay. I need to update the slide .

Sorry. This external macro is now called 'public' . But I think both will work. We have removed 'external' to be consistent with Solidity . So use 'public' , if you clone the default counter , you will see that it shows ' , you will see that it shows ' public' .

Keep using the same using the same . What we do with that 'public' macro or ' macro or ' external' macro is we implement it in the counter and set up our Solidity API for methods that explicit users can call in your smart contract. Okay, let 's get into the code. Yes, yes. Yes Yes, yes.

Yes . Yes, those are price tracks. But let's get into the code. I only have a few minutes , so I want to get to it quickly . Hmm, okay.

So, very quickly, I'm going to do ' cargo stylist' . So, let's assume you have everything ready . I'm going to say ' . I'm going to say ' Cargo Stylist New Counter Demo' here . It will become a clone.

And I think I'll have it here. Okay. So, I'm going to click into lib.rs , which is the default master file that you edit in your smart contracts. And I'll take you through this quickly .

Here are some comments. Let's skip these comments and move on. Most of this is boilerplate code that you can leave as is. This will help you later export the AI ​​for your contract . So, leave it as it is .

These are the dependencies we bring from the Stylus SDK . We only get unsigned 256-bit integers from the Alloy Primitives library. And this ' prelude star' brings various things for us to easily reference, such as this entry point macro . These are the commonly used things we need. So that asterisk brings us those dependencies .

What you see here is this ' Saul storage' macro, which allows you to declare your types in a way that is compatible with Solidity , so I think in the slide I used the Rust style , there are two ways to do this, but using this Solidity style, you would use the Solidity style syntax to set your state . So this is a 256-bit number that keeps track of the state of our counter, and again we connect this entry point. So that's the root level storage for our smart contract . Okay. Again, remember that I said it was external before , but now it's it's public.

So stay with ' public. So stay with ' public' , we are implementing for that counter that we declared , we have many public methods including 'number' which can get the value of the number from the storage. We can change the number to whatever we need. We can multiply it by a number. We can add a number or increase it by one .

Okay. Here's how it works in practice , we've made these public , which means they'll be exported in the API . We use the 'mute self' syntax for a mutable function , meaning that this function is mutable or capable of changing state. So when we call ' self.number.

set_new_number' , we set that value in storage, which is stored on-chain with the value we input . Okay. Time is running out running out , so I'll finish this very quickly . cdls uh cd counter demo. Okay, great.

Now we will use 'cargo stylus deploy' . Okay. I think I have set some environment variables locally . This 'no verify' syntax is for contract verification to run locally verification to run locally , which can take some computer time . If you want to upload quickly, you can skip the verification step.

If you want to verify your contract on sites like Ether Scan, you can do that later . But, I enter the endpoint using the private key provided when I set up the local RPC variable and the local dev node . Looking at the documentation, you will be provided with a private key along with local ETH that you can use for that . So, you will use that private key to upload , and it will be uploaded locally . This is how it will look , and it will work quickly once the upload is complete.

This is being compiled . Uploaded . Okay. It came in at 7 kilobytes . So, we will copy that address.

I am using the 'Cast' library from Foundry . So, I will set this up for our new contract . 'Cast' is a great tool, whether you're working with...Solidity or something else . This is a great tool for interacting with on- on- chain contracts via CLI .

Oh, I should have called there . I have sent it . Okay, quickly I'll call the counter , it should show zero. Okay. When I go up and click , this time I'm doing 'increment'.

And what I'm going to do is cast increment. Okay, it worked fine on-chain , then , then ...cast call. Now if we call the number again , it should show up together, right? It shows together there.

If I increase this again, it should now be two , right? This is how you should build it, that's the way. I think it's very easy to learn if you just focus on the simple parts of Rust. Rust can seem a little daunting , especially its advanced parts, but if you're new to it, you can start with a basic contract and gradually add the functionality you need . However, even if you're new to Rust, I think it's possible to learn it in a weekend.

Oh.

Automatic transcript — names and jargon may be misspelled.