WEB3DEV

Cover image for abi.encode, abi.encodePacked e abi.decode no Solidity
Isabela Curado Nehme
Isabela Curado Nehme

Posted on

abi.encode, abi.encodePacked e abi.decode no Solidity

https://miro.medium.com/v2/resize:fit:720/format:webp/1*ZQzSOlLYBwqA9leSTjIyNg.png

No Solidity, várias funções importantes para codificação e decodificação de dados são abi.encode, encodePacked, decode, string.concat, bytes.concat e, finalmente, conversão de tipo usando bytes ou strings.

Essas funções permitem converter tipos de dados do Solidity, como strings, inteiros, endereços, etc., em uma representação binária compacta e vice-versa.

Compreender como codificar e decodificar dados adequadamente é essencial ao construir contratos inteligentes que precisam emitir eventos, retornar dados aos clientes ou interagir com contratos e protocolos externos.

Não ter uma boa ideia de como fazer isso pode levar a bugs, comportamento não intencional ou desperdício de taxas de gás.

Neste artigo, daremos uma olhada de baixo nível em como essas funções de codificação do Solidity funcionam sob o capô. Exploraremos as principais diferenças entre encode e encodePacked e quando usar cada um. Também abordaremos algumas armadilhas e problemas comuns que podem surgir ao codificar e decodificar dados em seus contratos.

Como diria Patrick, vamos mergulhar na toca do coelho. Espero te ver do outro lado.

Pré-requisito

  • Conhecimento básico de Solidity ou qualquer linguagem de programação
  • Remix IDE

abi.encode

abi.encode é uma função do Solidity que faz parte do mecanismo de codificação da Application Binary Interface (ABI) ou interface binária de aplicação. Ela codifica principalmente múltiplos valores em um formato binário bem compactado.

function encodeValue() public pure returns (bytes memory){
    bytes memory vals = abi.encode("Scofield course", "is easy to grasp");
    return vals;
    }
Enter fullscreen mode Exit fullscreen mode

Por exemplo, queremos codificar "scofield course" e "is easy to grasp". Criamos nossa função e definimos a memória como memória de bytes, lembrando que qualquer coisa armazenada na memória não é retida, ao contrário do armazenamento que guarda valor.

Criamos uma variável de bytes, codificamos nosso valor nela e em seguida, retornamos o valor em vals, enquanto abi.encode agrupa todos os valores.

https://miro.medium.com/v2/resize:fit:720/format:webp/0*69Xnh3fYzwwvjaVH.png

Existem muitos preenchimentos, e é por isso que a função abi.encodePacked é necessária.

abi.encodePacked

A seguir esta função abi.encodePacked, que foi projetada especificamente para compactar múltiplos valores sem adicionar qualquer preenchimento. Ela concatena os dados binários brutos de cada parâmetro.

Um exemplo:

function encodeValue2() public pure returns (bytes memory){
    bytes memory vals = abi.encodePacked("Scofield course", "is easy to grasp");
        return vals;
   }
Enter fullscreen mode Exit fullscreen mode

O mesmo exemplo que o anterior, apenas alteramos a forma como ele é compactado. Aqui está o resultado:

https://miro.medium.com/v2/resize:fit:720/format:webp/0*cS1uQKdpbrhv4jLX.png

A versão compactada remove todo o preenchimento enquanto obtemos apenas o valor em retorno, economizando gás e nos permitindo ainda usar o valor do byte recuperado.

TypeCasting

Typecasting refere-se à conversão explícita de uma variável de um tipo de dados para outro.

Se você sabe um pouco sobre typecasting, pode argumentar: por que não simplesmente fazemos typecasting e obtemos o mesmo resultado? Se você for iniciante, consulte este artigo para saber mais sobre typecasting.

function encodeB() public pure returns(bytes memory) {
       bytes memory value = bytes("Scofield course", "is easy to grasp");
        return value;
    }
Enter fullscreen mode Exit fullscreen mode

Testamos isso e obtivemos esse erro.

TypeError: Exactly one argument expected for explicit type conversion.
  --> encode.sol:18:30:
  |
18 |         bytes memory value = bytes("Scofield course", "is easy to grasp");
  |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Enter fullscreen mode Exit fullscreen mode

Só poderíamos receber um argumento por vez, o que, se ainda continuássemos usando esse método, talvez nos fizesse ter que definir mais bytes de memória, da seguinte forma:

function encodeB() public pure returns(bytes memory, bytes memory) {
    bytes memory value1 = bytes("Scofield course");
    bytes memory value2 = bytes("is easy to grasp");
    return (value1, value2);
Enter fullscreen mode Exit fullscreen mode

Observe que ainda temos que separá-los e também separar o resultado. Mesmo que sejam iguais, estão em uma memória separada, o que não é o que buscamos.

https://miro.medium.com/v2/resize:fit:720/format:webp/0*bAmMgNhYWzoGBDwi.png

bytes.concat

bytes.concat é especializada em concatenar arrays de bytes brutos, garantindo que o resultado seja um array de bytes devidamente alinhado. Falta a versatilidade do abi.encodePacked para lidar com múltiplos tipos de dados.

function encodB() public pure returns(bytes memory) {
        bytes memory value = bytes.concat("my name is ", "scofield");
            return value;
    }
Enter fullscreen mode Exit fullscreen mode

bytes.concat junta arrays de bytes de ponta a ponta, preservando o alinhamento. Funciona apenas em arrays de bytes.

https://miro.medium.com/v2/resize:fit:720/format:webp/0*AwwDzPoONl1pFAg9.png

Lembre-se de que só pode funcionar para determinados tipos de dados e não para todos, como encode.

string.concat

A função string.concat no Solidity permite unir várias strings em uma nova string única. Isso evita a necessidade de adicioná-las manualmente com a adição básica de strings.

function encodB() public pure returns(string memory) {
        string memory value = string.concat("my name is ", "scofield");
            return value;
    }
Enter fullscreen mode Exit fullscreen mode

Aqui, adicionamos “my name is” a “scofield” e o resultado é o que está abaixo.

abi.decode

Se você está se perguntando se conseguiremos recuperar nosso valor convertido após a conversão, você está certo; podemos, com a função abi.decode.

abi.decode permite decodificar parâmetros codificados de chamadas de contrato externos. Ele descompacta os dados codificados para que seu contrato do Solidity possa trabalhar novamente com os valores originais.

A decodificação de parâmetros de dados com abi.decode é essencial para trabalhar com valores de retorno de chamadas de função de contrato externos. Também permite que seu contrato aceite e processe parâmetros de entrada codificados de usuários e outros contratos.

Por exemplo:

function decodeValue() public pure returns (string memory){
        string memory vals = abi.decode(encodeValue() , (string));
            return vals;
        }
Enter fullscreen mode Exit fullscreen mode

Temos que mudar a memória de bytes para strings à medida que convertemos de volta para strings e então copiamos a função encodeValue() mais a (string), que gera isto.

https://miro.medium.com/v2/resize:fit:720/format:webp/0*dh-Qd2w3mLNt0Aa1.png

OH NÃO!!!!

Recebemos apenas metade do nosso valor codificado. O que aconteceu com a outra metade? Se você conseguir descobrir, deixe um comentário abaixo para que eu possa saber.

Fontes

Presenteie-nos com uma xícara de café se você for gentil.

Este artigo foi escrito por Scofield O. Idehen, e traduzido por Isabela Curado Nehme. Seu original pode ser lido aqui.

Oldest comments (0)