O que Segurança de AMM DeFi faz?
Padrões críticos de vulnerabilidade e implementações robustas para contratos AMM Solidity, vaults de LP e funções de swap.
Quando Usar
- Escrevendo ou auditando um contrato AMM ou pool de liquidez em Solidity
- Implementando fluxos de swap, depósito, saque, mint ou burn que mantêm saldos de tokens
- Revisando qualquer contrato que use
token.balanceOf(address(this))em matemática de shares ou reservas - Adicionando setters de taxas, pausadores, atualizações de oráculos ou outras funções administrativas a um protocolo DeFi
Como Funciona
Use esta skill como uma biblioteca de lista de verificação mais padrões. Revise cada ponto de entrada do usuário em relação às categorias abaixo e prefira os exemplos robustos em vez de variantes feitas manualmente.
Segurança de Execução
Os comandos shell nesta skill são exemplos locais de auditoria. Execute-os apenas em um checkout confiável ou sandbox descartável, e não insira nomes de contratos, caminhos, URLs RPC, chaves privadas ou flags fornecidas pelo usuário não confiáveis em comandos shell. Pergunte antes de instalar ferramentas ou executar jobs longos de fuzzing/análise estática que possam consumir recursos locais ou pagos significativos.
Nunca inclua segredos, chaves privadas, frases semente, tokens de API ou credenciais de assinatura de mainnet em exemplos de comando, logs ou relatórios.
Exemplos
Reentrância: impor ordem CEI
Vulnerável:
function withdraw(uint256 amount) external {
require(balances[msg.sender] >= amount);
token.transfer(msg.sender, amount);
balances[msg.sender] -= amount;
}
Seguro:
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
using SafeERC20 for IERC20;
function withdraw(uint256 amount) external nonReentrant {
require(balances[msg.sender] >= amount, "Insufficient");
balances[msg.sender] -= amount;
token.safeTransfer(msg.sender, amount);
}
Não escreva seu próprio guard quando uma biblioteca robusta existir.
Ataques de doação ou inflação
Usar token.balanceOf(address(this)) diretamente para matemática de shares permite que atacantes manipulem o denominador enviando tokens para o contrato fora do caminho pretendido.
// Vulnerável
function deposit(uint256 assets) external returns (uint256 shares) {
shares = (assets * totalShares) / token.balanceOf(address(this));
}
// Seguro
uint256 private _totalAssets;
function deposit(uint256 assets) external nonReentrant returns (uint256 shares) {
uint256 balBefore = token.balanceOf(address(this));
token.safeTransferFrom(msg.sender, address(this), assets);
uint256 received = token.balanceOf(address(this)) - balBefore;
shares = totalShares == 0 ? received : (received * totalShares) / _totalAssets;
_totalAssets += received;
totalShares += shares;
}
Mantenha contabilidade interna e meça os tokens realmente recebidos.
Manipulação de oráculos
Preços spot são manipuláveis por flash loans. Prefira TWAP.
uint32[] memory secondsAgos = new uint32[](2);
secondsAgos[0] = 1800;
secondsAgos[1] = 0;
(int56[] memory tickCumulatives,) = IUniswapV3Pool(pool).observe(secondsAgos);
int24 twapTick = int24(
(tickCumulatives[1] - tickCumulatives[0]) / int56(uint56(30 minutes))
);
uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(twapTick);
Proteção contra slippage
Cada caminho de swap precisa de slippage fornecido pelo chamador e um prazo final.
function swap(
uint256 amountIn,
uint256 amountOutMin,
uint256 deadline
) external returns (uint256 amountOut) {
require(block.timestamp <= deadline, "Expired");
amountOut = _calculateOut(amountIn);
require(amountOut >= amountOutMin, "Slippage exceeded");
_executeSwap(amountIn, amountOut);
}
Matemática segura de reservas
import {FullMath} from "@uniswap/v3-core/contracts/libraries/FullMath.sol";
uint256 result = FullMath.mulDiv(a, b, c);
Para matemática de grandes reservas, evite a * b / c ingênuo quando houver risco de overflow.
Controles administrativos
import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
contract MyAMM is Ownable2Step {
function setFee(uint256 fee) external onlyOwner { ... }
function pause() external onlyOwner { ... }
}
Prefira aceitação explícita para transferência de propriedade e proteja cada caminho privilegiado.
Lista de Verificação de Segurança
- Pontos de entrada expostos a reentrância usam
nonReentrant - Ordenação CEI é respeitada
- Matemática de shares não depende de
balanceOf(address(this))bruto - Transferências ERC-20 usam
SafeERC20 - Depósitos medem tokens realmente recebidos
- Leituras de oráculo usam TWAP ou outra fonte resistente a manipulação
- Swaps exigem
amountOutMinedeadline - Matemática de reservas sensível a overflow usa primitivas seguras como
mulDiv - Funções administrativas são controladas por acesso
- Pausa de emergência existe e é testada
- Análise estática e fuzzing são executados antes da produção
Ferramentas de Auditoria
pip install slither-analyzer
slither . --exclude-dependencies
echidna-test . --contract YourAMM --config echidna.yaml
forge test --fuzz-runs 10000