Jump Into Solana — for EVM devs

I started with EVM development and then learned Solana development after two years. It was different in many senses, so I want to highlight some of the differences. Note: This is a developer's guide.
(Content will be corrected & updated as I get more time on hand...)
A crude analogy
An EVM contract is a class, a Solana program is a function.
Consider a contract (in TypeScript) that sets and returns money
value. You might notice that the EVM contract is stateful, while the Solana program is stateless.
// EVM contract
class Contract {
private _money: number;
public getMoney() {
return this._money;
}
public saveMoney(m: number) {
this._money += m;
}
}
// Solana program
function Program_getMoney(money_storage: Account) {
const money = money_storage.bytes.slice(0, 4);
return parseInt(money);
}
function Program_saveMoney(money_storage: Account, m: number) {
money_storage.bytes[0] = m;
}
Stateful vs. Stateless
EVM contracts hold some data, while Solana programs don't hold any data. You can sort of think of it as running AWS EC2 vs. serverless Lambda.
Example: Token
On EVM, an ERC-20 contract stores the ledger of user balances. When an app needs to know the balance of its users, it calls balanceOf(address)
to query the in-contract ledger.
On Solana, programs don't store any data — there's no ledger to track the balances! Instead, we directly input all the necessary data to the program every time we call it. Thus, the sole purpose of a program is to take in some data and modify them.
Q: Where do we store those data?
A: Accounts!
Accounts on Solana
Accounts are some blobs of data on Solana exposed by its public address. Everything on Solana is an account, for example:
- User's wallet (signable by private key)
- Program (executable data)
- Some other data (to be used in programs)
In fact, SVM is a generalization of EVM: A "contract" is an account holding both the program (executable data) and "some other data" used in the program.
Rents for Accounts
When accounts are created on Solana, they need to store a minimum amount of SOL to meet "rent exemption." From the official doc:
Keeping accounts alive on Solana incurs a storage cost called rent because the blockchain cluster must actively maintain the data to process any future transactions.
This is different from Bitcoin and Ethereum, where storing accounts doesn't incur any costs.
If an account's SOL balance stays below the minimum rent-exemption amount, the account will eventually get purged. You can also "close" an account, which destroys the memory allocated for its data and returns the rent-exemption SOL (to the creator of the account).
"Everything is an account" enables parallelization
Imagine 1000 contracts are trying to read Bob's USDC balance to determine if he's a whale, all at the same time.
On EVM, 1000 contracts read the USDC balance sequentially (one by one). Contract_A reads Bob's balance, then Contract_B reads the balance, then Contract_C, ...
On Solana, 1000 programs read the USDC balance in parallel (all at once). SVM does some magic, and now Contract_A, Contract_B, ... reads Bob's balance at the same time.
Here's Mr. Bean. He counts the sheep one by one. Soon enough, he realizes that none of them moves (value isn't changing), so he counts them all at once... sort of.
No msg.sender
or tx.origin
Calling a function on SVM program is just passing all the necessary accounts, which means the program has no context of "who is calling" itself. On EVM, we get msg.sender
and tx.origin
because a transaction is always initiated by EOA (user wallet).
On SVM, the closest we have to msg.sender
is "is_signer = true" flag for the input accounts.
Hotspots + Local Fee Market
On EVM, everyone pays the same gas fee, plus the tips. All transactions have their positions in a block, and they get executed sequentially (hence the example above). All contracts are accessed at most once per transaction in EVM!
On Solana, accounts are accessed many times simultaneously! As long as no one is modifying an account's data, SVM can guarantee that the data will be the same for all those accesses.
Hotspots are programs that are accessed many times for writes. If 100 programs try to write to an account (e.g. NFT mint program) at the same time, it becomes a hotspot. SVM can identify hotspots and mitigate chain congestion by introducing a local fee market.
hotspot => write contention for accounts
Write contention. https://t.co/eg3bjARQYl
— toly 🇺🇸 (@aeyakovenko) July 4, 2022
Local Fee Market
Recall that EVM has a one-gas-fee-for-all-users model. SVM can create multiple fees for particular users of the chain, by introducing localized fee markets.
The APE sage, EVM vs. SVM
It's 2021, and the APE token mint is going viral. Everyone is calling the "mint" function, paying crazy amounts of tips.
On EVM, the gas fee skyrockets to $100+. EVERYONE has to pay that gas to get their transactions included anytime soon. If you're trying to buy coffee with USDC, well, you need to pay $100 to pay $5.
On SVM, the APE program is categorized as a hotspot and gets a limit on how much block space it can occupy. All minters fight for that limited sub-block space, while other non-minters can use the rest of the block space for sub-cent transactions.
Programs deal with Accounts
So, "everything is an account" is unique in Solana. For programs to work correctly, they need to know which accounts they can modify.
For example, to transfer tokens, you have to input some data accounts like:
user_account = readable, signer
user_another_account = readable, writable (mut)
user_associated_token_account = readable (mut)
Wait... what is an Associated Token Account (mut)?
> Let's dive into PDA first.
Program Derived Address (PDA)
From Anchor's doc:
Unlike normal addresses, PDAs are not public keys and therefore do not have an associated private key. There are two use cases for PDAs. They provide a mechanism to build hashmap-like structures on-chain and they allow programs to sign instructions.
PDAs don't have any private key associated — they are accounts owned by programs (as the name implies), which are also accounts. You get PDAs by deriving the public key using "seeds" (words) and bumping them off the elliptic curve.
A rough analogy: a PDA account is a programmable EOA/Contract on EVM, where the owner is a contract!

How do we "prove" that a program owns a PDA account? The seeds used to derive the PDA include the program's ID (contract address). SVM ensures that PDAs are marked as writable (content can be modified) only when the signer's ID matches the program ID in the seed.
One prominent use case of PDA is:
"Associated" Token Accounts
One question I had when learning Solana: If there's no ERC-20 contract storing the balance of each user on Solana, how do we know who owns how much?
Answer: There are programs called Token Program and Associated Token Program (ATP). In particular, ATP manages PDAs that store the token balance of each user.
Token Program allows creating and interacting with SPL tokens. Here, the SPL token is like the ERC-20 standard. ATP creates and controls Associated Token Accounts (ATA), which are PDAs!
An ATA stores the token balance of a user. Revisiting the token example, if you need to transfer Alice's USDC to Bob, you need to input the following accounts:
- USDC token "mint" — stores all metadata of a token, e.g. total supply
- Alice's ATA — stores the Alice's USDC balance
- Bob's ATA — stores the Bob's USDC balance
- Token Program — debits Alice's ATA & credits Bob's ATA
- Associated Token Program — manages ATAs
Token Accounts
ATP is the recommended way to manage the token balance of users, but not the only way. In fact, ATP is just an abstraction to manage Token Accounts, which stores the token balance of each user.
When ATP creates (associated) Token Accounts, it derives the PDAs from its program ID. Thus, ATAs are only modifiable by calling the ATP's functions. This, by design, ensures that the token accounts are handled correctly.
You can also write a program that derives your own PDA for Token Accounts. Those PDA accounts would be owned by the program.
Token Mints
Token mints are accounts that hold the token's metadata, e.g. USDC's total supply and mint admin (authority). The name is a bit confusing because it sounds like it can "mint" like EVM, but it's actually just a blob of data for a token.
Anyone can pay for transactions!
EVM requires the contract caller (EOA) to pay for the transaction fee.
On Solana, there is a feePayer
attached to a transaction that pays for the fee. Usually, the feePayer is set to the person sending the transaction. However, one straightforward application is:
- Alice signs a transaction to transfer USDC to the app
- App receives the signed transaction, attaches it as a
feePayer
and signs it - App sends the transaction to the blockchain
Transactions can have more than one smart contract call!
On EVM, a transaction is atomic. If the transaction interacts with a smart contract, it packs the function signature, followed by the parameters.
On SVM, interactions with a program (smart contract) are known as instructions, which are atomic. Instructions can be packed into a transaction, which has a limit of 1232 bytes. So, if there are three instructions of size 300 bytes each, you can send them as one transaction!
No Re-entrancy
EVM allows unlimited re-entrancy for smart contracts, often leading to re-entrancy exploits. SVM has a call stack limit of 4, meaning that cross-program invocations (CPI) are limited.
No Hardhat or Foundry, but Anchor!
Yeah, there's no beloved Hardhat or Foundry on Solana. But there's the Anchor framework, which makes developing on Solana much easier!
A crude comparison: Anchor is like Solidity.
Well, then programming in raw Solana Rust is like Yul on EVM. It's great if you care about optimization or other super-detailed things. Otherwise, it's much better to stick with Anchor (Solidity) for general purposes.
also:
— buffalu (@buffalu__) September 4, 2023
- you can write programs in rust, c++, c, and python via @seahorse_lang
- afaik most people use @anchorlang but if you're compute constrained or want more control under the hood you can write with raw program entrypoints (see @PhoenixTrade_ + SPL programs for examples of…
Compute Units, not Gas
On Solana, any atomic actions like addition or subtraction use some "compute unit," or CU. So, calling a function (instruction) on a Solana program costs some compute fees.
Which brings us to:
Compute is MUCH CHEAPER than Storage
Solana's main storage lives on RAM, not SSD. This enables much faster execution at the cost of limited on-chain storage for nodes.
On EVM, compute is cheaper than storage, but the difference is much bigger on Solana.
Programs are upgradable by default
Because programs are stateless, upgrading is just replacing the old code with the new code. This is very different from EVM, where you need intricate approaches like proxies and storage management to enable "upgrading" programs.
One extremely under-appreciated feature of Solana is native program upgradability.
— Jongwon 👨🍳 (@jwpark02) September 1, 2023
Ethereum proxy and upgrades are nightmares, e.g. storage collisions and exploits from improper upgrades.
Solana programs are stateless, so upgrade is a breeze. Shocked me when I first touched it
RUST RUST RUST
You write Solana's programs in Rust (or C, if you insist). But if you insist, you can use Solang to mimic that EVM development experience, to a certain degree.
✨ 𝐄𝐑𝐂-𝟐𝟎 𝐨𝐧 𝐒𝐨𝐥𝐚𝐧𝐚 𝐉𝐔𝐒𝐓 𝐖𝐎𝐑𝐊𝐒 ✨
— Jongwon 👨🍳 (@jwpark02) July 21, 2023
Transfer costs
❏ $0.000125 on Solana
❏ $4 on Ethereum
Solidity, but 𝟗𝟗.𝟗𝟗𝟕% 𝐜𝐡𝐞𝐚𝐩𝐞𝐫https://t.co/DBCgxfbgTg pic.twitter.com/GRXDmonIDd
The Solana community is full of stellar and thoughtful yet generous people. For example:
I'm interested in Solana, heard the grass is greener. Anybody got any connections?
— Will Chen 🌖 (@stablechen) September 3, 2023