Bucharest Stylus competition with prizes, Zig on Stylus, On-chain randomness and price oracle/randomness using Chainlink with Stylus (part 2), interview with Tolga
Stylus Saturdays, 19th March 2025
Welcome back! To recap: Stylus is a technology to build smart contracts with using WASM on Arbitrum. The code you write is 1-to-1 compatible with the EVM, including calling and storage.
Before we continue, Cyclone Alfred has left 16,000 homes without power, several people injured, and one person dead. Our thoughts are with the community of Brisbane and Queensland who were affected.
I’m excited to announce that at ETH Bucharest, the Arbitrum Foundation is going to be hosting a hackathon! Stylus Saturdays will be hosting a series of challenges similar to Advent of Code in one of the tracks, concluding with a competition to design the most gas efficient Stylus program for a fun problem! Yours truly will be judging and mentoring, so say hi if you’re there and you enjoy the newsletter.
There will be prizes, with the USD prize being provided by the Arbitrum Foundation, and special one-of-a-kind keyboards and (optional) testnet infrastructure sponsored by Superposition! The Wizard on Stylus will graciously be supporting custom templates for the competition.
Visit https://ethbucharest.superposition.so for more. Early days, so we’ll be updating things gradually to have more info.

Recently, Chrisco (@ChrisCo512) of Offchain Labs was able to support Zig with Arbitrum Stylus. His repo lives at https://github.com/chrisco512/wax. He gave a talk on the topic at ETH Denver, which you can watch on X here:
https://x.com/EthereumDenver/status/1895577797416087708
Being able to do this goes to show how relatively easy it is for a developer to add programming languages to Arbitrum, provided there’s a decent WASM compiler backend. Zig is a programming language known for its simplicity and safety, and a huge perk is that the codesize it outputs is way smaller than the Rust equivalent!
This recent post on Lobsters is a good example of how simple Zig can be. This is a allocator implemented in less than 200 lines of code, and I found it simple to understand.
Perhaps your next project will be in Zig?
Continuing from our previous post:
Rust for smart contracts book, on-chain randomness and price oracle using Chainlink with Stylus (part 1), Alisander from OpenZeppelin
Hello again! A bit of a delayed post, being at ETH Denver threw my schedule off a little.
Now that we’ve established our storage initial attempt, and our entrypoint function to store the requests, we need to build our first attempt at a function to handle the callback from Chainlink with the VRF word that we use to seed our vending machine interaction. In the post after this, we’ll test all of this more rigorously to ensure it actually works.
Before we continue, in the process of writing this function, I tweaked our storage to add more toplevel storage so we can prune our storage vectors comfortably when NFTs are consumed:

The change is that there is an extra field called nft_ids_to_send
, which is simply a vector of ids that can be sent per nft address. Simultaneously, each level also includes a vector of the nft addresses. We’ll be pruning these if we run out of NFTs to distribute during this callback’s life.
The callback function that we need to use with Chainlink has the following user story:
It first (this is not included in the above diagram), takes the USD value of ETH at the time, then normalises it, using Chainlink. This follows a similar process as the previous post’s example with Chainlink (making a call), and you can read more here if you’re so inclined. The code then begins to go through each item in the queue, normalising the ETH amount in the queue item. It compares each minimum ask for the queue items in the queue to the amount asked by the user. After finding the first NFT price point that could be reasonably spent this way, it starts seeking backwards to find a NFT.
For this next part, we implement some testing affordances in the form of the Default trait for our storage:
// Default for testing purposes.
#[cfg(not(target_arch = "wasm32"))]
impl Default for StorageVendingMachine {
fn default() -> Self {
use stylus_sdk::testing::vm::TestVM;
StorageVendingMachine::from(&TestVM::new())
}
}
This simply sets up the VM for us. In the next post, we’ll be testing everything, and amending our code based on how things go.
We implement our first stab at the callback function Chainlink will use. Chainlink VRF will call a function called rawFulfillRandomWords
, and Stylus’s code generator will replace snake case with camel case.
It first checks if the caller is Chainlink, and if it isn’t, it breaks. It’s important we do this to avoid providing users with a vehicle for abuse. Following this, we take the word we requested (the previous lockup function called this for us), and we seed local randomness. We use the ChaCha8 PRNG function for this, which is suitable in that we don’t need a high quality of randomness, and a simple XOR-shift strategy could suffice, but it’s a nice show of what’s achievable using Rust with Stylus (we can use virtually any Rust crate!) in this setting to do this this way.
We do a lookup to get the price of ETH at the time using Chainlink. We do this to get the USD price of ETH. We then begin going through the queue of accumulated requests and processing them.
For each element in the queue, we begin to unpack the word we created earlier as the concatenation of the address and the amount. We calculate the USD amount invested for the user by multiplying the price we got from Chainlink with the amount the user deposited. We do a local helper function to convert the type from a uint96 to a uint256.
We enter a function that helps us do a lookup to find the appropriate NFT to distribute. It does so using a binary search strategy:
We use the core library to do the search. This will search the vector in storage, looking for an instance of a NFT level that costs less than the amount of USD the user was willing to offer for it. It only selects the NFT where the next item in the storage vector is greater than or does not exist for the price point they chose. A flag is provided to only search for NFTs with liquidity, by checking the associated storage of NFTs for the level. The function searches backwards for NFTs that have liquidity this way.
In a normal setting, developers might normalise the price to a system of buckets with special numbers, like a system of sqrt price X96 numbers a la Uniswap. That approach would allow a developer to normalise the price based on a tick, which would enable them to select the price that’s appropriate for the NFT in one go, skipping the complicated series of SLOAD storage lookups. I chose this strategy to show off what’s achievable with Stylus, writing a binary search function over storage is trivial. Perhaps a developer could implement something simple like ERC20Votes of OpenZeppelin fame, which is where this approach would be more suitable.
After we discover the level we want to offer the user, we first check if we owe the user a refund. A refund is taking the fee rebate, which is the fee that was paid by every user, and adding it to the amount of ETH that the user deposited when they went to purchase a NFT.
We use this function internally here:
It might be smart for a developer of a real world application to, instead of using Chainlink and doing this calculation in the callback, have it instead store the words in storage. This way the gas costs are more understandable, since many users could submit in a short amount of time with a small amount of ETH for example, and break the entire system. This applies to the search for the NFT, since fragmentation could be so bad that the entire storage range could be cached. This code will check if the level was found, and if not, refund the user.
After picking the level, we start to pick a NFT. We use the PRNG from before (ChaCha8) to generate a u32, the native word of the wasm environment we’re in, which translates to a usize. We pick the NFT from a multidimensional array of the NFT address and the level we’re at. Once we’ve picked a NFT, we also randomly pick the ID we want to distribute.
At this point we try to send them their NFT. If we can’t (maybe they’re a contract that doesn’t implement the ERC721 callback), we then initiate a refund. Refunding can fail (maybe for similar reasons as before), so we allow that to happen to prevent griefing.
We try to send the user a rebate for the amount they sent us. This function is simple:
We op the consumed ID from the storage vector by doing a “swap and pop”.
We do the same as the ID, but we do this to check if this is the last NFT we distributed from the NFTs at that level. We use the same approach for this! Then we check in that we’ve distributed a NFT using a event.
We finally close things out by logging that we resolved the outstanding request for randomness from Chainlink.
So to recap: this function is a callback for Chainlink that receives a random word using VRF, which it then uses to seed a local random number generator (of the complex kind). It looks up the price of ETH, which it then remembers. It goes through the queue of submitted requests for NFTs, and starts to select the level to distribute the NFTs with. It uses randomness to select each. It then goes to send the user what they won!
In the next post, we’ll be testing this code at length using end to end tests of the online kind, and of the offline kind. We’ll be doing this testing using property and mutation testing. All of the code is in the repo: https://github.com/af-afk/vendingmachine.com
Interview with Tolga from Stylus Wizard
I had the time to catch up with Tolga, the founder of The Wizard on Stylus. I really recommend everyone to check this out! Great platform.
Who are you, and what do you do?
I’m Tolga, a computer engineer based in Ankara, Türkiye. I got into tech during university, doing part-time jobs in web development and internships in software testing, creative solutions, and even early metaverse projects. I discovered Web3 in my final year at university through a side project. What started as a fun experiment quickly turned into a full-time job when my classmate and I decided to go all in. Over the past three years, we’ve built a range of solutions, from Telegram bots to full-fledged products, and worked with some of the biggest blockchain protocols.
One of our favorite projects is Wizard, an online playground for building and testing Rust-based smart contracts on Arbitrum Stylus. The idea came from my struggles trying to set up Stylus locally. The whole process installing Rust, Cargo Stylus, setting up a local node, dealing with RPCs — was way too much hassle just to write a few lines of code. We figured there had to be a better way. That’s how Wizard was born — so developers could try Stylus instantly in their browser with zero setup.
The response from the community has been amazing. In just the first month, Wizard gained a lot of traction, and people love how easy it makes experimenting with Stylus. Even Chris, an Engineer @Offchain Labs, showcased a demo:
What makes Wizard awesome?
📝 Pro Code Editor: Built on VS Code's Monaco Editor with full support for Rust & Stylus.
⚙️ Secure Remote Compilation: Compile contracts in a safe, isolated environment.
🚀 One-Click Deployments: No need for setup—just deploy instantly with pre-funded wallets.
🔄 Interactive Testing: Run smart contract tests right in your browser.
🔗 Shareable Contracts: Create public links and share your work with the community.
✨ No setup, no headaches—just start coding!
Try Wizard now: https://thewizard.app/
Check out the docs: https://docs.thewizard.app
What web3 ecosystems have you worked in?
We’ve worked across multiple Web3 ecosystems, including Ethereum, Arbitrum, Stellar, Internet Computer, and Polkadot, plus many others. In the last three years, we’ve successfully built 30+ projects across 10+ major blockchain ecosystems.
Right now, we’re focusing on Arbitrum Stylus because it’s pushing smart contract development forward in a big way. By enabling Rust-based smart contracts, Stylus makes it possible for a whole new wave of developers to enter the space without needing to learn Solidity. Rust’s speed, safety, and efficiency make it an incredible choice, and we want to make Stylus development as smooth as possible with Wizard.
What are your impressions of working with Stylus, good and bad?
The Good
Rust Support: Stylus lets you write smart contracts in Rust, which is huge for developers who prefer it over Solidity.
Better Performance: Rust’s efficiency means contracts can be more optimized and cost-effective.
More Devs Can Join In: Stylus makes Web3 more accessible for Rust developers, bringing in fresh talent.
Great Community & Support: The Arbitrum team and community have been really engaged and helpful.
The Challenges
Difficult Setup: Getting Stylus running locally requires a bunch of installations and configurations, which is why we created Wizard.
Still Growing: Stylus is new, so its tooling and ecosystem aren’t as mature as Solidity’s yet.
Adoption Hurdles: Solidity still dominates Web3. Getting developers to switch to Rust will take time and good incentives.
Even with these challenges, we believe Stylus has massive potential, and tools like Wizard will help speed up adoption!
What software do you use?
Windsurf + Claude Sonnet (IDE)
Warp (Terminal)
Firefox (Browser)
What hardware do you use?
Macbook Pro (M1 Pro)
How can we get in touch with you?
Telegram: tolga0x
LinkedIn: https://www.linkedin.com/in/tolgayayci/
GitHub: https://github.com/tolgayayci/
Stylus Saturdays is brought to you by… Arbitrum! With a grant from the Fund the Stylus Sprint program. You can learn more about Arbitrum grants here: https://arbitrum.foundation/grants
Follow me on X: @baygeeth
Side note: I develop Superposition, a defi-first chain that pays you to use it. You can check our dapps out at https://superposition.so