Fundamentos de Funções, Armazenamento e Unidades em Solidity

Definição de Retornos em Funções

Em Solidity, a definição de valores de retorno ocorre na assinatura da função utilizando a palavra-chave returns, anquanto a entrega efetiva dos dados é feita através do comando return dentro do corpo da função. Existe também a possibilidade de usar retornos nomeados, onde as variáveis são declaradas na assinatura e atribuídas diretamente no corpo, sendo retornadas implicitamente ao final da execução.

Para consumir esses valores, especialmente quando há múltiplos retornos, pode-se utilizar a desestruturação de tuplas, permitindo selecionar apenas os dados relevantes.

// SPDX-License-Identifier: MIT
pragma solidity 0.8.0;

contract OperacoesContract {
    int public valorInicial = 5;

    // Retorno padrão usando tupla
    function calcular(int _entrada) public view returns (int, int) {
        return (valorInicial - _entrada, valorInicial * _entrada);
    }

    // Retorno utilizando variáveis nomeadas
    function calcularNomeado(int _entrada) public view returns (int resultadoA, int resultadoB) {
        resultadoA = valorInicial - _entrada;
        resultadoB = valorInicial * _entrada;
        // Retorna implicitamente resultadoA e resultadoB
    }

    // Captura de retornos via desestruturação
    function obterResultados() public view {
        int _val1;
        int _val2;

        // Captura todos os valores
        (_val1, _val2) = calcular(2);
        
        // Captura apenas o primeiro valor, ignorando o segundo
        (_val1, ) = calcular(3);
    }
}

Locais de Armazenamento e Custos de Gas

A especificação do local de dados é obrigatória para tipos complexos como arrays, structs e mappings. A escolha entre storage, memory e calldata impacta diretamente o custo de execução (gas) e a persistência dos dados.

Local Características
storage Persistente na blockchain. Custo de gas elevado.
memory Temporário, existe apanas durante a execução. Custo de gas menor.
caldata Temporário e não modificável. Usado geralmente em parâmetros externos. Custo mínimo.

Por padrão, variáveis de estado utilizam storage. Parâmetros de funções e retornos usam calldata (para externos) ou memory. Variáveis locais dentro de funções são memory por padrão.

O calldata não é armazenado na memória convencional do contrato. É uma área de dados especial, somente leitura, contendo os argumentos da chamada externa. Ela não persiste após a execução da função e não altera o estado do contrato.

A atribuição de tipos de referência cria um ponteiro para o dados originais. Modificar o ponteiro afeta o original se estiver em storage, mas não se for uma cópia em memory.

contract TesteArmazenamento {
    uint256[] public vetorEstado = [10, 20, 30];

    // Modifica o estado permanente pois usa referência storage
    function alterarPersistente() public {
        uint256[] storage refArmazenamento = vetorEstado;
        refArmazenamento[0] = 500;
    }

    // Cria uma cópia em memória, o estado permanente não é afetado
    function alterarTemporario() public view {
        uint256[] memory refMemoria = vetorEstado;
        refMemoria[0] = 500;
    }

    // Demonstra referência em memória: ambas variáveis apontam para o mesmo local
    function verificarReferencia() public view returns (uint256) {
        uint256[] memory copiaA = vetorEstado;
        uint256[] memory copiaB = copiaA;
        
        copiaB[0] = 500;
        return copiaA[0]; // Retornará 500 devido à referência compartilhada
    }
}

Escopo de Variáveis e Globais

As variáveis em Solidity são classificadas conforme sua visibilidade e local de armazenamento:

  • Variáveis de Estado: Persistem na chain, acessíveis por todas as funções, alto custo de gas.
  • Variáveis Locais: Existem apenas durante a execução da função, armazenadas em memória, baixo custo.
  • Variáveis Globais: Palavras-chave reservadas fornecidas pelo ambiente de execução.

Exemplos comuns de variáveis globais incluem msg.sender (endereço do chamador), msg.data (payload da chamada) e block.number (número do bloco atual).

Denominações de Ether

Para facilitar a leitura e escrita de valores monetários, a Solidity oferece sufixos que representam múltiplos de Wei, a menor unidade da rede Ethereum.

  • wei: Unidade base (1).
  • gwei: Equivale a 10^9 wei.
  • ether: Equivale a 10^18 wei (1 ETH).
contract ValidadorMoeda {
    function confirmarValores() public pure returns (bool) {
        bool checkWei = 1 wei == 1;
        bool checkGwei = 1 gwei == 1e9;
        bool checkEther = 1 ether == 1e18;
        
        return checkWei && checkGwei && checkEther;
    }
}

Unidades de Tempo

Contratos inteligentes frequentemente necessitam de lógica baseada em tempo, como prazos de execução ou validação de janelas temporais. A linguagem fornece modificadores literais para representar segundos, minutos, horas, dias e semanas.

pragma solidity ^0.8.0;

contract TarefaComPrazo {
    uint public limiteTempo;

    constructor() {
        // Define o prazo para 2 dias a partir do momento da implantação
        limiteTempo = block.timestamp + 2 days;
    }

    function realizarTarefa() public {
        require(block.timestamp <= limiteTempo, "O prazo para esta ação expirou");
        // Lógica da operação vai aqui
    }
}

No exemplo acima, o construtor calcula um timestamp futuro somando unidades de tempo ao timestamp atual. A função de execução valida se o tempo corrente ainda está dentro do limite permitido antes de prosseguir.

As unidades de tempo disponíveis são convertidas internamente para segundos:

  • seconds: 1
  • minutes: 60
  • hours: 3600
  • days: 86400
  • weeks: 604800

Tags: solidity ethereum smart-contracts gas-optimization evm

Publicado em 10-11 17:14