Lição: 262: Escrevendo Contratos em Yul
Nesta aula, vamos explorar o Yul, uma linguagem intermediária projetada para o Ethereum. O Yul é particularmente útil para escrever contratos inteligentes em baixo nível otimizados para casos de uso específicos, especialmente para implantações que exigem uma execução mais eficiente ou otimização de gás.
Introdução ao Yul
Yul é uma linguagem de baixo nível que oferece um equilíbrio entre o Solidity de alto nível e o bytecode EVM. É frequentemente usada para escrever contratos que precisam de otimizações ou que exigem operações complexas que são complicadas no Solidity.
Sintaxe Básica
O código Yul é estruturado de uma forma que lembra a assembly, mas mantém uma legibilidade de nível superior. Aqui está uma estrutura básica de um contrato Yul:
object "MeuContrato" {
code {
// O código do construtor vai aqui
// Ex: opcode para criar o contrato
let resultado := create(0, data, size)
// Armazena o resultado (endereço do contrato)
mstore(0x00, resultado)
return(0x00, 0x20)
}
data {
// Dados do contrato, tipicamente dados de inicialização ou seletores de função
}
}
Escrevendo um Contrato Yul Simples
Vamos escrever um contrato Yul simples que armazena um número e permite que os usuários recuperem esse número.
object "ArmazenamentoSimples" {
code {
// O código de inicialização do contrato
// Aloca um armazenamento na posição zero
sstore(0, 0) // Inicializa o armazenamento com 0
// Início da execução principal
let seletor := calldataload(0) // Seletor da função chamada
switch seletor
case 0x60fe47b1 { // Função: set(uint256)
let num := calldataload(4) // Carrega o número de entrada
sstore(0, num) // Armazena o número
return(0, 0) // Retorna da função
}
case 0x70a08231 { // Função: get()
let valorArmazenado := sload(0) // Carrega o número armazenado
mstore(0x0, valorArmazenado) // Armazena na memória
return(0x0, 0x20) // Retorna o número
}
default {
revert(0, 0) // Reverte se o método não for encontrado
}
}
}
Explicação do Código
-
Inicialização do Armazenamento: Inicializamos a variável de armazenamento na posição
0
com0
. -
Seleção de Função: A declaração
switch
verifica o seletor de função que é passado nos dados da transação. -
Função Set:
- A função com o seletor
0x60fe47b1
(o hash da assinatura da funçãoset(uint256)
) recupera os dados docalldata
, armazena o novo número no armazenamento do contrato e não retorna saída.
- A função com o seletor
-
Função Get:
- A função com o seletor
0x70a08231
(o hash deget()
) recupera o valor armazenado no armazenamento do contrato e o retorna.
- A função com o seletor
-
Reverter: Se o seletor da função não corresponder a nenhum caso, a função reverte.
Implantando o Contrato Yul
Para implantar o contrato Yul, você pode usar a Máquina Virtual Ethereum (EVM) ou o compilador Solidity com o backend Yul. No caso de uso do Solidity, você normalmente usaria uma abordagem de assembly inline para chamar o código Yul:
pragma solidity ^0.8.0;
contract ImplantarYul {
function implantar() external returns (address) {
address novoContrato;
assembly {
// Implante o contrato Yul abaixo
novoContrato := create(0, add(0x40, code), mload(code))
}
return novoContrato;
}
}
// O código Yul real será inserido onde necessário acima, da seção anterior
A abordagem pode variar; a implantação também pode ser feita usando o solc
, o compilador do Ethereum que suporta diretamente o Yul.
Conclusão
O Yul fornece uma maneira poderosa de escrever contratos inteligentes que exigem operações de baixo nível, especificamente voltados para otimização de gás e desempenho. Embora desenvolver em Yul exija um bom entendimento da Máquina Virtual Ethereum e da mecânica dos contratos inteligentes, oferece aos desenvolvedores a capacidade de escrever aplicações descentralizadas de alto desempenho.
À medida que você avança em sua jornada com o Yul, lembre-se de experimentar funcionalidades mais complexas e sempre testar seus contratos de forma abrangente para garantir sua confiabilidade e segurança. Boa codificação!