# Jeancvllr - EVM Assembly

{% embed url="<https://jeancvllr.medium.com/solidity-tutorial-all-about-assembly-5acdfefde05c>" %}
Solidity Tutorial : all about Assembly
{% endembed %}

## Namespace

Quote from Solidity doc:

> **Different inline assembly blocks share no namespace**, i.e. it is not possible to call a Yul function or access a Yul variable defined in a different inline assembly block.

```solidity
assembly { 
    let x := 2
}
        
assembly {
    let y := x          // Error
}// DeclarationError: identifier not found
// let y := x
// ^
```

## Basic Example

```solidity
function addition(uint x, uint y) public pure returns (uint) {
     
    assembly {
        // Create a new variable `result`
        //     -> calculate the sum of `x + y` with the `add` opcode
        //     -> assign the value to `result`
        
        let result := add(x, y)   // x + y
        // Use the `mstore` opcode, to:
        //     -> store `result` in memory
        //     -> at memory address 0x0
        
        mstore(0x0, result)       // store result in memory
         
        // return 32 bytes from memory address 0x0
        
        return(0x0, 32)          
    
    }
}
```

In the inner working of the EVM, `let` performs the following:

1. **Creates a new stack slot**
2. The new slot is **reserved for the variable**.
3. The slot is then automatically removed again when the end of the block is reached.

{% hint style="danger" %}
Variables declared with the `let` keyword are not visible outside the `assembly` block.
{% endhint %}

## Literals

Literals are also written in the same way than in Solidity. However, **string literals can be up to 32 characters**:

```solidity
assembly {
    let a := 0x123             // Hexadecimal
    let b := 42                // Decimal
    let c := "hello world"     // String
    
    let d := "very long string more than 32 bytes" // Error
} 
// TypeError: String literal too long (35 < 32)
// let d := "really long string more than 32 bytes"
//           ^------------------------------------^
```

## Blocks and Scope

Variables follow the standard rule of block scoping. A block scope is defined by adding code between two curly braces `{ ... }`.

In the example below, `y` and `z` are only visible in the scope they are defined in. So `Scope 1` for `y` and `Scope 2` for `z`:

```solidity
assembly { 
    
    let x := 3          // x is visible everywhere
      
    // Scope 1           
    { 
        let y := x     // ok
    }  // y is "deallocated" here
    
    // Scope 2    
    {
        let z := y     // Error
    } // x is "deallocated" here
        
}
// DeclarationError: identifier not found
// let x:= y
// ^
```

## Loops

This is a for loop in Solidity:

```solidity
function for_loop_solidity(uint n, uint value) public pure returns(uint) {
         
    for ( uint i = 0; i < n; i++ ) {
        value = 2 * value;
    }
    return value;
}
```

This is its assembly equivalent:

```solidity
function for_loop_assembly(uint n, uint value) public pure returns (uint) {
         
     assembly {
             
       for { let i := 0 } lt(i, n) { i := add(i, 1) } { 
           value := mul(2, value) 
       }
           
       mstore(0x0, value)
       return(0x0, 32)
           
   }
         
}
```

Note that `lt(i, n)` is a functional-style expression. In fact, everything in Solidity assembly must be written in functional.

There is no while loop in Solidity assembly, but similar effect can be achieved by for loop:

```solidity
assembly {
    let x := 0
    let i := 0
    for { } lt(i, 0x100) { } {   // while(i < 256), 100 (hex) = 256
        x := add(x, mload(i))
        i := add(i, 0x20)
    }
}
```

## Conditional Statements

Solidity inline assembly supports `if` statement to check conditions before executing code. However, there is no `else` part:

```solidity
assembly {
    if slt(x, 0) { x := sub(0, x) }  // Ok
            
    if eq(value, 0) revert(0, 0)    // Error, curly braces needed
}
```

Curly braces for the body of the `if` statement are required.

EVM Assembly also includes `switch` statement. A `switch` statement takes the value of an expression and compares it to several constants. The branch corresponding to the matching constant is taken. You can also have a `default` case if none of the cases match:

```solidity
assembly {
    let x := 0
    switch calldataload(4)
    case 0 {
        x := calldataload(0x24)
    }
    default {
        x := calldataload(0x44)
    }
    sstore(0, div(x, 2))
}
```

## Functions
