Codificação de ABI

Similar a abi.encode, mas codifica os argumentos de uma maneira mais compacta, sem preenchimento, o que pode ser útil para certas operações criptográficas. No entanto, a falta de preenchimento pode levar a ambiguidades em certas situações, portanto, deve ser usado com cautela.

Exemplo:

bytes memory packedData = abi.encodePacked(arg1, arg2);

abi.encodeWithSelector(bytes4 selector, ...) returns (bytes memory)

Uso: Codifica os argumentos fornecidos com um seletor de função específico. Útil para chamadas de funções em contratos externos quando o seletor da função é conhecido.

Exemplo:

bytes memory dataWithSelector = abi.encodeWithSelector(selector, arg1, arg2);

O seletor de função é essencialmente a assinatura da função codificada em 4 bytes. Essa funcionalidade é particularmente útil ao fazer chamadas de baixo nível ou ao interagir com contratos cujas interfaces podem não estar totalmente definidas no momento da compilação.


Vamos incluir um exemplo de como usar abi.encodeWithSelector em Solidity para preparar dados para uma chamada de contrato de baixo nível:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract Receiver {

    event Received(uint256 indexed value, address sender);

    // Uma função simples que emite um evento com o valor e o remetente
    function receiveValue(uint256 value) public {
        emit Received(value, msg.sender);
    }
}

contract Caller {

    // Função que chama `receiveValue` no contrato Receiver usando abi.encodeWithSelector
    function callReceiveValue(address _receiver, uint256 _value) public {
        
        // Primeiro, calculamos o seletor da função.
        // A assinatura da função é "receiveValue(uint256)"
        bytes4 selector = bytes4(keccak256("receiveValue(uint256)"));

        // Em seguida, codificamos o seletor junto com os argumentos da função.
        bytes memory data = abi.encodeWithSelector(selector, _value);

        // Realizamos a chamada de baixo nível.
        (bool success, ) = _receiver.call(data);

        require(success, "A chamada falhou.");
    }
}

Neste exemplo:

  • Receiver: É um contrato que possui uma função receiveValue, que emite um evento quando chamada. Essa função pode conter qualquer lógica que você deseja invocar em outro contrato.

  • Caller: É um contrato que realiza uma chamada ao contrato Receiver. Ele usa abi.encodeWithSelector para preparar os dados da chamada. Isso inclui o seletor da função, que identifica qual função chamar no contrato Receiver, e os argumentos para essa função.

    • bytes4 selector = bytes4(keccak256("receiveValue(uint256)")); calcula o seletor da função com base na sua assinatura. A assinatura é simplesmente o nome da função seguido dos tipos de seus parâmetros entre parênteses, codificado em 4 bytes.

    • abi.encodeWithSelector(selector, _value) codifica esses dados em um formato que o contrato Receiver pode decodificar e executar.


abi.encodeWithSignature(string memory signature, ...) returns (bytes memory)

Similar a abi.encodeWithSelector, mas em vez de fornecer o seletor de função como um valor bytes4, a assinatura da função é fornecida como uma string. O Solidity calcula o seletor de função correspondente.

Exemplo:

bytes memory dataWithSignature = abi.encodeWithSignature("functionName(uint256,address)", arg1, arg2);

Neste exemplo, functionName(uint256,address) é a assinatura da função.


abi.decode(bytes memory data, (type1, type2, ...)) returns (type1, type2, ...)

Decodifica os dados codificados de acordo com as regras ABI nos tipos especificados. É útil para interpretar os dados de saída de chamadas de funções de baixo nível ou respostas de chamadas a outros contratos.

Exemplo:

// Exemplo de decodificação de dados de retorno
(uint256 value, address sender) = abi.decode(data, (uint256, address));

Last updated