# Becoming an EVM Expert

By [hatem.eth](https://paragraph.com/@hatem) · 2024-05-16

---

Becoming an EVM Expert - The Hard Way
=====================================

There’s a large learning curve to learning blockchain development because it’s so different than web2 programming paradigms. Instead of writing code that runs on one computer, you’re writing and interacting with code that runs on a distributed network

To deeply understand blockchain development, we’ll want to look at the virtual machine (VM) that’s used. There’s a couple different virtual machines that different blockchain’s use including [Sealevel](https://medium.com/solana-labs/sealevel-parallel-processing-thousands-of-smart-contracts-d814b378192) (Solana), [CosmWasm](https://cosmwasm.com/) (Cosmos), [Wasm](https://wiki.polkadot.network/docs/learn-wasm) (Polkadot), Move VM (created by Facebook for Diem and will be used by [Sui](https://sui.io/resources-move/why-we-created-sui-move/) and [Aptos](https://aptos.dev/guides/move-guides/move-on-aptos/)).

The most popular virtual machine, though, is the Ethereum Virtual Machine or EVM. It has the largest number of applications and support from some of the largest blockchains including Ethereum, Polygon, Avalanche, Near, Optimism, and Arbitrum to name a few.

This guide is designed to get you up to speed on advanced concepts extremely quickly. It should take about 10 hours of deeply focused work to get through but you’ll come out of it with a great knowledge of the EVM.

1\. The Basics
==============

_Some of the basics to understand on Ethereum_

For a deeper dive into most of these topics you can go to [https://ethereum.org/en/developers/docs/intro-to-ethereum/](https://ethereum.org/en/developers/docs/intro-to-ethereum/)

*   [**Public Key Cryptography**](https://en.wikipedia.org/wiki/Public-key_cryptography): Blockchains rely on public key cryptography to prove ownership of assets and to create transactions. Public key cryptography uses a key pair which consists of a public key and a private key. The private key is kept secret and is used to digital signatures and can derive the public key.
    
*   [**Hash**](https://en.wikipedia.org/wiki/Cryptographic_hash_function) **Function**: a cryptographic function which creates a unique digital identifier (hash) for a piece of data.
    
*   **ether (ETH)**: The native token on Ethereum which is required to pay for transaction fees.
    
    *   wei: the smallest denomination of ETH. `1 ETH = 10e18 wei`
        
    *   gwei. `1 ETH = 10e9 gwei`.
        
*   **Ethereum Account**: An entity that can send transactions. Accounts are either external owned (EOA) and controlled by a private key or they have code associated with them (i.e. it is a smart contract)
    
*   **Ethereum Address**: The public identifier of an ethereum account is it's address. The address is the keccak256 hash of an account
    
*   **Walle**t: a wallet is a piece of software that controls a user's private key. More advance wallets like [MetaMask](https://metamask.io/) provide an easy way to connect to dapps and send transactions.
    
*   [**Transaction**](https://ethereum.org/en/developers/docs/transactions/): A signed instruction from an account
    
*   [**Block**](https://ethereum.org/en/developers/docs/transactions/): A batch of transactions that includes a hash of the previous block in the chain.
    
*   [**Gas**](https://ethereum.org/en/developers/docs/gas/): a unit of measure for how computationally intensive an operation is on Ethereum. The amount of gas a transaction requires is used to calculate the transaction fee a user must pay to execute a transaction.
    
*   **Gas Price**: The amount of ETH a user pays per unit of gas to execute a transaction. Gas Price is typically measured in gwei.
    
*   [**Ethereum Node**](https://ethereum.org/en/developers/docs/nodes-and-clients/): a computer running the software for the Ethereum protocol
    
*   [**Json-RPC**](https://ethereum.org/en/developers/docs/apis/json-rpc/): A lightweight remote procedure protocol (RPC). Ethereum nodes an expose their json rpc api so that clients can query the state of the blockchain.
    

Token Decimals: [https://docs.openzeppelin.com/contracts/2.x/erc20#a-note-on-decimals](https://docs.openzeppelin.com/contracts/2.x/erc20#a-note-on-decimals)

2\. Your First Smart Contract
=============================

We’re going to use [Foundry](https://book.getfoundry.sh/) to create your first smart contract. Foundry is a rust-based smart contract development toolchain created by [Georgios Konstantopoulos](https://twitter.com/gakonst) that’s new but very well liked. There’s other smart contract development environments which I’ll split into 2 categories:

1.  Pure Solidity: Tests are written in Solidity
    
    1.  Foundry
        
    2.  [DappTools](https://dapp.tools/)
        
2.  Javascript Based: Tests are written in JS/TS
    
    1.  [Hardhat](https://hardhat.org/)
        
    2.  [Truffle](https://trufflesuite.com/)
        

For your first smart contract, we’re going to create an [ERC20](https://eips.ethereum.org/EIPS/eip-20) token which is the standard interface for fungible tokens on EVM blockchains. You won’t be expected to understand a lot of what’s happening under the hood, which is fine because we’re just trying to quickly expose you to a bunch of different concepts in EVM development.

Pre Requisites
--------------

Go to the Foundry [installation page](https://book.getfoundry.sh/getting-started/installation) and follow its directions to install Foundry. If you’re successful you should be able to run the following command.

    $ forge --version
    # Output should be something like
    # -> forge 0.2.0 (60b1919 2022-07-24T00:08:10.658215Z)
    

`forge` and `cast` are the two binaries that `foundryup` installs and running `forge version` only returns the version of forge if forge is successfully installed.

Setting up the Project
----------------------

### Create the Project

Follow the [instructions](https://book.getfoundry.sh/getting-started/first-steps) in the Foundry docs to set up your first project.

### Install Dependencies

We’re going to use [transmissions11’s](https://twitter.com/transmissions11) [Solmate](https://github.com/transmissions11/solmate) repo as a dependency. Solmate is a collection of common smart contracts that are helpful for using as building blocks. Solmate is gas-optimized (a.k.a. it’s written so people spend as little as possible on transaction fees) and already audited which reduces the surface area for a vulnerability and the cost of an audit for your project.

    $ forge install transmissions11/solmate
    

### Create the Token

Rename `src/Counter.sol` to `src/FirstToken.sol`. Open up src/FirstToken.sol in your editor and copy in:

    // SPDX-License-Identifier: UNLICENSED
    pragma solidity 0.8.13;
    
    import { ERC20 } from "solmate/tokens/ERC20.sol";
    
    contract FirstToken is ERC20 {
        constructor(uint256 totalSupply) ERC20("First Token", "FT", 18) {
            _mint(msg.sender, totalSupply);
        }
    }
    

Let’s quickly go over what is happening in the contract.

*   Line 2: The [pragma](https://en.wikipedia.org/wiki/Directive_\(programming\)) statement specifies which version of the Solidity compiler we need to use. In this case we’ll only accept the compiler version 0.8.13
    
*   Line 4: We import the Solmate [ERC20 token contract](https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol). This contract is what’s doing all the work under the hood. Refer to that contract if you’re interested in how the token is implemented.
    
*   Line 6: We define our contract `FirstToken` and that it inherits from the Solmate `ERC20` contract. Contracts in Solidity are similar to classes in object-oriented languages and can inherit from one another.
    
*   Line 7: We define the constructor of the contract and call the constructor of the ERC20 contract.
    
    *   Solidity is unique in that a contract can extend multiple other contracts, and thus the atypical syntax of calling the ERC20 constructor in the constructor definition, not in a `super` call.
        
    *   Our constructor accepts 1 argument `totalSupply`. The ERC20 constructor accepts 3 arguments: `name`, `symbol` and `decimals`. `name` and `symbol` are straightforward. `decimals` is the number of decimals to use in the numbers representation. Ethereum and all other blockchains I know of have no concept of floating point numbers so for more granular accuracy they just stick a bunch of zeros behind each number and refer to those as decimal points. ETH and most ERC20 tokens have 18 decimals. [USDC](https://etherscan.io/token/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48) and [USDT](https://etherscan.io/token/0xdac17f958d2ee523a2206206994597c13d831ec7) both have 6 decimals (because fiat?) and Wrapped Bitcoin (WBTC) has 8 decimals because Bitcoin has 8 decimals.
        
*   Line 8: We mint the `totalSupply` of tokens to the `msg.sender`, which is the account that is sending the message to create the contract.
    

Deploy the Smart Contract
-------------------------

Now that we’ve created the smart contract, we need to deploy it.

### Wallet Creation

Before we can deploy the smart contract, we’ll have to create a wallet that we can deploy the contract from.

The simple way to create a wallet with foundry is running:

    cast wallet new
    

But if you want to get creative you can run:

    cast wallet vanity --starts-with <prefix>
    

This command will search for a private key that matches an address that starts with `<prefix>`. Not that `<prefix>` must be valid hex (i.e. valid characters include 0-9 and a-f only). Note that the longer the prefix is, the more attempts it will take the script to find a valid address that fulfills your vanity requirements. From my experience, anything under 4 characters will return instantly, 5 characters will take about 20-40s and each successive character will take an order of magnitude longer (it’s 16x harder to be exact). The exact times you’ll see will depend on the specs of the machine you run this on.

💡 Keep your private key safe. Anyone with access to this private key can access any funds in your wallet. It’s recommended to not keep a lot of funds in a hot wallet like this.

### **Fund the Wallet**

We’ll need to fund the wallet before we can send a transaction to it. To accomplish this, we’ll use a “faucet” which see send us testnet tokens. Go to [https://faucet.paradigm.xyz/](https://faucet.paradigm.xyz/) and claim tokens from the faucet to the wallet you created in the previous step.

**Check the wallet is funded**

We’re going to deploy the contract on Ethereum’s Goerli testnet so go to [https://goerli.etherscan.io/](https://goerli.etherscan.io/) and search for the wallet address you previously created. After claiming tokens from the faucet you should see that it has an Ether balance.

You should also run:

    cast balance --rpc-url https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161 \
        <your_address>
    

You should notice that there are a lot more 0s behind your ETH balance when running this CLI command.

### Deploy

Now let’s deploy the contract. Run the following command:

    forge create --rpc-url <your_rpc_url> --private-key <your_private_key> \ 
        src/FirstToken.sol:FirstToken \
      --constructor-args 1000000000000000000000000
    

Replace `<your_rpc_url>` with `https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161` and with the private key you previously created. This will create a token with a total supply of 100,000 (assuming I counted correctly). If you go to the etherscan link for your account that deployed the contract, you’ll notice your balance is shown under the “Erc20 Token Txns” Tabs (e.g. [https://goerli.etherscan.io/address/0x8404a542298827022bf4441afef0a96766be7201#tokentxns](https://goerli.etherscan.io/address/0x8404a542298827022bf4441afef0a96766be7201#tokentxns) for account `0x8404A542298827022bf4441Afef0a96766Be7201` on Goerli) **Peeking Under the Hood** Let’s take a look at what’s happening under the hood. Go back to Goerli etherscan and look up the transaction you just sent. Find the parameter on the transaction called “Input Data” (often just called “data” or “input”). You may have to expand more properties on the transaction to see it. Now open up the `out/FirstToken.sol/FirstToken.json` file in your repo. The “Input Data” on the transaction should look similar to the `bytecode.object` field in the file. Next, look up the address of the contract you just created. Click on the “Contract” tab and you should see the deployed bytecode of the contract. This value should look similar to the `deployedBytecode.object` property within the FirstToken.json file. Interacting with your Contract Now that you’ve deployed your first contract, let’s interact with it. **Checking Your Balance** First we need to get the calldata to check your balance cast calldata "balanceOf(address)" <your\_eoa\_address> If you look closely at the calldata, you’ll notice that there’s 8 digits after the “0x” prefix at the start of it and the last 40 characters are from your address. Now that we have the calldata run: cast call --rpc-url https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161 \\ <your\_contract\_address> <call\_data> The output of the previous command is a bunch of hex jargon so let’s make it a little easier to read: cast --to-dec <hex\_output> You should see the same number you passed into the constructor when creating the contract. **Transferring the Token** Let’s now transfer some of your token to another address. Run the following command: cast send --rpc-url https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161 \\ --private-key <your\_private\_key> \\ <your\_contract\_address> \\ "transfer(address,uint)" 0x6666664c7d32A5577070EB846f7dFa5f962e5e6a 1000000000000000 This will transfer tokens to my address `0x6666664c7d32A5577070EB846f7dFa5f962e5e6a`. Replace this address with an address you control if you want to keep all the tokens for yourself. 3. Read Up on EVM Read the Ethereum [Yellow Paper](https://ethereum.github.io/yellowpaper/paper.pdf). The Ethereum Yellow Paper is the technical specification for Ethereum and is probably the quickest way to understand how the EVM works at a granular level. The yellow paper is super dense but understanding sections 4-7 are super useful to understand. Feel free to skim/skip all the proofs. 4. Analyzing ERC20 Contracts Lastly, we’ll analyze 2 different implementations of the ERC20 standard. The first is the Solmate contract that we used in part 2. The second is a contract written entirely in [Yul](https://docs.soliditylang.org/en/v0.8.15/yul.html), which is a low-level EVM language. Yul is often used for highly optimized contracts in terms of gas efficiency. Analyzing the contract will help us understand what’s happening under the hood when looking at a Solidity contract. Solmate: [https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol](https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol) ERC20 in Yul: [https://docs.soliditylang.org/en/v0.8.15/yul.html#complete-erc20-example](https://docs.soliditylang.org/en/v0.8.15/yul.html#complete-erc20-example)

---

*Originally published on [hatem.eth](https://paragraph.com/@hatem/becoming-an-evm-expert)*
