Network
Launch Date
Consensus
Note
Sepolia
Oct 2021
PoW
Like-for-like representation of Ethereum
Görli
Jan 2019
PoA
Proof-of-Authority
Kiln
Mar 2022
PoS
Post-Merge (for ETH2), shadow fork of the mainnet
Kintsugi
Dec 2021
PoS
DEPRECATED, use Kiln; post-Merge (for ETH2)
Ropsten
Nov 2016
PoW
DEPRECATED, use Sepolia; the Merge to happen on Jun 8, 2022
Rinkeby
Apr 2017
PoA
DEPRECATED, use Görli and Görli Faucet
Kovan
Mar 2017
PoA
DEPRECATED, use Sepolia or Görli
List of active and deprecated Ethereum testnets, including Kintsugi.
Features
Optimistic rollup 
ZK-rollup 
Proof
Uses fraud proofs to prove transaction validity. 
Uses validity (zero-knowledge) proofs to prove transaction validity. 
Capital efficiency
Requires waiting through a 1-week delay (dispute period) before withdrawing funds. 
Users can withdraw funds immediately because validity proofs provide incontrovertible evidence of the authenticity of off-chain transactions. 
Data compression
Publishes full transaction data as calldata to Ethereum Mainnet, which increases rollup costs. 
Doesn't need to publish transaction data on Ethereum because ZK-SNARKs and ZK-STARKs already guarantee the accuracy of the rollup state. 
EVM compatibility
Uses a simulation of the Ethereum Virtual Machine (EVM), which allows it to run arbitrary logic and support smart contracts. 
Doesn't widely support EVM computation, although a few EVM-compatible ZK-rollups have appeared. 
Rollup costs
Reduces costs since it publishes minimal data on Ethereum and doesn't have to post proofs for transactions, except in special circumstances. 
Faces higher overhead from costs involved in generating and verifying proofs for every transaction block. ZK proofs require specialized, expensive hardware to create and have high on-chain verification costs. 
Trust assumptions
Doesn't require a trusted setup. 
Requires a trusted setup to work. 
Liveness requirements
Verifiers are needed to keep tabs on the actual rollup state and the one referenced in the state root to detect fraud. 
Users don't need someone to watch the L2 chain to detect fraud. 
Security properties 
Relies on cryptoeconomic incentives to assure users of rollup security. 
Relies on cryptographic guarantees for security. 
Start building
on Alchemy.
Sign up for free
Start building on Optimism.
Sign up for free
Start building on Arbitrum.
Sign up for free
Start building on Ethereum.
Sign up for free
Start building on Polygon.
Sign up for free
Start building on Starknet.
Sign up for free
Start building on Flow.
Sign up for free
kiln faucet
Get free Kiln ETH.
Start building today
Goerli faucet
Get free Goerli ETH.
Start building today
SEPOLIA FAUCET
Get free Sepolia ETH.
Start Building Today
mumbai faucet
Get free Mumbai Matic.
Start building today
rinkeby faucet
Get free Rinkeby
ETH.
Start building today
Start building on Ethereum.
Get started for free
Start building on Ethereum.
Get started for free
Start building on Flow.
Get started for free
Start building on Polygon.
Get started for free
Start building on Starknet.
Get started for free
Start building on Optimism.
Get started for free
Start building on Solana.
Get started for free
Start building on Solana.
Sign up for beta access
Start building on Solana.
Join the waitlist
Arbitrum logo
Start building on Arbitrum.
Get started for free
Build with Alchemy's
Gas Manager & Bundler APIs
Learn
Solidity at
Alchemy
University
Get started today
Build with Alchemy's
Gas Manager & Bundler APIs
curl 
https://release.solana.com/v1.10.32/solana-install-init-x86_64-pc-windows-msvc.exe 
--output 
C:\solana-install-tmp\solana-install-init.exe 
--create-dirs
Learn Solidity
YUL MEMORY OVERVIEW

How Does Memory Work in Yul?

Learn How Memory Works in the Yul Smart Contract Programming Language
Last Updated:
July 28, 2023
Table of Contents
Table of Contents
Table of Contents

{{building-on-ethereum}}

Yul is an intermediate programming language that can be used to write a form of assembly language inside smart contracts. Once you’ve learned about Yul storage and how to read and write packed storage variables, it’s important to learn how memory works with Yul smart contracts.

How does memory work in Yul?

Memory behaves differently than storage. Memory is not persistent, which means that once the function is done executing all of the variables are cleared. 

Memory is comparable to heap in other languages, but there is no garbage collector. 

Memory is a lot cheaper than storage. The first 22 words of memory costs are calculated linearly, but be careful because after that memory costs become quadratic. 

Memory is laid out in 32 byte sequences. We will get a better understanding of this later, but for now understand 0x00 - 0x20 is one sequence (you can think of it like a slot if that helps, but they are different). 

Solidity allocates 0x00 - 0x40 as scratch space. This area of memory is not guaranteed to be empty, and is used for certain operations. 

0x40 - 0x60 stores the location of what is known as the free memory pointer, which is used to write something new to memory. 

0x60 - 0x80 is left empty as a gap. 

0x80 is where we begin our operations. 

Memory does not pack values. Retrieving values from storage will be stored in their own 32 byte sequence (i.e 0x80-0xa0).

What operations use memory in Yul?

Memory is used for the following operations:

  • Return values for external calls
  • Set function values for external calls
  • Get values from external calls
  • Revert with an error string
  • Log messages
  • Hash with keccak256()
  • Create other smart contracts

Here are some useful Yul instructions for memory:

Table of Yul Instructions and Their Explanations
Table of Yul Instructions and Their Explanations

Let’s check out some more data structures!

How to Use Structs and Memory in Yul

Structs and fixed arrays actually behave the same but since we already looked at fixed arrays in the storage section, we are going to look at structs here. Look at the following struct.

struct Var10 {
    uint256 subVar1;
    uint256 subVar2;
}

Nothing unusual about this, just a simple struct. 

Now let’s look at some code!

function getStructValues() external pure returns(uint256, uint256) {
 
    // initialize struct
    Var10 memory s;
    s.subVar1 = 32;
    s.subVar2 = 64;
 
    assembly {
        return( 0x80, 0xc0 )
    }
 
}

Here we are setting s.subVar1 to memory location 0x80 - 0xa0 and s.subVar2 to memory location 0xa0 - 0xc0. That is why we are returning 0x80 - 0xc0. Here is a table of the memory layout right before the end of the transaction.

Table of Yul Memory Locations and Their Stored Values
Current Memory Layout

Things to take away from this:

  • 0x00 - 0x40 is empty for scratch space
  • 0x40 gives us the free memory pointer
  • Solidity leaves a gap for 0x60
  • 0x80 and 0xa0 are used for storing the values of the struct
  • 0xc0 is the new free memory pointer

In this last part of the memory section I want to show you how dynamic arrays work in memory. We are going to pass [0, 1, 2, 3] as the parameter arr for this example. As an added bonus for this example we are going to add an extra element to the array. Be careful doing this in production as you may overwrite a different memory variable. 

Here is the code:

function getDynamicArray(uint256[] memory arr) external view returns (uint256[] memory) {
 
    assembly {
 
        // where array is stored in memory (0x80)
        let location := arr
 
        // length of array is stored at arr (4)
        let length := mload(arr)
 
        // gets next available memory location
        let nextMemoryLocation := add( add( location, 0x20 ), mul( length, 0x20 ) )
 
        // stores new value to memory
        mstore(nextMemoryLocation, 4)
 
        // increment length by 1
        length := add( length, 1 )
 
        // store new length value
        mstore(location, length)
 
        // update free memory pointer
        mstore(0x40, 0x140)
 
        return ( add( location, 0x20 ) , mul( length, 0x20 ) )
 
    }
 
}

Here is what’s happening:

  • Get where the array is stored in memory
  • Get the length of the array, which is stored in the first memory location of the array
  • Add 32 bytes to the location (skip the length of the array) to see the next available location
  • Multiply the length of the array by 32 bytes to advance us to the next memory location
  • Store our new value (4)
  • Update the length of the array by one. 
  • Update the free memory pointer
  • Return the array.

Let’s look at the memory layout once again.

Table of Yul Memory Locations and Their Stored Values
Current Memory Layout

That concludes the section on memory!

Next up, learn how to call smart contracts using Yul or go back to learn how to read and write packed storage variables!

ALCHEMY SUPERNODE - ETHEREUM NODE API

Scale to any size, without any errors

Alchemy Supernode finally makes it possible to scale blockchain applications without all the headaches. Plus, our legendary support will guide you every step of the way.

Get started for free
Supernode footer
Learn Solidity
YUL MEMORY OVERVIEW

How Does Memory Work in Yul?

Learn How Memory Works in the Yul Smart Contract Programming Language
Last Updated:
July 28, 2023
Last Updated:
March 14, 2023
Don't miss an update
Sign up for our newsletter to get alpha, key insights, and killer resources.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Table of Contents

Talk to an Expert

Learn how Alchemy's blockchain developer tools can help your business succeed in web3!
Valid number
Thank you! An Alchemy expert will be in touch with you shortly!
Oops! Something went wrong while submitting the form.

{{building-on-ethereum}}

Yul is an intermediate programming language that can be used to write a form of assembly language inside smart contracts. Once you’ve learned about Yul storage and how to read and write packed storage variables, it’s important to learn how memory works with Yul smart contracts.

How does memory work in Yul?

Memory behaves differently than storage. Memory is not persistent, which means that once the function is done executing all of the variables are cleared. 

Memory is comparable to heap in other languages, but there is no garbage collector. 

Memory is a lot cheaper than storage. The first 22 words of memory costs are calculated linearly, but be careful because after that memory costs become quadratic. 

Memory is laid out in 32 byte sequences. We will get a better understanding of this later, but for now understand 0x00 - 0x20 is one sequence (you can think of it like a slot if that helps, but they are different). 

Solidity allocates 0x00 - 0x40 as scratch space. This area of memory is not guaranteed to be empty, and is used for certain operations. 

0x40 - 0x60 stores the location of what is known as the free memory pointer, which is used to write something new to memory. 

0x60 - 0x80 is left empty as a gap. 

0x80 is where we begin our operations. 

Memory does not pack values. Retrieving values from storage will be stored in their own 32 byte sequence (i.e 0x80-0xa0).

What operations use memory in Yul?

Memory is used for the following operations:

  • Return values for external calls
  • Set function values for external calls
  • Get values from external calls
  • Revert with an error string
  • Log messages
  • Hash with keccak256()
  • Create other smart contracts

Here are some useful Yul instructions for memory:

Table of Yul Instructions and Their Explanations
Table of Yul Instructions and Their Explanations

Let’s check out some more data structures!

How to Use Structs and Memory in Yul

Structs and fixed arrays actually behave the same but since we already looked at fixed arrays in the storage section, we are going to look at structs here. Look at the following struct.

struct Var10 {
    uint256 subVar1;
    uint256 subVar2;
}

Nothing unusual about this, just a simple struct. 

Now let’s look at some code!

function getStructValues() external pure returns(uint256, uint256) {
 
    // initialize struct
    Var10 memory s;
    s.subVar1 = 32;
    s.subVar2 = 64;
 
    assembly {
        return( 0x80, 0xc0 )
    }
 
}

Here we are setting s.subVar1 to memory location 0x80 - 0xa0 and s.subVar2 to memory location 0xa0 - 0xc0. That is why we are returning 0x80 - 0xc0. Here is a table of the memory layout right before the end of the transaction.

Table of Yul Memory Locations and Their Stored Values
Current Memory Layout

Things to take away from this:

  • 0x00 - 0x40 is empty for scratch space
  • 0x40 gives us the free memory pointer
  • Solidity leaves a gap for 0x60
  • 0x80 and 0xa0 are used for storing the values of the struct
  • 0xc0 is the new free memory pointer

In this last part of the memory section I want to show you how dynamic arrays work in memory. We are going to pass [0, 1, 2, 3] as the parameter arr for this example. As an added bonus for this example we are going to add an extra element to the array. Be careful doing this in production as you may overwrite a different memory variable. 

Here is the code:

function getDynamicArray(uint256[] memory arr) external view returns (uint256[] memory) {
 
    assembly {
 
        // where array is stored in memory (0x80)
        let location := arr
 
        // length of array is stored at arr (4)
        let length := mload(arr)
 
        // gets next available memory location
        let nextMemoryLocation := add( add( location, 0x20 ), mul( length, 0x20 ) )
 
        // stores new value to memory
        mstore(nextMemoryLocation, 4)
 
        // increment length by 1
        length := add( length, 1 )
 
        // store new length value
        mstore(location, length)
 
        // update free memory pointer
        mstore(0x40, 0x140)
 
        return ( add( location, 0x20 ) , mul( length, 0x20 ) )
 
    }
 
}

Here is what’s happening:

  • Get where the array is stored in memory
  • Get the length of the array, which is stored in the first memory location of the array
  • Add 32 bytes to the location (skip the length of the array) to see the next available location
  • Multiply the length of the array by 32 bytes to advance us to the next memory location
  • Store our new value (4)
  • Update the length of the array by one. 
  • Update the free memory pointer
  • Return the array.

Let’s look at the memory layout once again.

Table of Yul Memory Locations and Their Stored Values
Current Memory Layout

That concludes the section on memory!

Next up, learn how to call smart contracts using Yul or go back to learn how to read and write packed storage variables!

Yul is an intermediate programming language that can be used to write a form of assembly language inside smart contracts. Once you’ve learned about Yul storage and how to read and write packed storage variables, it’s important to learn how memory works with Yul smart contracts.

How does memory work in Yul?

Memory behaves differently than storage. Memory is not persistent, which means that once the function is done executing all of the variables are cleared. 

Memory is comparable to heap in other languages, but there is no garbage collector. 

Memory is a lot cheaper than storage. The first 22 words of memory costs are calculated linearly, but be careful because after that memory costs become quadratic. 

Memory is laid out in 32 byte sequences. We will get a better understanding of this later, but for now understand 0x00 - 0x20 is one sequence (you can think of it like a slot if that helps, but they are different). 

Solidity allocates 0x00 - 0x40 as scratch space. This area of memory is not guaranteed to be empty, and is used for certain operations. 

0x40 - 0x60 stores the location of what is known as the free memory pointer, which is used to write something new to memory. 

0x60 - 0x80 is left empty as a gap. 

0x80 is where we begin our operations. 

Memory does not pack values. Retrieving values from storage will be stored in their own 32 byte sequence (i.e 0x80-0xa0).

What operations use memory in Yul?

Memory is used for the following operations:

  • Return values for external calls
  • Set function values for external calls
  • Get values from external calls
  • Revert with an error string
  • Log messages
  • Hash with keccak256()
  • Create other smart contracts

Here are some useful Yul instructions for memory:

Table of Yul Instructions and Their Explanations
Table of Yul Instructions and Their Explanations

Let’s check out some more data structures!

How to Use Structs and Memory in Yul

Structs and fixed arrays actually behave the same but since we already looked at fixed arrays in the storage section, we are going to look at structs here. Look at the following struct.

struct Var10 {
    uint256 subVar1;
    uint256 subVar2;
}

Nothing unusual about this, just a simple struct. 

Now let’s look at some code!

function getStructValues() external pure returns(uint256, uint256) {
 
    // initialize struct
    Var10 memory s;
    s.subVar1 = 32;
    s.subVar2 = 64;
 
    assembly {
        return( 0x80, 0xc0 )
    }
 
}

Here we are setting s.subVar1 to memory location 0x80 - 0xa0 and s.subVar2 to memory location 0xa0 - 0xc0. That is why we are returning 0x80 - 0xc0. Here is a table of the memory layout right before the end of the transaction.

Table of Yul Memory Locations and Their Stored Values
Current Memory Layout

Things to take away from this:

  • 0x00 - 0x40 is empty for scratch space
  • 0x40 gives us the free memory pointer
  • Solidity leaves a gap for 0x60
  • 0x80 and 0xa0 are used for storing the values of the struct
  • 0xc0 is the new free memory pointer

In this last part of the memory section I want to show you how dynamic arrays work in memory. We are going to pass [0, 1, 2, 3] as the parameter arr for this example. As an added bonus for this example we are going to add an extra element to the array. Be careful doing this in production as you may overwrite a different memory variable. 

Here is the code:

function getDynamicArray(uint256[] memory arr) external view returns (uint256[] memory) {
 
    assembly {
 
        // where array is stored in memory (0x80)
        let location := arr
 
        // length of array is stored at arr (4)
        let length := mload(arr)
 
        // gets next available memory location
        let nextMemoryLocation := add( add( location, 0x20 ), mul( length, 0x20 ) )
 
        // stores new value to memory
        mstore(nextMemoryLocation, 4)
 
        // increment length by 1
        length := add( length, 1 )
 
        // store new length value
        mstore(location, length)
 
        // update free memory pointer
        mstore(0x40, 0x140)
 
        return ( add( location, 0x20 ) , mul( length, 0x20 ) )
 
    }
 
}

Here is what’s happening:

  • Get where the array is stored in memory
  • Get the length of the array, which is stored in the first memory location of the array
  • Add 32 bytes to the location (skip the length of the array) to see the next available location
  • Multiply the length of the array by 32 bytes to advance us to the next memory location
  • Store our new value (4)
  • Update the length of the array by one. 
  • Update the free memory pointer
  • Return the array.

Let’s look at the memory layout once again.

Table of Yul Memory Locations and Their Stored Values
Current Memory Layout

That concludes the section on memory!

Next up, learn how to call smart contracts using Yul or go back to learn how to read and write packed storage variables!

{{building-on-ethereum}}

Contact Us

Talk to an expert at Alchemy to answer all of your product questions.
Valid number
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Build blockchain magic with Alchemy

Alchemy combines the most powerful web3 developer products and tools with resources, community and legendary support.

Get started for free