Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
561 changes: 557 additions & 4 deletions README.md

Large diffs are not rendered by default.

144 changes: 144 additions & 0 deletions SECURITY_AUDIT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# Auditoria de Segurança - AdvertisementManager

## Vulnerabilidades Críticas

### 1. **CRITICAL: Bug no Construtor do AdToken**
```solidity
constructor() ERC20("AdToken", "A+") {
owner = owner; // ❌ Isto atribui owner a si mesmo (sempre 0x0)
// Deveria ser: owner = msg.sender;
}
```
**Impacto**: O owner nunca é definido corretamente, ficando como address(0).
**Severidade**: CRÍTICA
**Correção**: `owner = msg.sender;`

### 2. **CRITICAL: Reentrancy em recordEngagement**
```solidity
function recordEngagement(uint256 _adIndex) external nonReentrant whenNotPaused {
// ... código ...
adToken.mint(msg.sender, reward); // ❌ Mint externo antes de atualizar estado
user.lastEngagementTime = block.timestamp;
}
```
**Impacto**: Apesar do nonReentrant, a ordem de operações pode causar problemas.
**Severidade**: ALTA
**Correção**: Seguir o padrão Checks-Effects-Interactions.

### 3. **HIGH: Integer Overflow em distributeReferralRewards**
```solidity
for (uint256 i = 0; i < 3 && currentReferrer != address(0); i++) {
UD60x18 reward = amount.mul(ud(10e18).sub(ud(i * 2e18))).div(ud(100e18));
// ❌ Se i > 5, sub() pode underflow
}
```
**Impacto**: Underflow pode causar valores inesperados.
**Severidade**: ALTA
**Correção**: Adicionar validações ou limitar o loop.

### 4. **MEDIUM: Gas Limit em awardWeeklyBonus**
```solidity
for (uint256 i = 0; i < advertisements.length; i++) {
address advertiser = advertisements[i].advertiser;
if (weeklyEngagements[advertiser] > maxEngagements) {
maxEngagements = weeklyEngagements[advertiser];
topEngager = advertiser;
}
}
// ❌ Pode exceder gas limit com muitos anúncios
```
**Impacto**: Função pode se tornar inutilizável.
**Severidade**: MÉDIA
**Correção**: Implementar paginação ou usar estrutura de dados otimizada.

### 5. **MEDIUM: Falta de validação em createAdvertisement**
```solidity
function createAdvertisement(
string memory _link,
string memory _imageUrl,
address _referrer
) public payable {
// ❌ Sem validação de _link e _imageUrl vazios
}
```
**Impacto**: Anúncios inválidos podem ser criados.
**Severidade**: MÉDIA
**Correção**: Adicionar validações de input.

### 6. **LOW: Divisão por zero em getUserStats**
```solidity
function distributeCommunityReward() internal {
uint256 rewardPerParticipant = currentChallenge.reward / advertisements.length;
// ❌ Se advertisements.length == 0, divisão por zero
}
```
**Impacto**: Revert inesperado.
**Severidade**: BAIXA
**Correção**: Adicionar verificação.

## Problemas de Design

### 7. **Design Issue: Reset de weeklyEngagements ineficiente**
```solidity
for (uint256 i = 0; i < advertisements.length; i++) {
address advertiser = advertisements[i].advertiser;
weeklyEngagements[advertiser] = 0;
}
```
**Impacto**: Alto consumo de gas, possível DoS.
**Correção**: Usar epoch-based tracking.

### 8. **Design Issue: Falta de limites em loops**
- `getActiveAds()` itera sobre todos os anúncios
- `getUserEngagedAds()` pode retornar arrays enormes
**Correção**: Implementar paginação.

### 9. **Centralization Risk: Múltiplos papéis admin**
- ADMIN_ROLE pode pausar, sacar fundos, recuperar tokens
- Risco de abuso de poder
**Correção**: Implementar timelock e multi-sig.

### 10. **Missing Events**
- Faltam eventos em várias funções administrativas
- Dificulta auditoria off-chain

## Questões de Otimização de Gas

### 11. **Storage vs Memory**
```solidity
Advertisement storage ad = advertisements[_adIndex];
Advertiser storage user = advertisers[msg.sender];
// ✅ Correto uso de storage
```

### 12. **Múltiplas leituras de storage**
```solidity
if (chefOfAdvertising != address(0) && chefOfAdvertising != msg.sender) {
// ❌ Lê chefOfAdvertising 2 vezes
}
```
**Correção**: Cachear em variável local.

## Resumo de Correções Necessárias

| # | Vulnerabilidade | Severidade | Status |
|---|----------------|------------|--------|
| 1 | Bug no construtor AdToken | CRÍTICA | 🔴 Corrigir |
| 2 | Reentrancy em recordEngagement | ALTA | 🔴 Corrigir |
| 3 | Integer overflow em referrals | ALTA | 🔴 Corrigir |
| 4 | Gas limit em awardWeeklyBonus | MÉDIA | 🟡 Corrigir |
| 5 | Validação de inputs | MÉDIA | 🟡 Corrigir |
| 6 | Divisão por zero | BAIXA | 🟡 Corrigir |
| 7 | Reset ineficiente | MÉDIA | 🟡 Otimizar |
| 8 | Falta de paginação | MÉDIA | 🟡 Implementar |
| 9 | Centralização | BAIXA | 🟢 Documentar |
| 10 | Eventos faltando | BAIXA | 🟢 Adicionar |

## Recomendações Gerais

1. **Adicionar testes de fuzzing** para encontrar edge cases
2. **Implementar circuit breakers** para pausar em emergências
3. **Adicionar rate limiting** para prevenir spam
4. **Implementar upgrade pattern** (UUPS ou Transparent Proxy)
5. **Realizar auditoria externa** antes do deploy em produção
6. **Implementar monitoring off-chain** para detectar comportamentos anômalos
215 changes: 215 additions & 0 deletions deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
#!/bin/bash

# Script de Deploy Simplificado para AdvertisementManager
# Uso: ./deploy.sh [network]

set -e

# Cores para output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Banner
echo -e "${BLUE}"
echo "╔═══════════════════════════════════════════════════════════════════════╗"
echo "║ ║"
echo "║ █████╗ ██████╗ ███╗ ███╗ █████╗ ███╗ ██╗ █████╗ ██████╗ ║"
echo "║ ██╔══██╗██╔══██╗ ████╗ ████║██╔══██╗████╗ ██║██╔══██╗██╔════╝ ║"
echo "║ ███████║██║ ██║ ██╔████╔██║███████║██╔██╗ ██║███████║██║ ███╗ ║"
echo "║ ██╔══██║██║ ██║ ██║╚██╔╝██║██╔══██║██║╚██╗██║██╔══██║██║ ██║ ║"
echo "║ ██║ ██║██████╔╝ ██║ ╚═╝ ██║██║ ██║██║ ╚████║██║ ██║╚██████╔╝ ║"
echo "║ ╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═════╝ ║"
echo "║ ║"
echo "║ DEPLOYMENT SCRIPT v1.0 ║"
echo "║ ║"
echo "╚═══════════════════════════════════════════════════════════════════════╝"
echo -e "${NC}"

# Verificar se .env existe
if [ ! -f .env ]; then
echo -e "${RED}❌ Erro: Arquivo .env não encontrado!${NC}"
echo -e "${YELLOW}💡 Copie .env.example para .env e configure suas variáveis${NC}"
exit 1
fi

# Carregar .env
source .env

# Verificar PRIVATE_KEY
if [ -z "$PRIVATE_KEY" ]; then
echo -e "${RED}❌ Erro: PRIVATE_KEY não definida no .env${NC}"
exit 1
fi

# Função para mostrar menu
show_menu() {
echo -e "\n${BLUE}═══════════════════════════════════════${NC}"
echo -e "${BLUE} Selecione a Rede para Deploy${NC}"
echo -e "${BLUE}═══════════════════════════════════════${NC}\n"

echo -e "${GREEN}MAINNETS:${NC}"
echo " 1) Celo Mainnet"
echo " 2) Scroll Mainnet"
echo " 3) Base Mainnet"
echo " 4) Optimism Mainnet"
echo " 5) Arbitrum One"
echo " 6) Polygon Mainnet"
echo " 7) Ethereum Mainnet"

echo -e "\n${YELLOW}TESTNETS:${NC}"
echo " 8) Celo Alfajores"
echo " 9) Scroll Sepolia"
echo " 10) Base Sepolia"
echo " 11) Optimism Sepolia"
echo " 12) Arbitrum Sepolia"
echo " 13) Mumbai Testnet"
echo " 14) Sepolia Testnet"

echo -e "\n${RED} 0) Sair${NC}\n"
}

# Função para deploy
deploy_to_network() {
local network_name=$1
local rpc_url=$2
local api_key=$3
local chain_id=$4

echo -e "\n${BLUE}═══════════════════════════════════════${NC}"
echo -e "${BLUE} Deploying to ${network_name}${NC}"
echo -e "${BLUE}═══════════════════════════════════════${NC}\n"

# Verificar se RPC está configurado
if [ -z "$rpc_url" ]; then
echo -e "${RED}❌ RPC URL não configurada para ${network_name}${NC}"
echo -e "${YELLOW}💡 Configure no .env${NC}"
return 1
fi

echo -e "${YELLOW}📡 RPC URL: ${rpc_url}${NC}"
echo -e "${YELLOW}🔗 Chain ID: ${chain_id}${NC}\n"

# Executar testes primeiro
echo -e "${BLUE}🧪 Executando testes...${NC}"
if ! forge test; then
echo -e "${RED}❌ Testes falharam! Deploy cancelado.${NC}"
return 1
fi
echo -e "${GREEN}✅ Testes passaram!${NC}\n"

# Confirmar deploy
echo -e "${YELLOW}⚠️ Você está prestes a fazer deploy em ${network_name}${NC}"
read -p "Continuar? (s/N): " confirm

if [[ ! $confirm =~ ^[Ss]$ ]]; then
echo -e "${YELLOW}Deploy cancelado${NC}"
return 0
fi

# Deploy
echo -e "\n${BLUE}🚀 Iniciando deploy...${NC}\n"

if [ -z "$api_key" ]; then
# Deploy sem verificação
forge script script/DeployMultiChain.s.sol:DeployAdvertisementManager \
--rpc-url "$rpc_url" \
--broadcast \
--legacy
else
# Deploy com verificação
forge script script/DeployMultiChain.s.sol:DeployAdvertisementManager \
--rpc-url "$rpc_url" \
--broadcast \
--verify \
--etherscan-api-key "$api_key" \
--legacy
fi

if [ $? -eq 0 ]; then
echo -e "\n${GREEN}✅ Deploy concluído com sucesso!${NC}"
echo -e "${BLUE}📝 Verifique deployments/ para os endereços${NC}\n"

# Mostrar próximos passos
echo -e "${YELLOW}═══════════════════════════════════════${NC}"
echo -e "${YELLOW} PRÓXIMOS PASSOS${NC}"
echo -e "${YELLOW}═══════════════════════════════════════${NC}"
echo -e "1. Verifique o contrato no explorer"
echo -e "2. Configure achievements iniciais"
echo -e "3. Inicie o primeiro desafio comunitário"
echo -e "4. Atualize seu frontend com o novo endereço"
echo -e "${YELLOW}═══════════════════════════════════════${NC}\n"
else
echo -e "\n${RED}❌ Deploy falhou!${NC}"
return 1
fi
}

# Menu principal
if [ -z "$1" ]; then
while true; do
show_menu
read -p "Escolha uma opção: " choice

case $choice in
1) deploy_to_network "Celo Mainnet" "$CELO_RPC_URL" "$CELOSCAN_API_KEY" "42220" ;;
2) deploy_to_network "Scroll Mainnet" "$SCROLL_RPC_URL" "$SCROLLSCAN_API_KEY" "534352" ;;
3) deploy_to_network "Base Mainnet" "$BASE_RPC_URL" "$BASESCAN_API_KEY" "8453" ;;
4) deploy_to_network "Optimism Mainnet" "$OPTIMISM_RPC_URL" "$OPTIMISTIC_ETHERSCAN_API_KEY" "10" ;;
5) deploy_to_network "Arbitrum One" "$ARBITRUM_RPC_URL" "$ARBISCAN_API_KEY" "42161" ;;
6) deploy_to_network "Polygon Mainnet" "$POLYGON_RPC_URL" "$POLYGONSCAN_API_KEY" "137" ;;
7) deploy_to_network "Ethereum Mainnet" "$ETHEREUM_RPC_URL" "$ETHERSCAN_API_KEY" "1" ;;
8) deploy_to_network "Celo Alfajores" "$CELO_ALFAJORES_RPC_URL" "$CELOSCAN_API_KEY" "44787" ;;
9) deploy_to_network "Scroll Sepolia" "$SCROLL_SEPOLIA_RPC_URL" "$SCROLLSCAN_API_KEY" "534351" ;;
10) deploy_to_network "Base Sepolia" "$BASE_SEPOLIA_RPC_URL" "$BASESCAN_API_KEY" "84532" ;;
11) deploy_to_network "Optimism Sepolia" "$OPTIMISM_SEPOLIA_RPC_URL" "$OPTIMISTIC_ETHERSCAN_API_KEY" "11155420" ;;
12) deploy_to_network "Arbitrum Sepolia" "$ARBITRUM_SEPOLIA_RPC_URL" "$ARBISCAN_API_KEY" "421614" ;;
13) deploy_to_network "Mumbai Testnet" "$MUMBAI_RPC_URL" "$POLYGONSCAN_API_KEY" "80001" ;;
14) deploy_to_network "Sepolia Testnet" "$SEPOLIA_RPC_URL" "$ETHERSCAN_API_KEY" "11155111" ;;
0)
echo -e "\n${GREEN}👋 Até logo!${NC}\n"
exit 0
;;
*)
echo -e "${RED}❌ Opção inválida!${NC}"
;;
esac

echo -e "\n${YELLOW}Pressione ENTER para continuar...${NC}"
read
done
else
# Deploy direto via argumento
network=$1

case $network in
celo) deploy_to_network "Celo Mainnet" "$CELO_RPC_URL" "$CELOSCAN_API_KEY" "42220" ;;
celo-testnet) deploy_to_network "Celo Alfajores" "$CELO_ALFAJORES_RPC_URL" "$CELOSCAN_API_KEY" "44787" ;;
scroll) deploy_to_network "Scroll Mainnet" "$SCROLL_RPC_URL" "$SCROLLSCAN_API_KEY" "534352" ;;
scroll-testnet) deploy_to_network "Scroll Sepolia" "$SCROLL_SEPOLIA_RPC_URL" "$SCROLLSCAN_API_KEY" "534351" ;;
base) deploy_to_network "Base Mainnet" "$BASE_RPC_URL" "$BASESCAN_API_KEY" "8453" ;;
base-testnet) deploy_to_network "Base Sepolia" "$BASE_SEPOLIA_RPC_URL" "$BASESCAN_API_KEY" "84532" ;;
optimism) deploy_to_network "Optimism Mainnet" "$OPTIMISM_RPC_URL" "$OPTIMISTIC_ETHERSCAN_API_KEY" "10" ;;
optimism-testnet) deploy_to_network "Optimism Sepolia" "$OPTIMISM_SEPOLIA_RPC_URL" "$OPTIMISTIC_ETHERSCAN_API_KEY" "11155420" ;;
arbitrum) deploy_to_network "Arbitrum One" "$ARBITRUM_RPC_URL" "$ARBISCAN_API_KEY" "42161" ;;
arbitrum-testnet) deploy_to_network "Arbitrum Sepolia" "$ARBITRUM_SEPOLIA_RPC_URL" "$ARBISCAN_API_KEY" "421614" ;;
polygon) deploy_to_network "Polygon Mainnet" "$POLYGON_RPC_URL" "$POLYGONSCAN_API_KEY" "137" ;;
polygon-testnet) deploy_to_network "Mumbai Testnet" "$MUMBAI_RPC_URL" "$POLYGONSCAN_API_KEY" "80001" ;;
ethereum) deploy_to_network "Ethereum Mainnet" "$ETHEREUM_RPC_URL" "$ETHERSCAN_API_KEY" "1" ;;
ethereum-testnet) deploy_to_network "Sepolia Testnet" "$SEPOLIA_RPC_URL" "$ETHERSCAN_API_KEY" "11155111" ;;
*)
echo -e "${RED}❌ Rede desconhecida: $network${NC}"
echo -e "${YELLOW}💡 Redes disponíveis:${NC}"
echo " - celo, celo-testnet"
echo " - scroll, scroll-testnet"
echo " - base, base-testnet"
echo " - optimism, optimism-testnet"
echo " - arbitrum, arbitrum-testnet"
echo " - polygon, polygon-testnet"
echo " - ethereum, ethereum-testnet"
exit 1
;;
esac
fi
8 changes: 8 additions & 0 deletions deployments/42220-1762097766.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"chainId": 42220,
"network": "Celo Mainnet",
"AdvertisementManager": "0xdc461a5b7Dd3527612867b08A2cCc87416b44879",
"AdToken": "0x89A3236224086d43D56981ff928E4645aaa29F7A",
"timestamp": 1762097766,
"deployer": "0xd1a8Dd23e356B9fAE27dF5DeF9ea025A602EC81e"
}
Loading
Loading