Lição: 149: Carteiras Multisig
As carteiras multisig, comumente referidas como carteiras com múltiplas assinaturas, são uma ferramenta poderosa no mundo das criptomoedas. Elas fornecem segurança aprimorada, exigindo múltiplas assinaturas ou aprovações antes que uma transação possa ser executada. Nesta aula, exploraremos o conceito de carteiras multisig e como implementar uma usando Solidity.
O que é uma Carteira Multisig?
Uma carteira multisig é um tipo de carteira digital que requer múltiplas chaves privadas para autorizar uma transação. Em vez de confiar em uma única chave privada, uma carteira multisig permite uma abordagem mais colaborativa para a segurança. Isso é especialmente útil para organizações ou grupos que precisam gerenciar fundos coletivamente.
Componentes Principais
- Proprietários: Indivíduos que têm a autoridade para assinar transações.
- Assinaturas Necessárias: O número mínimo de assinaturas necessário para validar uma transação.
- Transações: As ações que precisam ser aprovadas pelos proprietários.
Implementação Exemplo
Vamos criar uma carteira multisig simples usando Solidity.
Passo 1: Definir o Contrato
Começaremos definindo nosso contrato de carteira multisig.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract MultiSigWallet {
address[] public owners;
mapping(address => bool) public isOwner;
uint public requiredSignatures;
struct Transaction {
address to;
uint value;
bool executed;
uint numConfirmations;
mapping(address => bool) isConfirmed;
}
Transaction[] public transactions;
event Deposit(address indexed sender, uint amount);
event Submit(uint indexed txIndex, address indexed to, uint value);
event Confirm(uint indexed txIndex, address indexed owner);
event Execute(uint indexed txIndex, address indexed owner);
event Revoke(uint indexed txIndex, address indexed owner);
modifier onlyOwner() {
require(isOwner[msg.sender], "Não é um proprietário");
_;
}
modifier txExists(uint txIndex) {
require(txIndex < transactions.length, "Transação não existe");
_;
}
modifier notExecuted(uint txIndex) {
require(!transactions[txIndex].executed, "Transação já executada");
_;
}
modifier notConfirmed(uint txIndex) {
require(!transactions[txIndex].isConfirmed[msg.sender], "Transação já confirmada");
_;
}
constructor(address[] memory _owners, uint _requiredSignatures) {
require(_owners.length > 0, "Proprietários requeridos");
require(_requiredSignatures > 0 && _requiredSignatures <= _owners.length, "Número inválido de assinaturas requeridas");
for (uint i = 0; i < _owners.length; i++) {
address owner = _owners[i];
require(owner != address(0), "Proprietário inválido");
require(!isOwner[owner], "Proprietário não único");
isOwner[owner] = true;
owners.push(owner);
}
requiredSignatures = _requiredSignatures;
}
}
Passo 2: Depositando Fundos
A seguir, vamos implementar uma função que permite aos proprietários depositarem Ether na carteira multisig.
receive() external payable {
emit Deposit(msg.sender, msg.value);
}
Esta função escuta por Ether recebido e registra o evento de depósito.
Passo 3: Criando Transações
Adicionar uma função para criar transações que precisam ser confirmadas pelos proprietários.
function submitTransaction(address to, uint value) external onlyOwner {
uint txIndex = transactions.length;
transactions.push();
Transaction storage t = transactions[txIndex];
t.to = to;
t.value = value;
t.executed = false;
t.numConfirmations = 0;
emit Submit(txIndex, to, value);
}
Passo 4: Confirmando Transações
Os proprietários podem confirmar transações com as quais concordam.
function confirmTransaction(uint txIndex)
external
onlyOwner
txExists(txIndex)
notExecuted(txIndex)
notConfirmed(txIndex)
{
Transaction storage transaction = transactions[txIndex];
transaction.isConfirmed[msg.sender] = true;
transaction.numConfirmations++;
emit Confirm(txIndex, msg.sender);
}
Passo 5: Executando Transações
Uma vez que uma transação tenha confirmações suficientes, ela pode ser executada.
function executeTransaction(uint txIndex)
external
onlyOwner
txExists(txIndex)
notExecuted(txIndex)
{
Transaction storage transaction = transactions[txIndex];
require(transaction.numConfirmations >= requiredSignatures, "Não há confirmações suficientes");
transaction.executed = true;
(bool success, ) = transaction.to.call{value: transaction.value}("");
require(success, "Transação falhou");
emit Execute(txIndex, msg.sender);
}
Considerações Finais
As carteiras multisig proporcionam uma camada adicional de segurança para a gestão de ativos em criptomoedas. Ao exigir múltiplas assinaturas, elas minimizam o risco de transações não autorizadas. Esta implementação simples demonstra como criar uma carteira multisig em Solidity, mas muitas otimizações e recursos adicionais podem ser incorporados para uso em produção.
Lembre-se sempre de testar seus contratos inteligentes minuciosamente antes de implantá-los na mainnet, já que erros podem resultar na perda de fundos.