Recentemente, tenho revisado o Solidity para reforçar alguns detalhes e estou escrevendo um "Guia Simples do Solidity" para iniciantes (os experts em programação podem procurar outros tutoriais). Atualizo de 1 a 3 lições por semana.
Twitter: @0xAA_Science
Comunidade: Discord | Grupo do WeChat | Site da WTF Academy
Todo código e tutorial estão disponíveis no GitHub: github.com/AmazingAng/WTF-Solidity
Nesta lição, vamos falar sobre os três métodos para lançar exceções no Solidity: error, require e assert, e comparar o consumo de gas entre eles.
Ao escrever contratos inteligentes, é comum encontrar bugs. Os comandos de exceção do Solidity nos ajudam a fazer depuração.
error é um recurso adicionado na versão 0.8.21 do Solidity, que permite explicar de forma eficiente (e econômica em termos de gas) o motivo de uma operação falhar. É possível definir exceções fora dos contratos. Abaixo, definimos a exceção TransferNotOwner, que é lançada quando alguém que não é o dono da moeda tenta fazer uma transferência:
error TransferNotOwner(); // Erro personalizadoTambém podemos definir uma exceção com parâmetros, para mostrar o endereço que tentou fazer a transferência:
error TransferNotOwner(address sender); // Erro personalizado com parâmetrosDurante a execução, o error deve ser usado em conjunto com o comando revert:
function transferOwner1(uint256 tokenId, address newOwner) public {
if(_owners[tokenId] != msg.sender){
revert TransferNotOwner();
// revert TransferNotOwner(msg.sender);
}
_owners[tokenId] = newOwner;
}Definimos a função transferOwner1(), que verifica se o remetente é o dono da moeda. Se não for, uma exceção de TransferNotOwner é lançada; se for, a transferência é feita.
O comando require é uma maneira comum de lançar exceções antes da versão 0.8 do Solidity e ainda é amplamente utilizado. A desvantagem do require é que o consumo de gas aumenta com o tamanho da descrição da exceção, em comparação com o comando error. A sintaxe é: require(condição de verificação, "descrição da exceção"). Quando a condição não é atendida, uma exceção é lançada.
Podemos reescrever a função transferOwner1 usando o comando require:
function transferOwner2(uint256 tokenId, address newOwner) public {
require(_owners[tokenId] == msg.sender, "Transfer Not Owner");
_owners[tokenId] = newOwner;
}O comando assert geralmente é usado pelos programadores durante a depuração do código, pois não fornece uma explicação do motivo da exceção (ao contrário do require). A sintaxe é simples: assert(condição). Se a condição não for atendida, uma exceção é lançada.
Podemos reescrever a função transferOwner1 usando o comando assert:
function transferOwner3(uint256 tokenId, address newOwner) public {
assert(_owners[tokenId] == msg.sender);
_owners[tokenId] = newOwner;
}-
Insira um número
uint256qualquer e um endereço não nulo, chame a funçãotransferOwner1(comerror), e no console do Remix será exibida a nossa exceção customizadaTransferNotOwner. -
Insira um número
uint256qualquer e um endereço não nulo, chame a funçãotransferOwner2(comrequire), e no console do Remix será exibida a descrição da exceção do comandorequire. -
Insira um número
uint256qualquer e um endereço não nulo, chame a funçãotransferOwner3(comassert), e apenas a exceção será lançada no console do Remix.
Comparamos o consumo de gas dos três métodos de exceção no Remix, usando o botão de Debug do console, encontramos os seguintes valores:
(compilado com a versão 0.8.17)
- Consumo de
gasdo métodoerror: 24457 (Com parâmetro, consumo degas: 24660) - Consumo de
gasdo métodorequire: 24755 - Consumo de
gasdo métodoassert: 24473
Podemos observar que o método error é o que consome menos gas, seguido pelo assert, e o require consome mais gas. Portanto, o error é uma boa opção, pois informa o motivo da exceção e consome menos gas.
Observação: Antes da versão 0.8.0 do Solidity, o assert lançava uma panic exception que consumia todo o gas restante, sem reembolso. Mais detalhes podem ser encontrados na documentação oficial.
Nesta lição, aprendemos sobre os três métodos para lançar exceções no Solidity: error, require e assert, e comparamos o consumo de gas entre eles. Concluímos que o error é uma opção eficiente, pois fornece explicação da exceção e consome menos gas.