A Guide to Solana for Ethereum Analysts
Translating EVM concepts to their Solana counterparts
If you’re an analyst in the Ethereum ecosystem, you’ll probably have a rough time trying to understand Solana. Many concepts you’re used to are honestly very different. But don’t worry; this guide is here to save you some headaches!
I’m going to cover three types of parallels:
Transactions: how should I think about blocks, functions, events, accounts, etc?
Contract Patterns: how are contracts structured, and what standards exist?
Protocol Counterparts: who are the lido, uniswap, blur, etc on Solana?
Each section will follow the format of:
EVM Concept Name: Solana equivalent and explanation
Don't hesitate to contact me if there is an EVM concept you’re looking for a parallel for that I have not covered (or is in here but still confusing).
I’ve covered the basic Solana concepts with example tables and queries in my four-part guide:
Blocks: blocks on Solana are confirmed every 400ms, in “slots”. You may notice that the block “slot” and “height” are different in solana.blocks, this is due to slot skipping. Staking rewards are distributed to validators every “epoch” which is 432,000 slots or roughly 2-3 days.
Wei: The smallest denomination of SOL is a “lamport” which is 9 decimals. Most fungible tokens are also 6 decimals by default, not 18.
Hexdecimals/Binary: Data in Solana is mostly represented as base58. You can convert this to hex to work with it like you do EVM data using from_base58().
Proof of Stake & Attestations: Solana uses delegated proof of stake by default to secure validators. Validators then vote on blocks using a “Proof of History” mechanism for confirming slots (leaders shift every epoch). This all happens on the base chain, giving two transaction types: vote and non-vote. Read more.
Addresses: addresses are stored as base58 hash, but if you convert them to hex you still get a 32-byte hex address. These are sometimes called “accounts”, and there is a special kind of account called a “Program Derived Accounts” (PDA) you will come across.
PDAs have to pay rent in a small fee per block to prevent state bloat. If you top up a PDA with enough rent, then fees aren’t deducted from the account.
Smart Contracts: These are called “programs” instead. All programs are deployed using the BPF uploader, which lets you upgrade programs anytime. We use “solana.programs” for decoding, instead of ethereum.contracts. Instead of CREATE, you have system createAccount as an equivalent.
Transaction “data” or “input”: These are called “instructions” on Solana. If you are familiar with multicall transactions on EVM, consider this the default on Solana. Every transaction will have many “data” fields in a nested array of “instructions”. Think of the outer instruction as the first instruction (like a uniswap route call) that then kicks off the inner instructions (all the pair swaps). You can learn to work with instructions in this guide, we have unnested them in the table “solana.instruction_calls”.
Addresses such as token transferred, trading pool, multisig, etc - are all passed in an array of “account arguments” as part of instruction data. I cover working with these in the guide linked above too.
From/To: From is going to be the signer/tx_signer. To will be the executing_account of any given instruction. You will notice an outer and inner executing account. The executing_account column is essentially coalesce(inner_executing_account,outer_executing_account). You should use the “solana.instruction_calls” table to easily filter on these columns.
Traces: Because instruction data is stored in a nested array, you don’t get the same nice pattern of ethereum.traces you are used to. We have an unnested table solana.instruction_calls you can use instead. The program being called is the “executing_account”, passing along the function/variables in “data”.
Trace address: Getting the call lineage (the depth of the call and also who called who) is not simple. You would usually use cardinality(trace_address) and from/to in Ethereum for this. In Solana, this is called a “cross program invocation” (CPI). One way is to extract this is parsing the “invoke [x]” from log_messages. This is sometimes called “stack height” as well, and currently can be a maximum of four. We’re working on a method to have this as a column in raw/decoded tables.
Function Signatures: You get discriminators instead. These can be 1 byte, 4 byte, or 8 bytes long depending on if it is an enum, native, or anchor program. You can use the “solana.discriminators” table to identify these, like I did in this query. I’ll talk about program types in the next section.
Event Signatures: Events are mostly in log_messages. Some of them are just text outputs with no signature to trace them to, others do have discriminators. There is also a pattern called Event CPI that puts events into instructions in a self-call. I wrote a longer guide on these different types of events. Dune does not have events decoded or event discriminators stored in a table yet.
Gas: instead of “gas” you have “compute units” which can be found emitted per program in log_messages. Native programs (system, stake, vote) don’t use up compute. I made a dashboard covering compute.
Gas Fee: There is no “gas price” because usage based pricing is not implemented on Solana yet. There is a flat fee per signature (tx) of 5000 lamports. Priority fees can be optionally added to each transaction, by calling “Set Compute Unit Price” (see instruction #2 here). 50% of transaction fees are burned, and 50% of rent fees too. You can find the epoch totals in the “solana.rewards” table.
Numbers: Numbers on Solana are stored in little endian instead of big endian. This just means you need to use bytearray_reverse() on any raw hex data before doing the normal bytearray_to_decimal() call.
Transfer: For the most part, you can use spl_token transfer/transferChecked decoded tables for this. However, there are some instructions that don’t have a transfer instruction called (like stake merging). In these cases, you need to rely on “solana.account_activity” for pre and post tx balances.
Balances: Token balances are stored per tx (pre and post) in “solana.account_activity”. We also have “solana_utils.daily_balances” and “solana_utils.latest_balances” for faster queries. You may be confused about the token balance schema here, I’ll explain it in the next section.
I’ll be hosting some live learning sessions for Solana soon, make sure to subscribe to stay up to date!
Solidity: Solana Programming Language (SPL) is the base rust crate used to write programs, Anchor lang was built as an abstraction on top. Native programs are written in SPL. Many older programs are written in SPL too. Most programs now are written with Anchor. I explain program types in this guide.
ABI: Anchor programs are given an IDL. You can convert SPL programs to an IDL, with some manual work. Many protocols upload their IDL onchain with the deployment, but unfortunately, some don’t. You can still try googling for their rust repo, like the Openbook repo. And no, there is no easy-to-read source code finder like Etherscan has. Try googling the pattern “protocol name rust docs” and see if it pops up - usually works.
Factories/Proxies: The main protocol program is the one that creates subaccounts (PDAs). In my first guide I showcase how for a new trading pair on the whirlpool DEX, it calls the whirl program to create the pair, token vaults, fee account, and more. Every swap or liquidity add/removal on the new pair still calls the whirl program. So it acts as the factory, and also as the proxy (in terms of forwarding along calls). Every protocol on Solana follows this pattern.
Storage: Data is stored in binary buffers (strings) on accounts, instead of storage slots. Usually, you end up with a nested/tree structure of accounts (PDAs) to store different relationships of data with the main program. This is why when you look at the creation of tokens or pools (or anything else), you’ll notice that like 5 other accounts also get created alongside it. I use this query to help find the creation transaction for an account, which usually tells me the key accounts that are holding related data.
Tokens: This is probably the hardest thing for you to initially wrap your head around. All tokens are deployed from a spl_token program (or the new token2022 program). Balances are stored in associated accounts, which act as the “balance mapping” you are used to. Learn about tokens and associated accounts in this guide on fungible tokens and then this guide on NFTs.
Staking: Staking on Solana is liquid by default. Anyone can create a “stake account” of any balance and delegate it to any validator. Pools can then be built on top. For stake accounts, reference the table “staking_solana.stake_actions”. For liquid staking, check out my guide.
ERC Standards: They don’t exist 🙃. This is one of my biggest gripes with the ecosystem. Things constantly just release, break, and adapt across protocols.
EIP Core standards: Changes to Solana’s core code go through “feature gates” in the Solana repo. Yes, it’s much less organized than the EIP pages you are used to, and a headache to understand or keep up with. A cost of the speed of development, I’m told.
To find the decoded tables you need, you can plug in any tx id here to see this:
Here are the closest matching protocols for the ones you are used to in EVM. I will note that protocols on Solana are more monolithic, meaning they tend to do many things simultaneously instead of just lending or trading.
If there is an EVM protocol type that I’ve missed, feel free to reach out to me and I’ll add it in with the Solana counterpart in below.
I’ve put a 📊 next to any protocols there is a Dune dashboard for.
MakerDAO/Dai → USDH Hubble.
Chainlink Oracles → Pyth 📊
Gnosis Safe (multisigs) → Squads Protocol 📊
Zora/Mintdotfun → Metaplex Candy Machine 📊
Opensea → Magiceden 📊
Blur → Tensorswap 📊
0x/1inch → Jupiter.ag 📊
Uniswap → Orca Whirlpools (yield farming built in) 📊
A majority of DEXs on Solana use fully onchain limit order books due to low fees/high tx speeds. Openbook, Raydium, Phoenix, etc.
Yearn Vaults/Arrakis/Morpho → Kamino Finance
Lido → Stake Pools (Marinade Finance, Jito Sol, etc) 📊
Deposit2 Contract → Stake Native Program
Flashbots → Jito Labs 📊
Bridges → Mayan Finance (and more built into Phantom, Jupiter, etc)
ENS Names → SNS Names (solana_utils.sns_domains)
Unibot → Bonkbot 📊
And some data tooling counterparts too:
Alchemy/Quicknode → Helius
EVM Quickstart → Solana Quickstart
You’re now Solana fluent (kinda)!
Hopefully, this makes it easier to start working on Solana data and reading different project docs. Again, don't hesitate to contact me if there is an EVM concept you’re looking for a parallel for that I have not covered (or is in here but still confusing).
As a next step, go through my four-part guide for some hands-on SQL queries: