SwiftHTML & CSSSolidityDesenvolvimento de JogosSolana/Rust
27.11.2024

Aula 150: Construindo um Contrato Multisig

Nesta aula, vamos criar uma carteira de Multassinatura (Multisig) simples usando Solidity. Uma carteira Multisig é um contrato inteligente que requer múltiplas assinaturas (aprovações) antes de executar operações sensíveis, como transferir fundos. Essa camada adicional de segurança é especialmente útil para gerenciar recursos em um ambiente descentralizado.

Pré-requisitos

Você deve ter uma compreensão básica de Solidity e do ecossistema Ethereum. Familiaridade com os seguintes conceitos será benéfica:

  • Contratos inteligentes
  • Funções e modificadores
  • Mapeamentos e arrays

Design da Carteira Multisig

Nossa carteira Multisig permitirá que vários proprietários aprovem transações. As principais características do nosso contrato incluirão:

  1. Adicionar/remover proprietários.
  2. Submeter uma transação.
  3. Aprovar uma transação.
  4. Executar uma transação.

Vamos passar por cada uma dessas funcionalidades.

Implementação do Contrato Multisig

Aqui está uma implementação de exemplo de um contrato de carteira Multisig simples:

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

contract MultisigWallet {
    address[] public owners;
    mapping(address => bool) public isOwner;
    uint256 public requiredApprovals;

    struct Transaction {
        address to;
        uint256 value;
        bool executed;
        uint256 approvals;
        mapping(address => bool) isApproved;
    }

    Transaction[] public transactions;

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

    modifier transactionExists(uint256 transactionId) {
        require(transactionId < transactions.length, "Transação não existe");
        _;
    }

    modifier notExecuted(uint256 transactionId) {
        require(!transactions[transactionId].executed, "Transação já executada");
        _;
    }

    constructor(address[] memory _owners, uint256 _requiredApprovals) {
        require(_owners.length > 0, "Proprietários são necessários");
        require(_requiredApprovals > 0 && _requiredApprovals <= _owners.length, "Número inválido de aprovações");

        for (uint256 i = 0; i < _owners.length; i++) {
            address owner = _owners[i];
            require(owner != address(0), "Proprietário inválido");
            require(!isOwner[owner], "Proprietário já adicionado");
            isOwner[owner] = true;
            owners.push(owner);
        }

        requiredApprovals = _requiredApprovals;
    }

    function submitTransaction(address to, uint256 value) public onlyOwner {
        Transaction storage newTransaction = transactions.push();
        newTransaction.to = to;
        newTransaction.value = value;
        newTransaction.executed = false;
        newTransaction.approvals = 0;
    }

    function approveTransaction(uint256 transactionId) public onlyOwner transactionExists(transactionId) notExecuted(transactionId) {
        Transaction storage transaction = transactions[transactionId];
        require(!transaction.isApproved[msg.sender], "Transação já aprovada");

        transaction.isApproved[msg.sender] = true;
        transaction.approvals++;

        if (transaction.approvals >= requiredApprovals) {
            executeTransaction(transactionId);
        }
    }

    function executeTransaction(uint256 transactionId) internal transactionExists(transactionId) notExecuted(transactionId) {
        Transaction storage transaction = transactions[transactionId];
        require(transaction.approvals >= requiredApprovals, "Número insuficiente de aprovações");

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

    receive() external payable {} // Permite que o contrato receba Ether
}

Análise do Contrato

Variáveis de Estado

  • owners: Um array de endereços que representam os proprietários da carteira Multisig.
  • isOwner: Um mapeamento para verificar de forma eficiente se um endereço é um proprietário.
  • requiredApprovals: O número de aprovações necessárias para executar uma transação.
  • transactions: Um array para armazenar as transações submetidas.

Modificadores

  • onlyOwner: Restringe o acesso às funções apenas para os proprietários do contrato.
  • transactionExists: Valida se um ID de transação existe.
  • notExecuted: Assegura que uma transação ainda não tenha sido executada.

Construtor

O construtor inicializa o contrato com a lista de proprietários e o número necessário de aprovações.

Funções

  • submitTransaction: Permite que os proprietários submetam uma nova transação.
  • approveTransaction: Habilita os proprietários a aprovarem uma transação submetida. Se receber aprovações suficientes, ela chama automaticamente executeTransaction.
  • executeTransaction: Executa a transação se o número necessário de aprovações for alcançado.

Recepção de Ether

A função receive permite que o contrato aceite Ether enviado para ele.

Conclusão

Agora você criou uma carteira Multisig simples que pode gerenciar transações Ethereum com segurança, exigindo múltiplas aprovações. Essa implementação básica pode ser expandida com mais funcionalidades, como remover proprietários, lidar com cancelamentos de transações e fornecer melhor rastreamento do histórico de transações.

Usando uma carteira Multisig, você pode aprimorar significativamente a segurança da gestão de fundos na blockchain do Ethereum. Boa programação!

Video

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

Thank you for voting!