Modo Manutenção em Solidity com Foundry
Ainda não tenho clientes reais em Web3. Mas ao invés de só fazer tutoriais soltos, decidi simular pedidos reais de clientes e resolvê-los como se fossem projetos de verdade do entendimento da dor até o deploy funcionando. Esse é o primeiro caso da série.
O pedido do Cliente (imaginário)
Imagine o seguinte cenário: CryptoMarket, um marketplace de NFTs, já está em produção com usuários reais. O dono me procura com uma dor bem específica:
"Se um bug aparecer no meio da noite, eu preciso conseguir travar as transações imediatamente, sem depender de ninguém, sem precisar rodar um novo deploy. E quando eu resolver, preciso poder destravar do mesmo jeito."
Duas alternativas ruins que ele tinha antes de me procurar:
- Deixar o contrato ativo mesmo sabendo do risco
- Fazer um novo deploy do zero (caro, quebra o endereço já divulgado, perde histórico)
O que eu vou construir
Um mecanismo de Modo Manutenção: um interruptor on-chain que só o dono do contrato pode ligar ou desligar, bloqueando funções críticas enquanto estiver ativo e permitindo que qualquer pessoa consulte o status a qualquer momento (transparência).
Arquitetura antes do código
| Função | Quem pode chamar | O que faz |
|---|---|---|
toggleMaintenance() |
Só o owner | Liga/desliga o modo manutenção |
isUnderMaintenance() |
Qualquer um | Consulta o status atual |
buyNFT() (exemplo) |
Usuários | Só executa se não estiver em manutenção |
O contrato
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract CryptoMarket {
address public owner;
bool public maintenanceMode;
event MaintenanceToggled(bool novoStatus);
constructor() {
owner = msg.sender;
maintenanceMode = false;
}
modifier onlyOwner() {
require(msg.sender == owner, "Apenas o owner pode fazer isso");
_;
}
modifier notInMaintenance() {
require(!maintenanceMode, "Contrato em manutencao no momento");
_;
}
function toggleMaintenance() public onlyOwner {
maintenanceMode = !maintenanceMode;
emit MaintenanceToggled(maintenanceMode);
}
function isUnderMaintenance() public view returns (bool) {
return maintenanceMode;
}
function buyNFT() public notInMaintenance {
}
}
Testando com Foundry
Escrevi 8 testes cobrindo os cenários principais: deploy correto, estado inicial, toggle nos dois sentidos, bloqueio de acesso pra quem não é owner, bloqueio do buyNFT() durante manutenção, e emissão do evento.
forge test -vvv
Todos os 8 testes passaram (8 passed; 0 failed; 0 skipped).
Deploy local com Anvil
Subi uma blockchain local simulada:
anvil
E fiz o deploy do contrato usando a primeira conta pré-financiada como owner:
forge create src/CryptoMarket.sol:CryptoMarket \
--rpc-url http://127.0.0.1:8545 \
--private-key <CHAVE_PRIVADA> \
--broadcast
Deploy feito com sucesso 🎉
-
Deployer (owner):
0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 -
Endereço do contrato:
0x5FbDB2315678afecb367f032d93F642f64180aa3
Interagindo com o contrato via Cast
Com o contrato no ar, testei o fluxo completo na prática não só nos testes, mas em uma blockchain local de verdade.
1. Consultar o status (leitura, sem gastar gas)
cast call 0x5FbDB2315678afecb367f032d93F642f64180aa3 "isUnderMaintenance()(bool)" --rpc-url http://127.0.0.1:8545
Retornou false — o contrato nasce operacional, como esperado.
2. Ativar o modo manutenção (escrita, precisa da chave do owner)
cast send 0x5FbDB2315678afecb367f032d93F642f64180aa3 "toggleMaintenance()" \
--rpc-url http://127.0.0.1:8545 \
--private-key <CHAVE_PRIVADA_DO_OWNER>
Transação minerada com status: 1 (success). Repare no campo logs: ali está o evento MaintenanceToggled sendo emitido on-chain — prova de auditoria, gravada permanentemente na blockchain.
3. Confirmar que mudou
cast call 0x5FbDB2315678afecb367f032d93F642f64180aa3 "isUnderMaintenance()(bool)" --rpc-url http://127.0.0.1:8545
Agora retorna true.
4. Testar o bloqueio
Tentei chamar buyNFT() enquanto o contrato está em manutenção:
cast send 0x5FbDB2315678afecb367f032d93F642f64180aa3 "buyNFT()" \
--rpc-url http://127.0.0.1:8545 \
--private-key <CHAVE_PRIVADA_DO_OWNER>
Error: execution reverted: Contrato em manutencao no momento
Exatamente o comportamento esperado: o modifier notInMaintenance bloqueou a função de negócio.
5. Voltar o status para operacional (false)
cast send 0x5FbDB2315678afecb367f032d93F642f64180aa3 "toggleMaintenance()" \
--rpc-url http://127.0.0.1:8545 \
--private-key <CHAVE_PRIVADA_DO_OWNER>
6. Confirmar que voltou
cast call 0x5FbDB2315678afecb367f032d93F642f64180aa3 "isUnderMaintenance()(bool)" --rpc-url http://127.0.0.1:8545
Retornou false novamente.
7. Testar buyNFT() com o contrato liberado
cast send 0x5FbDB2315678afecb367f032d93F642f64180aa3 "buyNFT()" \
--rpc-url http://127.0.0.1:8545 \
--private-key <CHAVE_PRIVADA_DO_OWNER>
status: 1 (success) sem nenhum erro. O contrato voltou a funcionar normalmente assim que a manutenção foi desativada.
O que essa simulação prova
| Estado | buyNFT() |
|---|---|
Em manutenção (true) |
❌ Reverte com "Contrato em manutencao no momento" |
Operacional (false) |
✅ Executa normalmente |
O ciclo completo — construção, teste, deploy e interação real — funcionou do início ao fim, exatamente como o cliente (imaginário) precisava.
Por que documentar assim
Não tenho clientes reais em Web3 ainda. Mas resolver problemas simulados com o mesmo rigor que teria com um cliente de verdade entender a dor antes de codar, testar com cobertura real, validar em ambiente local antes de qualquer coisa em produção é como estou construindo prática e portfólio ao mesmo tempo.
Código completo no GitHub: https://github.com/Eduprogrammer/solidity-maintenance-mode
Meu Linkedin: https://www.linkedin.com/in/educarlos29/
Se você é dev e tem uma dor parecida com essa (ou outra ideia de "cliente imaginário" pra próxima simulação), comenta aí 👇
#solidity #foundry #web3 #blockchain #smartcontracts #developer










Top comments (0)