MultiSig
Múltiplas assinaturas: 2-de-3, 3-de-5, etc.
Conceitos ensinados: - Múltiplos approvers - Voting pattern - Proposals - Execution control
Código
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title MultiSigSimples
* @dev Múltiplas assinaturas: 2-de-3, 3-de-5, etc
* Ensina: múltiplos approvers, voting pattern, execution
*
* Como testar no Remix:
* 1. Deploy com 3 signatários e assinaturasNecessarias = 2.
* 2. Envie ETH para o contrato (botão receive ou transação simples).
* 3. Um signatário chama submeterProposta(alvo, valor, dados).
* 4. Dois signatários diferentes chamam aprovarProposta(id).
* 5. Chame executarProposta(id) e valide a execução com evento.
*/
contract MultiSigSimples {
// Signatários autorizados
address[] public signatarios;
mapping(address => bool) public ehSignatario;
// Quantas aprovações são necessárias
uint256 public assinaturasNecessarias;
// Proposta de transação
struct Proposta {
uint256 id;
address alvo;
uint256 valor;
bytes dados;
uint256 aprovacoes;
bool executada;
}
Proposta[] public propostas;
mapping(uint256 => mapping(address => bool)) public jaAprovou;
event PropostaSubmetida(uint256 indexed id, address alvo, uint256 valor);
event PropostaAprovada(uint256 indexed id, address signatario);
event PropostaExecutada(uint256 indexed id);
constructor(address[] memory _signatarios, uint256 _assinaturasNecessarias) {
require(_signatarios.length >= _assinaturasNecessarias, "Signatarios insuficiente");
for (uint256 i = 0; i < _signatarios.length; i++) {
signatarios.push(_signatarios[i]);
ehSignatario[_signatarios[i]] = true;
}
assinaturasNecessarias = _assinaturasNecessarias;
}
modifier apenasSignatario() {
require(ehSignatario[msg.sender], "Nao e signatario");
_;
}
/**
* @dev Submete uma nova proposta de transação
*/
function submeterProposta(
address _alvo,
uint256 _valor,
bytes memory _dados
) public apenasSignatario {
propostas.push(Proposta({
id: propostas.length,
alvo: _alvo,
valor: _valor,
dados: _dados,
aprovacoes: 0,
executada: false
}));
emit PropostaSubmetida(propostas.length - 1, _alvo, _valor);
}
/**
* @dev Aprova uma proposta
*/
function aprovarProposta(uint256 _id) public apenasSignatario {
require(_id < propostas.length, "Proposta invalida");
require(!propostas[_id].executada, "Ja foi executada");
require(!jaAprovou[_id][msg.sender], "Ja aprovou");
jaAprovou[_id][msg.sender] = true;
propostas[_id].aprovacoes += 1;
emit PropostaAprovada(_id, msg.sender);
}
/**
* @dev Executa uma proposta se tiver aprovações suficientes
*/
function executarProposta(uint256 _id) public apenasSignatario {
require(_id < propostas.length, "Proposta invalida");
require(!propostas[_id].executada, "Ja foi executada");
require(propostas[_id].aprovacoes >= assinaturasNecessarias, "Aprovacoes insuficiente");
Proposta storage proposta = propostas[_id];
proposta.executada = true;
// Executa a transação
(bool sucesso, ) = proposta.alvo.call{value: proposta.valor}(proposta.dados);
require(sucesso, "Execucao falhou");
emit PropostaExecutada(_id);
}
/**
* @dev Total de propostas criadas
*/
function totalPropostas() public view returns (uint256) {
return propostas.length;
}
/**
* @dev Vê informações de uma proposta
*/
function verProposta(uint256 _id) public view returns (Proposta memory) {
require(_id < propostas.length, "Proposta invalida");
return propostas[_id];
}
// Para receber ETH
receive() external payable {}
}
Como Testar no Remix
- Deploy com array de 3 signatários e
_assinaturasNecessarias= 2 - Envie 1 ETH para o contrato (via campo Value + Deploy ou
receive()) - Signatário 1 chama
submeterProposta(endereço_externo, 1000000000000000000, "") - Signatário 2 chama
aprovarProposta(0) - Signatário 3 chama
aprovarProposta(0) - Qualquer signatário chama
executarProposta(0)→ ETH enviado
Use Case
Tesouro coletivo • DAOs • Contratos seguros de produção