During the past month, I've been building evm.codes (an interactive reference to the Ethereum Virtual Machine Opcodes) in collaboration with Comity Labs - an A16Z Crypto fund-backed startup helping communities fund, engage, and reward members with blockchain technologies.
In this post, I wanted to share how we built this cool project and how it could help developers get a better understanding of EVM internals.
evm.codes is also my first open-source contribution to the Web 3 world, and even though I have been into crypto on an on-off basis for a few years (trading, observing, and testing out various dev tools), I only got serious about blockchain development at the beginning of 2021. Web 3 became so significant that I couldn't simply ignore it anymore; it's definitely the next wave of innovation happening right now. Check out this Twitter thread from Chris Dixon (general partner at A16Z focusing on Crypto) sharing why Web 3 matters:
In August this year, I've had the pleasure to meet Dor Levi (Founder & CEO of Comity Labs), who recently approached me and offered to collaborate on evm.codes. What initially has been an internal Notion page Comity used for onboarding, appeared to be quite a useful resource and hence their team decided to make something better, what other developers could use and learn from.
By the time, I had been full-on learning Web 3 development (mostly Ethereum, with some exposure to Solana & Rust), going through a number of online courses at Udemy, Udacity, and Buildspace (which by the way, deserves a post of its own).
So, the idea of building an interactive reference to EVM with a code playground quickly caught my attention. Coming from the DevTools background myself, I learned how important it is for developers to have a one-stop resource with the ability to interactively experiment with pieces of code, especially when it involves an emerging technology with a lack of established tooling and documentation.
If you aren't familiar with EVM, I recommend you read official Ethereum documentation on the subject, but it's basically a stack-based computation engine that powers the Ethereum Blockchain, enabling it to run and deploy smart contracts. Each version of EVM (hardfork), consists of an instruction set called opcodes (operation codes), and associated gas costs, which are thoroughly described in the Ethereum Yellow Paper. When a developer writes a smart contract in Solidity or Vyper (two of the most active smart contract languages for the EVM), it is compiled into bytecode, which is then converted into opcodes for the EVM to interpret.
However, we couldn't find yet a single place where developers could easily look up opcodes, their associated gas costs, usage examples, nor the playground to run the smart contract code along with bytecode, in order to see the operations and gas costs involved. Hence, building EVM Codes from scratch seemed like an interesting side-project and an awesome contribution to the open-source community.
The aim is to expand on this project to help Ethereum developers get better at understanding EVM internals and write more efficient code, to hopefully reduce gas consumption for the rest of the world.
After a few discussions with the team at Comity Labs, I have been provided with a single-page HTML/JS prototype interacting with EVM via EthereumJS, as well as a demo compilation of the code with SolcJS and a step-by-step execution flow.
Throughout this entire project, I was fortunate enough to collaborate with Adrien Hamelin, an engineer at Comity Labs, who helped me with the low-level parts of the EVM, which honestly I am not deeply familiar with yet. He also wrote all the explanations of the opcodes used in the reference table 🙌. So, my role was to turn it into a usable and polished application ready to be used by the public.
After designing a couple of mockups, I quickly started prototyping with ReactJS + NextJS, which is nowadays my frontend "framework" of choice. Additionally, I tend to default to TypeScript for better code completion and the ability to hopefully catch bugs earlier.
As the entire application consists of just a few pages, I ended up not using any external state management solutions, relying on only a few React Contexts sharing the global application state - EVM and user preferences, in our case.
For the CSS framework, my choice was mostly between TailwindCSS and Chakra UI. Both have active communities, excellent documentation, and features we required - customization, dark mode support, easiness of use, and utilities for site responsiveness. Since, we didn't need a lot of Chakra UI's components (modals, forms, etc.), I've decided to keep things simple and go with TailwindCSS.
To get the fastest feedback cycle from the team at Comity Labs, we've configured the app to continuously deploy to Vercel. It's so powerful when every Pull Request has an automatically deployed preview environment, without having to run anything manually.
We thought of running a backend service with an API for interacting with the EVM, however, to keep things simple for the first version, we have decided to run it in a browser, even if it increased the bundle size. That way, there also shouldn't be concerns about what we do with the uploaded smart contract code (we don't 😉), as everything runs client-side.
How it works
The app basically consists of three sections: an interactive reference table of EVM, a playground for executing contracts and seeing the EVM state in real-time (memory, stack, storage, and return values), and an About EVM page with the details on how it operates and what it all means. I definitely recommend you to read it first before giving Playground a spin.
The opcodes reference table is pretty self-explanatory, showing you all the instructions for the chosen fork, along with their associated names, gas costs, inputs/outputs, and descriptions. You can also quickly filter the table by the name/opcode/description.
Expanding each row of the table shows you a more detailed explanation of the opcode, with such important information as to when the opcode was introduced (hardfork), types of inputs/outputs, example usage, and possible error cases.
All the information is backed by the Markdown documents (MDX actually for future dynamic interactivity), which could be easily updated in the GitHub repository. So, if you find anything that's missing or incorrect, we'd happily accept your contribution.
The playground is the area where you can enter your smart contract code in Solidity or Yul, which is then compiled in the browser with SolcJS. You can also paste the bytecode directly into the code editor.
Using EthereumJS, the playground then deploys the contract to the in-browser running EVM, shows a breakdown of all instructions involved and their associated gas costs.
And here is the fun part: by clicking the Next button you are able to go through every instruction and see what's happening behind the scenes: what's in the EVM memory, what's being pushed or popped from the stack, what's being stored, what's the return value from the execution of the contract, and of course, the gas fee for each instruction and the total consumption.
Additionally, we've implemented breakpoints, so by clicking near any instruction, you can pause the execution at the point you are interested in, without having to go through the entire set. Pressing the Continue button continues the execution until the next breakpoint or the end of the instruction set is reached.
Generally, the entire project was pretty straightforward to build, thanks to such open-source libraries as SolcJS and EthereumJS. There are a couple of gotchas we've run into, which took us a few iterations to code.
Firstly, fitting all the details about every opcode in a table that's also responsive was challenging. So, we quickly ended up moving secondary information to the expanded section of every row.
Secondly, we've had a number of discussions about the code editor layout. As some developers could be interested in the smart contract code and their related instructions, whereas more experienced developers in the actual EVM state, we ended up breaking up the columns in a 50/50 layout. Ideally, the entire code editor would be resizable so anybody could customize it to fit their needs (the feature we've already planned).
Lastly, right now we are only displaying static gas costs, but there are some instructions where the gas is dynamically computed based on a number of variables. That's the next feature on our hitlist, so be sure to keep an eye on this GitHub issue.
There are a bunch of ideas we want to build on top of evm.codes and some of them we've logged into GitHub. For instance, it would be really cool to see diffs of instructions and gas costs between the forks, or visually relate the smart contract code to the instructions being run along with the contract code optimization recommendations right in the editor, or even go ahead and interact with the mainnet. If you have an idea to extend evm.codes or want to collaborate, leave your comment in any of the existing GitHub issues, or feel free to create a new one.
Overall, I am pretty stoked with the outcome of this short project and our collaboration with Comity Labs. It's been really interesting to dive into the Ethereum Virtual Machine internals, to get some understanding of what's actually happening when the smart contract code is compiled and interpreted.
I hope, this was a useful open-source contribution to the Web 3 world and I have definitely enjoyed it. If you liked the evm.codes or found this post interesting, spread the word and share it with your friends & colleagues. You can reach me out for any questions or suggestions, till then GN. 🤓