---
title: "Como funciona o storage em Yul?"
description: "Entenda Como Funciona o Storage na Linguagem de Programação de Smart Contracts Yul"
---

# Como funciona o storage em Yul?

[Yul](http://www.alchemy.com/overviews/what-is-yul) é uma linguagem de programação intermediária que pode ser usada para escrever uma forma de linguagem assembly dentro de [smart contracts](https://www.alchemy.com/overviews/solidity-smart-contract). Entender Yul pode elevar o nível dos seus smart contracts e ajudar a economizar gas dos usuários. Para começar a escrever smart contracts com Yul, é importante entender como funciona o storage.

## **Como funciona o storage no Yul?**

Antes de nos aprofundarmos em como funciona o Yul, precisamos entender bem [como funciona o storage em smart contracts](https://www.alchemy.com/docs/smart-contract-storage-layout). O storage é composto por uma série de slots. Existem 2²⁵⁶ slots para um smart contract.

Ao declarar variáveis, começamos no slot 0 e incrementamos a partir daí. Cada slot tem 256 bits de comprimento (32 bytes), e é daí que vêm os nomes uint256 e bytes32. Todas as variáveis são convertidas para hexadecimal.

Se uma variável, como um uint128, é usada, não ocupamos um slot inteiro para armazená-la. Em vez disso, ela é preenchida com 0's do lado esquerdo. Vamos ver um exemplo para entender melhor.

var1: Como variáveis uint256 equivalem a 32 bytes, var1 ocupa a totalidade do slot 0.

Aqui está o que é armazenado no slot 0:

`0x0000000000000000000000000000000000000000000000000000000000000100`

var2: Endereços são um pouco mais complexos. Como ocupam apenas 20 bytes de storage, endereços são preenchidos com 0's do lado esquerdo.

Aqui está o que é armazenado no slot 1:

`0x0000000000000000000000009acc1d6aa9b846083e8a497a661853aae07f0f00.`

var3: Este pode parecer simples, o slot 2 é consumido pela totalidade da variável bytes32.

var4 & var5: Lembra quando mencionei que uint128's são preenchidos com 0's? Bem, se ordenarmos nossas variáveis de forma que a soma do seu storage fique abaixo de 32 bytes, podemos encaixá-las juntas em um slot! Isso é chamado de packing de variáveis, e pode economizar gas.

Vamos ver o que é armazenado no slot 3:

`0x0000000000000000000000000000000200000000000000000000000000000001. `

Perceba que `0x000000000000000000000000000002` e `0x000000000000000000000000000001` se encaixam perfeitamente juntos no mesmo slot. Isso acontece porque ambos ocupam 16 bytes (metade de um slot).

<EmbeddedTable
  table={{
    columns: [
      { key: "1", width: 200, title: "Instruction", dataType: "object" },
      { key: "2", width: 200, title: "Explanation", dataType: "object" },
    ],
    data: [
      {
        "1": { title: "<p>sload(p)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Carrega a variável no slot p a partir do storage.</p>", tooltip: "", icon: "" },
        id: 0,
      },
      {
        "1": { title: "<p>sstore(p,v)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Atribui ao slot de storage p o valor v.</p>", tooltip: "", icon: "" },
        id: 1,
      },
      {
        "1": { title: "<p>v.slot</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Retorna o slot de storage da variável v.</p>", tooltip: "", icon: "" },
        id: 2,
      },
      {
        "1": { title: "<p>v.offset</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Retorna o índice em bytes de onde a variável v começa em um slot de storage. Variáveis são organizadas (packed) da direita para a esquerda.</p>", tooltip: "", icon: "" },
        id: 3,
      },
    ],
  }}
/>

Vamos ver outro exemplo!

x = 3. Isso faz sentido já que sabemos que var5 está armazenada no slot 3.

y = 16. Isso também deve fazer sentido já que sabemos que var4 ocupa metade do slot 3. Como as variáveis são organizadas da direita para a esquerda, obtemos o byte 16 como índice inicial de var5.

z = 1. O sstore\(\) está atribuindo ao slot 0 o valor 1. Em seguida, atribuímos a z o valor do slot 0 com o sload\(\).

Antes de continuarmos, você deve adicionar essa função ao seu arquivo do remix. Ela vai ajudar a visualizar o que está sendo armazenado em cada slot de storage.

Agora vamos olhar algumas estruturas de dados mais complexas!

Ao trabalhar com arrays estáticos, a EVM sabe quantos slots alocar para nossos dados. Neste array em particular, estamos organizando (packing) 2 elementos por slot.

Então, se você chamar `getValInHex\(4\)`, isso retornará `0x0000000000000000000000000000000100000000000000000000000000000000`.

Como era de se esperar, lendo da direita para a esquerda, vemos o valor 0 e o valor 1.

O slot 5 contém `0x0000000000000000000000000000000300000000000000000000000000000002`.

A seguir, vamos olhar arrays dinâmicos.

Tente chamar `getValInHex\(6\)`. Você verá que retorna 0x00. Como a EVM não sabe quantos slots de storage precisam ser alocados, não podemos armazenar o array aqui.

Em vez disso, o hash keccak256 do slot de storage atual (slot 6) é usado como índice inicial do array. A partir daí, tudo o que precisamos fazer é somar o índice do elemento desejado para recuperar o valor.

**Aqui está um exemplo de código demonstrando como encontrar um elemento de um array dinâmico:**

Aqui recuperamos o slot do array, e então realizamos uma operação add\(\) junto com um sload\(\) para obter o valor do elemento desejado do array.

Você pode estar se perguntando o que impede que ocorra uma colisão com o slot de outra variável?

Isso é totalmente possível, porém extremamente improvável, já que 2²⁵⁶ é um número muito grande.

Mappings se comportam de forma semelhante a arrays dinâmicos, exceto que fazemos o hash do slot junto com a chave.

Para esta demonstração, defini o valor do mapping var8\[1\] = 2. Agora vamos ver um exemplo de como obter o valor de uma chave de um mapping.

Como você pode ver, o código é bem parecido com quando encontramos um elemento de um array dinâmico. A principal diferença é que fazemos o hash da chave e do slot juntos.

A última parte da nossa seção sobre storage é aprender sobre mappings aninhados (nested). Antes de continuar a leitura, encorajo você a escrever sua própria implementação de como ler um valor de um mapa aninhado com base no que aprendeu até agora.

Para este exemplo, defini o valor do mapping var9\[0\]\[1\] = 2.

Aqui está o código, vamos direto ao ponto!

**Aqui está o que está acontecendo:**

1. Primeiro obtemos o hash da primeira chave (0).
1. Em seguida, pegamos o hash disso com a segunda chave (1).
1. Por fim, carregamos o slot do storage para obter nosso valor.

Parabéns, você concluiu a seção sobre storage com Yul!

Leia mais sobre [Yul Memory](http://www.alchemy.com/overviews/yul-memory), [Yul Contract Calls](http://www.alchemy.com/overviews/yul-contract-calls), e [Yul Packed Storage Variables](http://www.alchemy.com/overviews/yul-packed-storage-variables).
