As part of the research I’m doing to make sure Athena is a best in class VM and offers a best in class blockchain development experience I’ve been studying smart contract development and the associated tooling in a variety of other ecosystems. While I’m quite familiar with Ethereum I’m embarrassed to admit that before this week I hadn’t ever built or deployed code to any other blockchain.
My goal is to learn what other projects and ecosystems are doing well and as much as possible to address the things they’re not doing well in Athena. The first step was a minimum viable “real world” blockchain application: to write, test, and deploy a basic fungible token smart contract and then mint and transfer a few coins on several different testnets.
While the Athena project involves a big stack of technologies, and while most of the project will probably be focused on things like VM design, programming language design, programmability, executability, etc., tooling also matters a lot. I spent a lot of time this week studying tooling.
Here are some of the things I’ve learned in the first few days of this research.
Thing #1: Ethereum 💎
I didn’t expect this to take very long on Ethereum. I’m very familiar with Ethereum and I’ve built and deployed production applications on the platform before. I know how to use the wallets and testnets and I even have testnet coins (which for silly reasons can be hard to come by). And while it’s been a couple years and the tooling wasn’t so great the last time I checked, I imagined it must be a lot better today.
Strictly speaking if I had been in a rush and had simply tried to work as quickly as possible using only tools I’m familiar with, I probably could’ve finished in a couple of hours. But I haven’t written or deployed a smart contract on Ethereum in a while and lots of new tools have emerged since then, so I wanted to try using newer tools. There were a couple of tools in particular that looked helpful and that I thought would make the task easier, but this ended up being a wild goose chase and in the end I wasted a lot of time on half-broken tools.
I started with ERC-20 templates from OpenZeppelin, the gold standard. OpenZeppelin even has a nifty interactive token creator tool that lets you design token contracts with features like pausable, flash minting, etc.. But on Ethereum the problem wasn’t going to be the smart contract code: it’s simple, I’ve written it before, there are good templates, etc., so this part only took a few minutes. The problem was deploying it.
OpenZeppelin also offers a new tool call Defender that, in theory, allows you to manage the deployment and security of smart contracts on various chains and in various environments including production and testnet. It’s a great idea and would be wonderful if it actually worked, but I ended up wasting at least a couple of hours trying to get it to work. It turned out that the documentation was sadly out of date and that key pieces of information like RPC endpoints were wrong. It also required setting up a Safe just in order to set up a deployment environment, which makes no sense and was also a waste of time. I had errors simply logging into Defender from time to time. I eventually found instructions and figured out how to deploy to Defender from the command line but when I tried to do so I ran into errors and the deployment hung. There was no useful debug output. Eventually I gave up on Defender.
I also tried a framework called scaffold-eth-2 that I had been excited to try for a while. The framework is designed as a one-stop-shop for local development, testing, and deployment of not only smart contracts but also a basic web app that talks to the smart contract. Out of the box you get nice features like an auto-generated debug UI that lets you interact directly with your smart contracts, a local network (which allows totally offline development: think of a hackathon with dodgy wifi), and a built in block explorer. While the goal of the project wasn’t to do frontend work, I figured if it’s easy, why not try and give the project a very basic UI?
Unfortunately I ran into a lot of issues with scaffold-eth-2 as well. It worked out of the box with the Hardhat framework but I wanted to try Foundry since it’s newer, and a bug with the foundry integration threw me off. I also disliked the fact that the default wallet used by the frontend (which comes from a burner wallet) isn’t the same as the funded wallet accounts created by the localnet, which also threw me off and meant that not all of the smart contract interactions even in the basic demo worked correctly.
After wasting more time on scaffold-eth-2 I gave up on the frontend idea entirely (I may go back later and try to add frontends, since the frontend-backend integration is critical too) and fell back on a simpler foundry template that I found that didn’t include a frontend or any fancy web app gizmos. I plugged this into an Alchemy RPC endpoint and was off to the races. Everything was up and running in under an hour.
Time spent: ~6 hrs
Tools used: Foundry, foundry-template, Alchemy RPC
Lines of code: ~10 for contract, ~10 for deploy
Hardest part: Wasting time on tools that don’t quite work and out of date docs. Learning the basics of foundry and its associated tools. I like it and it’s quite powerful but it has a steep learning curve.
Lessons learnt: The Eth/EVM ecosystem is unique in how many competing tools and frameworks there are, but many aren’t quite there yet, are buggy, have docs that are out of date, etc. A buggy tool or one that isn’t well documented is worse than no tool! Keeping docs and integrations up to date is absolutely essential and it’s a lot of work as things change rapidly in this ecosystem.
Thing #2: Solana 🚀
I was especially excited to try developing on Solana for the first time since I had heard many good things (and some scary things!) about it at Breakpoint last year and hadn’t had the opportunity yet. I was also keen since I’m a big fan of Rust and Solana contracts are written in Rust.
I had heard that developing for Solana is quite different than developing for Ethereum and this turned out to be very true for a number of reasons. The first is the Solana CLI. Unlike Ethereum (but like every other project that I tested) Solana has an official CLI tool that can be used to do things like create program templates, create and fund accounts, deploy programs, check balances, send transactions and interact with programs, run a local testnet, etc. In Ethereum terms the CLI tool and the Solana Test Validator are like foundry or hardhat.
This is a mixed blessing. It’s convenient to have a CLI tool for basic chain interactions but the tool talks to a single, centralized RPC endpoint. Solana has been having severe issues clearing transactions recently and, while I assumed the issues were isolated to mainnet, I also ran into issues submitting transactions to the devnet. Whenever I tried to deploy a program to the devnet the deploy script would hang with no output; verbose mode provided no additional information. Ethereum tools like foundry require you to obtain and provide your own API key, and you can configure them to talk to any RPC endpoint including your own node. While I’m sure it’s theoretically possible to repoint the solana CLI tool at a different RPC server, I wasn’t able to find any other public devnet endpoints.
The biggest difference between Solana and Ethereum, however, is the Solana account model. I had been warned about this and the warnings didn’t disappoint. In Ethereum a smart contract account manages its own state: that is to say, it contains both code and state. The most common example of this is a fungible ERC-20 token contract which contains not only the code for minting, transferring, burning, etc. but also a mapping of addresses to the number of tokens each address owns. In Solana, by contrast, an account contains either code (called a “program”) or data but not both. All state is owned by an account and each piece of owned state lives in its own account. The architecture of the Solana equivalent of an ERC-20 token, the SPL token, is therefore quite different. The balance for each holder is stored in a different account.
There are benefits and disadvantages to each model. The Ethereum model is simple but requires expensive indexing to calculate what each account holds since these data aren’t all stored in any one place. What’s more, it makes things like charging state rent difficult since state “owned” by many tokenholders is all commingled in a single contract’s storage, so it’s unworkable to expect each tokenholder to contribute to paying rent. (The situation is even more difficult in the case of a more complex multi tenant smart contract like a DEX. I have no idea how this is done on Solana!)
The Solana model is a bit more elegant from a data ownership perspective but it comes at the cost of complexity. The basic code for common fungible token transactions like mint, transfer, burn, get balance, etc. is tiny, intuitive, and easily readable in the case of Ethereum, involving as it does only token balances, accounts, and lookup tables. The same code in Solana is monstrous. A single function may touch five or six different accounts. The addresses/public keys for these accounts and their signing credentials need to be provisioned ahead of time, a process that’s byzantine and opaque. The account addresses need to be dynamically computed. For instance, to calculate the number of $SPUD coins that Alice has, you need to do something along the lines of checking the balance of the account at HASH($SPUD, Alice). For the purposes of this exercise I tried to focus on just the bare essentials and not on gaining a perfect understanding of the Solana architecture, but even the most basic tutorials spent a lot of time on this topic.
There’s a framework called Anchor that helps a bit and handles some of the boilerplate logic for you, but I also had trouble getting it to play nicely with the rest of the Solana tooling. The default installation of Anchor was incompatible with the default Solana SDK; I had to upgrade several times to the “edge” version to get it to work at all (this wasn’t documented). I also found the Anchor docs to be woefully inadequate. I ended up using another framework called Metaplex to create tokens, but ran into further incompatibility issues here. It didn’t help that all the documentation refers to an old, deprecated version of Metaplex. Getting the Solana SDK, Anchor, and Metaplex to play nice around things like “providers” and “signers” was a real headache and I spent not a small amount of time stuck on this. Note that the Eth deploy code, mentioned above, was much shorter because foundry handles these things for you.
In the end I found an excellent tutorial and the Solana playground, both of which I relied upon heavily. I was never able to get program deployment working locally but it did work through the playground. Unfortunately the playground uses some magic syntactic sugar and when you export the code and try to run it locally, nothing works—it took a lot of work even to get the programs to compile, and this may have been at least one source of my deployment headaches.
Nevertheless I was able to write and deploy the necessary code using the playground. I appreciated the fact that Solana has a standard program library that includes SPL tokens, so it’s not actually necessary to deploy any program to create a basic token unless you want to change the logic. In fact you can do the entire job in a few lines of Typescript, which isn’t possible on Ethereum.
I also found the Solana explorers (there are two) to be pretty difficult to work with. Even after successfully deploying, minting, and transferring SPL tokens, the explorers refused to display the token metadata correctly (this was also a problem with other networks). Unlike Etherscan, the Solana explorers don’t provide enough information on each transaction. You can’t even tell at a glance what a transaction does. After working with Solana for a few hours I began to realize how much I tend to take Etherscan for granted on a day to day basis.
I found working with Solana to be eye opening, a bit like trying to learn Chinese after spending my entire life speaking English. Solana does many of the same things as Ethereum but it goes about them in totally different ways, and in ways I didn’t even know were possible. It was eye opening and fun, if frustrating.
Time spent: 8-12 hrs
Tools used: Solana CLI, Solana SDK, @solana/web3.js, Anchor, Metaplex, Solana Playground
Final product: code, token (note that the explorer refuses to show transfers for this coin)
Lines of code: ~20 for contract, ~70 for deploy
Hardest part: Trying to understand the basics of the Solana account model. Trying to get the code from the Solana playground to work locally.
Lessons learnt: Having many competing Javascript/Typescript tools and frameworks is nice, but it can be a major headache when they don’t play nice, when versions misalign, etc. Good, up to date documentation is key here as well. So are good chain explorers—and Solana has work to do here. Finally, standard, core program templates make a lot of sense.
Thing #3: Aptos 🧢
I was also very excited to try writing and deploying a contract to one of the Move chains. The two largest and most popular are Sui and Aptos, both of which inherited Move (and much else besides) from the now-defunct Libra/Diem Facebook blockchain project and both of which made some changes and improvements to vanilla Move. I’ve been skeptical of both projects since the beginning as both felt more like overhyped VC pump and dump schemes than organic, community-driven projects (to be fair, Solana started this way too). That skepticism hasn’t faded, and indeed both projects had issues and faced criticism when they launched, but it’s nevertheless important to separate hype and particular, flawed instantiations of a given technology from the underlying technology itself and there’s a lot of interesting technology in the Move ecosystem that’s worth taking a closer look at.
I chose between Aptos and Sui more or less randomly and decided to try writing and deploying a smart contract for Aptos. Like Solana, Aptos has an official SDK/CLI tool maintained by the Aptos Foundation. I appreciated that the documentation is good and up to date, which is unfortunately quite rare. It’s also nice that there are SDKs, sample code, and tutorials in three languages: Typescript, Python, and Rust. I was able to get my first transaction working in only a few minutes and everything seemed to work out of the box—and the sample transactions landed on the actual devnet so I was able to track everything using the official explorer. So far, so good.
Then I began to run into an issue very similar to the one I ran into with Solana: devnet transactions mysteriously began to fail. As with Solana and its CLI tool, the Aptos CLI tool talks to a centralized RPC backend, which is less than ideal since that backend can (and obviously does) go down. As with Solana I’m sure it’s possible to talk to a different RPC endpoint, but as with Solana I failed to find another public devnet RPC endpoint.
Tooling and documentation aside I found Move to be my favorite among all the languages and Rust DSLs that I worked with as part of this project. Despite being quite unique, I found Move intuitive, easy to read and easy to work with—more so than the obtuse Solana account-related code mentioned above—and I found that it lived up to its hype as the best blockchain-specific programming language. Blockchain programming is a very specific kind of embedded programming that requires a different mindset, different considerations around security and game theory, different optimizations, etc., and as much as I like Rust it’s just not as well-suited out of the box to the blockchain use case as a bespoke language and account model like Move. Having data structures (move calls them resources) that are themselves permissioned, have clearly-defined ownership, etc. makes a lot of sense and makes smart contract programming in Move a lot more ergonomic than in other languages.
Like Solana, Aptos also has an enshrined fungible token contract that makes it trivially easy to deploy a fungible token. In fact, Aptos even goes a step further and has a standard that describes how you can deploy No-Code Digital Assets, which is about as close to best practice as you can get. I ended up deploying a contract anyway just as a test, and thanks to the managed_coin framework and inheritance the final code is laughably short and simple (like the Eth code above). Writing the glue code in Typescript took much longer and was much more complicated, albeit less complicated than on Solana. A big part of this was code required to manage keys and accounts, which was a theme across all the chains I worked with. As with the others I felt that the SDK could have done a better job of streamlining this process. As with Solana, as a result the deploy code was substantially longer and more complicated than on Eth.
Overall I give Aptos a lot of credit not only for using Move but also for having the best documentation, tools, and examples/tutorials of all the blockchains I worked with as part of this project. There’s a lot to admire and learn from. Like Solana, Aptos has the advantage of a good playground and at least one good ecosystem wallet (I only tested one).
One important caveat is that like Solana I didn’t have time yet this week to go very deep and understand what’s going on under the hood in Aptos or the Move VM. As with Solana, my biggest complaint is the Aptos explorer: while functional, I found it very difficult to understand what’s actually going on. I appreciated once again the importance of a good chain explorer and how much we take Etherscan for granted.
Time spent: 4-6 hours
Tools used: Aptos CLI and Typescript SDK, managed_coin template
Lines of code: ~10 for contract, ~100 for deploy
Hardest part: Wrangling Typescript glue code.
Lessons learnt: The elegance that can be achieved with a blockchain-specific language like Move; the importance (yet again) of a good explorer.