SwiftHTML & CSSSolidityDesenvolvimento de JogosSolana/Rust
28.11.2024

Lição 169: Entendendo a Abstração de Conta

A abstração de conta é um conceito no Ethereum que visa simplificar e aprimorar a forma como contas interagem com contratos inteligentes. Tradicionalmente, o Ethereum possui dois tipos de contas: Contas Externamente Controladas (EOAs) e Contas de Contrato. A abstração de conta permite uma gestão de conta mais flexível ao tratar EOAs e contas de contrato de maneira unificada. Esta lição irá explorar os princípios por trás da abstração de conta e fornecer exemplos para ilustrar sua aplicação.

O que é Abstração de Conta?

No Ethereum, existem dois tipos principais de contas:

  1. Contas Externamente Controladas (EOAs): Controladas por chaves privadas. Podem enviar transações e manter Ether, mas não contêm qualquer código.

  2. Contas de Contrato: Geridas pelo código dentro do próprio contrato. Podem manter Ether, executar funções e ter seu próprio estado.

A abstração de conta propõe um mecanismo onde as funcionalidades de ambas as contas podem ser mescladas. Isso significa que os usuários podem definir suas próprias regras para transações e como suas contas interagem com contratos.

Benefícios da Abstração de Conta

  • Flexibilidade: Os usuários podem criar contas inteligentes com lógica de validação personalizada.
  • Segurança Aprimorada: Mecanismos melhorados para autenticação de transações.
  • Experiência do Usuário: Abstrair complexidades como pagamento de gás e assinatura de transações.

Como Funciona

A abstração de conta permite que os usuários criem carteiras de contrato inteligente que podem ser programadas para lidar com transações recebidas de várias maneiras. Por exemplo, uma carteira inteligente pode ser projetada para exigir aprovações de múltiplas assinaturas ou impor limites de gastos.

Exemplo: Carteira Básica de Contrato Inteligente

Abaixo está um exemplo de uma carteira básica de contrato inteligente que demonstra os princípios da abstração de conta.

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

contract SmartWallet {
    address public owner;

    // Evento para registrar transações
    event TransactionExecuted(address indexed to, uint256 value, bytes data);

    constructor() {
        owner = msg.sender;  // Define o criador do contrato como o proprietário
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Não é o proprietário da carteira");
        _;
    }

    // Função para executar transações
    function executeTransaction(address to, uint256 value, bytes memory data) public onlyOwner returns (bytes memory) {
        (bool success, bytes memory returnData) = to.call{value: value}(data);
        require(success, "Transação falhou");
        emit TransactionExecuted(to, value, data);
        return returnData;
    }

    // Função para receber Ether
    receive() external payable {}
}

Explicação do Contrato SmartWallet

  1. Gestão do Proprietário: O contrato define o criador como o proprietário. Somente o proprietário pode executar transações.

  2. Executar Transação: A função executeTransaction permite que o proprietário envie Ether e execute outras funções de contrato em uma única transação. Ela utiliza call para flexibilidade e manipulação de erros.

  3. Recebendo Ether: O contrato pode receber Ether usando a função receive.

Aprimorando a Segurança com Multisig

A abstração de conta pode ser estendida para integrar padrões de segurança, como carteiras de múltiplas assinaturas. Abaixo está um exemplo de uma implementação de múltiplas assinaturas:

pragma solidity ^0.8.0;

contract MultiSigWallet {
    address[] public owners;
    uint256 public required;

    struct Transaction {
        address to;
        uint256 value;
        bytes data;
        bool executed;
    }

    mapping(uint256 => Transaction) public transactions;
    mapping(uint256 => mapping(address => bool)) public confirmations;

    uint256 public transactionCount;

    event SubmitTransaction(address indexed owner, uint256 indexed txIndex);
    event ConfirmTransaction(address indexed owner, uint256 indexed txIndex);
    event ExecuteTransaction(uint256 indexed txIndex);

    constructor(address[] memory _owners, uint256 _required) {
        owners = _owners;
        required = _required;
    }

    modifier onlyOwner() {
        require(isOwner(msg.sender), "Não é um proprietário");
        _;
    }

    modifier txExists(uint256 txIndex) {
        require(txIndex < transactionCount, "Transação não existe");
        _;
    }

    function isOwner(address owner) internal view returns (bool) {
        for (uint i = 0; i < owners.length; i++) {
            if (owners[i] == owner) return true;
        }
        return false;
    }

    function submitTransaction(address to, uint256 value, bytes memory data) public onlyOwner {
        uint256 txIndex = transactionCount;
        transactions[txIndex] = Transaction(to, value, data, false);
        transactionCount++;

        emit SubmitTransaction(msg.sender, txIndex);
    }

    function confirmTransaction(uint256 txIndex) public onlyOwner txExists(txIndex) {
        confirmations[txIndex][msg.sender] = true;
        emit ConfirmTransaction(msg.sender, txIndex);
    }

    function executeTransaction(uint256 txIndex) public onlyOwner txExists(txIndex) {
        require(isConfirmed(txIndex), "Confirmações insuficientes");
        require(!transactions[txIndex].executed, "Transação já executada");

        Transaction storage txn = transactions[txIndex];
        txn.executed = true;

        (bool success,) = txn.to.call{value: txn.value}(txn.data);
        require(success, "Transação falhou");

        emit ExecuteTransaction(txIndex);
    }

    function isConfirmed(uint256 txIndex) internal view returns (bool) {
        uint256 count = 0;
        for (uint i = 0; i < owners.length; i++) {
            if (confirmations[txIndex][owners[i]]) count++;
            if (count == required) return true;
        }
        return false;
    }

    receive() external payable {}
}

Explicação do Contrato MultiSigWallet

  1. Proprietários e Assinaturas Requeridas: O contrato mantém uma lista de proprietários e o número de confirmações necessárias para executar uma transação.

  2. Gestão de Transações: Os proprietários podem submeter transações que registrarão o destino, valor e quaisquer dados. Cada transação requer um número mínimo de confirmações antes da execução.

  3. Lógica de Confirmação: A função confirmTransaction permite que os proprietários confirmem uma transação, e a função executeTransaction a executa assim que confirmações suficientes são coletadas.

Conclusão

A abstração de conta abre as portas para mecanismos inovadores de gestão de conta no Ethereum. Ao permitir que contas—tanto EOAs quanto contas de contrato—sejam mais flexíveis e programáveis, os desenvolvedores podem melhorar a segurança e a experiência do usuário. Através dos exemplos fornecidos, você pode ver a implementação básica de carteiras inteligentes e como elas podem ser expandidas para incluir capacidades de múltiplas assinaturas. À medida que o Ethereum continua a evoluir, a abstração de conta provavelmente desempenhará um papel importante em seu desenvolvimento e usabilidade.

Video

Did you like this article? Rate it from 1 to 5:

Thank you for voting!