---
title: "Como funcionam as chamadas de contrato em Yul?"
description: "Aprenda como funcionam as chamadas de contrato na linguagem de programação de smart contracts Yul"
---

# Como funcionam as chamadas de contrato 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). Agora que você entende a sintaxe, o storage e como a memória funciona em Yul, é hora de chamar contratos!

## **Como funcionam as chamadas de contrato em yul?**

Na seção final desta série veremos como funcionam as chamadas de contrato em Yul. Antes de mergulharmos em alguns exemplos, precisamos aprender mais algumas Operações Yul primeiro. Vamos dar uma olhada.‍

<EmbeddedTable
  table={{
    columns: [
      { key: "1", width: 200, title: "Instruction", dataType: "object" },
      { key: "2", width: 200, title: "Explanation", dataType: "object" },
    ],
    data: [
      {
        "1": { title: "<p>gas()</p>", tooltip: "", icon: "" },
        "2": { title: "<p>A quantidade de gas que ainda está disponível para execução</p>", tooltip: "", icon: "" },
        id: 0,
      },
      {
        "1": { title: "<p>gasPrice()</p>", tooltip: "", icon: "" },
        "2": { title: "<p>O gas price da transação</p>", tooltip: "", icon: "" },
        id: 1,
      },
      {
        "1": { title: "<p>address()</p>", tooltip: "", icon: "" },
        "2": { title: "<p>O endereço do contrato atual</p>", tooltip: "", icon: "" },
        id: 2,
      },
      {
        "1": { title: "<p>balance(a)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>O saldo de ether, em wei, do endereço a</p>", tooltip: "", icon: "" },
        id: 3,
      },
      {
        "1": { title: "<p>selfbalance()</p>", tooltip: "", icon: "" },
        "2": { title: "<p>O mesmo que chamar balance(address()), mas ligeiramente mais barato</p>", tooltip: "", icon: "" },
        id: 4,
      },
      {
        "1": { title: "<p>caller()</p>", tooltip: "", icon: "" },
        "2": { title: "<p>O endereço que chamou o contrato (msg.sender)</p>", tooltip: "", icon: "" },
        id: 5,
      },
      {
        "1": { title: "<p>origin()</p>", tooltip: "", icon: "" },
        "2": { title: "<p>O endereço que originou a transação (tx.origin)</p>", tooltip: "", icon: "" },
        id: 6,
      },
      {
        "1": { title: "<p>callvalue()</p>", tooltip: "", icon: "" },
        "2": { title: "<p>A quantidade de ether, em wei, que foi enviada na chamada do contrato (msg.value)</p>", tooltip: "", icon: "" },
        id: 7,
      },
      {
        "1": { title: "<p>calldataload(p)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>O calldata começando na posição p (apenas 32 bytes de dados)</p>", tooltip: "", icon: "" },
        id: 8,
      },
      {
        "1": { title: "<p>calldatacopy(t, f, s)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>O calldata é copiado para a posição de memória t. Começando a partir da posição f no calldata. Copia s bytes de dados.</p>", tooltip: "", icon: "" },
        id: 9,
      },
      {
        "1": { title: "<p>extcodesize(a)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>O tamanho do código no endereço a</p>", tooltip: "", icon: "" },
        id: 10,
      },
      {
        "1": { title: "<p>returndatasize()</p>", tooltip: "", icon: "" },
        "2": { title: "<p>O tamanho do último returndata</p>", tooltip: "", icon: "" },
        id: 11,
      },
      {
        "1": { title: "<p>returndatacopy(t, f, s)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Copia s bytes do return data na posição f para a memória na posição t</p>", tooltip: "", icon: "" },
        id: 12,
      },
      {
        "1": { title: "<p>timestamp()</p>", tooltip: "", icon: "" },
        "2": { title: "<p>O timestamp atual do bloco em segundos</p>", tooltip: "", icon: "" },
        id: 13,
      },
      {
        "1": { title: "<p>number()</p>", tooltip: "", icon: "" },
        "2": { title: "<p>O número do bloco atual</p>", tooltip: "", icon: "" },
        id: 14,
      },
      {
        "1": { title: "<p>call(g, a, v, in, insize, out, outsize)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Chama um contrato no endereço a, com gas g, passando v wei como msg.value, passando tx.data a partir da posição de memória in - insize, e armazenando o return data na posição de memória out - outsize. Retorna 1 se a chamada foi bem-sucedida, caso contrário retorna 0.</p>", tooltip: "", icon: "" },
        id: 15,
      },
      {
        "1": { title: "<p>delegatecall(g, a, in, insize, out, outsize)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Similar a call(). A principal diferença é que delegatecall() atualiza as variáveis de estado no contrato que faz a chamada. Frequentemente usado para contratos proxy. É importante notar que o storage layout deve ser idêntico ao do contrato chamado, para evitar sobrescrever variáveis de storage não intencionais. Note que o parâmetro v está ausente. Não é possível enviar ether com delegatecall().</p>", tooltip: "", icon: "" },
        id: 16,
      },
      {
        "1": { title: "<p>staticcall(g, a, in, insize, out, outsize)</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Similar a call(). Exceto que não pode ser usado para chamar contratos que alteram o estado da blockchain (ou seja, funções marcadas como pure e view). Note que o parâmetro v está ausente. Não é possível enviar ether com staticcall().</p>", tooltip: "", icon: "" },
        id: 17,
      },
    ],
  }}
/>

Certo, agora vamos olhar para alguns novos contratos para esses exemplos. Primeiro, vamos ver o contrato que iremos chamar.

Este contrato tem duas variáveis de storage var1 e var2, armazenadas nos storage slots 1 e 2 respectivamente.

A função a\(\) exige que o usuário envie pelo menos 1 ether ao contrato, caso contrário ela reverte.

Em seguida, a função a\(\) atualiza var1 e var2 e as retorna.

A função b\(\) simplesmente lê var1 e var2 e as retorna.

Antes de passarmos ao nosso contrato que chama o contrato CallMe, precisamos de um momento para entender os function selectors.

Vamos olhar para o seguinte calldata de uma transação `0x773d45e000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002`.

Os primeiros 4 bytes do calldata são o que chamamos de function selector \(0x773d45e0\). É assim que a EVM sabe qual função você quer chamar. Derivamos o function selector obtendo os primeiros 4 bytes do hash de uma string da assinatura da função.

Então a assinatura da função a\(\) seria a\(uint256,uint256\).

Calculando o hash dessa string obtemos: `0x773d45e097aa76a22159880d254a5f1db8365bc2d0f0987a82bda7dfd3b9c8aa`.

Olhando para os primeiros 4 bytes, vemos que é igual a 0x773d45e0.

Note a ausência de espaços na assinatura. Isso é importante porque adicionar espaços resultaria em um hash completamente diferente. Você não precisa se preocupar em obter os selectors para nossos exemplos de código, eu os fornecerei.

Vamos começar olhando para o storage layout.

Note como var1 & var2 têm o mesmo layout do contrato CallMe. Você deve se lembrar de eu ter dito que o layout precisa ser o mesmo do nosso outro contrato para que delegatecall\(\) funcione corretamente.

Atendemos a essas necessidades e conseguimos ter outras variáveis \(selectorA & selectorB\) desde que nossas novas variáveis sejam adicionadas ao final. Isso evita colisões de storage.

Agora estamos prontos para fazer nossa primeira chamada de contrato.

### **Como usar staticcall\(\) em yul**

Vamos começar com algo simples, staticcall\(\). Aqui está nossa função:

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

- Recuperar o function selector de b\(\) do storage carregando o slot 2 \(ambos os selectors estão empacotados em um único slot\)
- Deslocar à direita 4 bytes \(32 bits\) para isolar selectorB
- Armazenar o function selector no scratch space da memória
- Fazer nossa static call
- Passar gas\(\) \(você também pode especificar a quantidade de gas\)
- Passar o parâmetro \_callMe como endereço do contrato
- Verificar se a chamada de função foi bem-sucedida, caso contrário retornamos sem dados. 
- Retornar nossos dados da memória e ver os valores 1 e 2

**Observação:** 0x1c e 0x20 indicam que queremos passar os últimos 4 bytes do que armazenamos no scratch space. Os dois últimos parâmetros de staticcall\(\) especificam que queremos armazenar o return data nas posições de memória 0x80 - 0xc0.

### **Como usar call\(\) em yul**

A seguir vamos olhar para call\(\). Vamos chamar a função a\(\) de CallMe. Lembre-se de enviar pelo menos 1 ether ao contrato! Vou passar 3 e 4 como \_var1 & \_var2 neste exemplo. 

**Aqui está o código:**

Ok, então de forma semelhante ao nosso último exemplo, precisamos carregar o slot2. Desta vez, no entanto, vamos mascarar selectorB para isolar selectorA. 

Agora vamos armazenar o selector em 0x80. 

Como precisamos de parâmetros do calldata, vamos usar calldatacopy\(\). Estamos dizendo a calldatacopy\(\) para:

- armazenar nosso calldata na posição de memória 0xa0
- pular os primeiros 36 bytes
- armazenar o tamanho do calldata menos 36 bytes

**Observação:** os primeiros 4 bytes que pulamos são o function selector de callA\(\) e os próximos 32 bytes são o endereço de callMe.

Agora estamos prontos para fazer nossa chamada de contrato! 

Assim como da última vez, passamos gas\(\) e \_callMe. No entanto, desta vez passamos nosso calldata a partir de 0x9c \(últimos 4 bytes da série de memória 0x80\) - 0xe0, e armazenamos nossos dados na posição de memória 0x100 - 0x120. 

Novamente, verificamos se a chamada foi bem-sucedida e retornamos nossa saída. Se verificarmos o contrato CallMe, veremos que os valores foram atualizados com sucesso para 3 e 4.

Para maior clareza sobre o que está acontecendo, aqui está o layout de memória logo antes de retornarmos:

<EmbeddedTable
  table={{
    columns: [
      { key: "1", width: 200, title: "Memory Location", dataType: "object" },
      { key: "2", width: 200, title: "Value Stored", dataType: "object" },
    ],
    data: [
      {
        "1": { title: "<p>0x00</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Scratch Space (Vazio)</p>", tooltip: "", icon: "" },
        id: 0,
      },
      {
        "1": { title: "<p>0x20</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Scratch Space (Vazio)</p>", tooltip: "", icon: "" },
        id: 1,
      },
      {
        "1": { title: "<p>0x40</p>", tooltip: "", icon: "" },
        "2": { title: "<p>0x80 (Nunca atualizamos o Free Memory Pointer, já que todas as operações são feitas manualmente em Yul.)</p>", tooltip: "", icon: "" },
        id: 2,
      },
      {
        "1": { title: "<p>0x60</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Vazio</p>", tooltip: "", icon: "" },
        id: 3,
      },
      {
        "1": { title: "<p>0x80</p>", tooltip: "", icon: "" },
        "2": { title: "<p>0x0000000000000000000000000000000000000000000000000000000000773d45e0 (Function Selector)</p>", tooltip: "", icon: "" },
        id: 4,
      },
      {
        "1": { title: "<p>0xa0</p>", tooltip: "", icon: "" },
        "2": { title: "<p>0x0000000000000000000000000000000000000000000000000000000000000003 (_var1)</p>", tooltip: "", icon: "" },
        id: 5,
      },
      {
        "1": { title: "<p>0xc0</p>", tooltip: "", icon: "" },
        "2": { title: "<p>0x0000000000000000000000000000000000000000000000000000000000000004 (_var2)</p>", tooltip: "", icon: "" },
        id: 6,
      },
      {
        "1": { title: "<p>0xe0</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Vazio</p>", tooltip: "", icon: "" },
        id: 7,
      },
      {
        "1": { title: "<p>0x100</p>", tooltip: "", icon: "" },
        "2": { title: "<p>0x0000000000000000000000000000000000000000000000000000000000000003 (Primeiro valor retornado)</p>", tooltip: "", icon: "" },
        id: 8,
      },
      {
        "1": { title: "<p>0x120</p>", tooltip: "", icon: "" },
        "2": { title: "<p>0x0000000000000000000000000000000000000000000000000000000000000004 (Segundo valor retornado)</p>", tooltip: "", icon: "" },
        id: 9,
      },
      {
        "1": { title: "<p>0x140</p>", tooltip: "", icon: "" },
        "2": { title: "<p>Free Memory Pointer (Vazio)</p>", tooltip: "", icon: "" },
        id: 10,
      },
    ],
  }}
/>

### **Como usar delegate call em yul**

Em nossa última seção, veremos delegatecall\(\). O código será quase idêntico ao de call\(\), com apenas uma mudança.

A única mudança que fizemos foi trocar call\(\) por delegatecall\(\) e remover callvalue\(\). 

Não precisamos de um callvalue\(\), porque delegate call executa o código de CallMe dentro de seu próprio estado. Portanto, o statement require\(\) em a\(\) está verificando se ether foi enviado ao nosso contrato Caller. Se verificarmos var1 e var2 em CallMe, não veremos mudanças. No entanto, var1 e var2 no nosso contrato Caller foram atualizadas com sucesso.

Isso encerra nossa seção sobre chamadas de contrato! A seguir, aprenda como [Memory](http://www.alchemy.com/overviews/yul-memory), [Storage](http://www.alchemy.com/overviews/yul-storage) e [Smart Contract Calls](http://www.alchemy.com/overviews/yul-contract-calls) funcionam em Yul.
