O que Segurança de AMM DeFi faz?
Padrões críticos de vulnerabilidade e implementações robustas para contratos Solidity de AMM, vaults de LP e funções de swap.
Quando Usar
- Escrevendo ou auditando um contrato Solidity de AMM ou pool de liquidez
- Implementando fluxos de swap, depósito, retirada, 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 taxa, pausers, atualizações de oráculo ou outras funções administrativas a um protocolo DeFi
Como Funciona
Use isto como um checklist combinado com uma biblioteca de 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 de 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 contrato, caminhos, URLs de RPC, chaves privadas ou flags fornecidas pelo usuário não confiáveis em comandos de shell. Pergunte antes de instalar ferramentas ou executar trabalhos longos de fuzzing/análise estática que possam consumir recursos locais ou pagos significativos.
Nunca inclua segredos, chaves privadas, seed phrases, tokens de API ou credenciais de assinatura da mainnet em exemplos de comando, logs ou relatórios.
Exemplos
Reentrância: aplicar ordenação 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, "Insuficiente");
balances[msg.sender] -= amount;
token.safeTransfer(msg.sender, amount);
}
Não escreva seu próprio guard quando uma biblioteca auditada 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 uma contabilidade interna e meça os tokens efetivamente recebidos.
Manipulação de oráculo
Preços spot são manipuláveis por empréstimos relâmpago. 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
Todo caminho de swap precisa de slippage fornecido pelo chamador e um deadline.
function swap(
uint256 amountIn,
uint256 amountOutMin,
uint256 deadline
) external returns (uint256 amountOut) {
require(block.timestamp <= deadline, "Expirado");
amountOut = _calculateOut(amountIn);
require(amountOut >= amountOutMin, "Slippage excedido");
_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 grandes operações com reservas, evite a * b / c ingênuo quando houver risco de estouro.
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 bloqueie todo caminho privilegiado.
Checklist de Segurança
- Pontos de entrada expostos a reentrância usam
nonReentrant - A ordenação CEI é respeitada
- A matemática de shares não depende de
balanceOf(address(this))bruto - Transferências ERC-20 usam
SafeERC20 - Depósitos medem tokens efetivamente recebidos
- Leituras de oráculo usam TWAP ou outra fonte resistente a manipulação
- Swaps exigem
amountOutMinedeadline - Matemática de reservas suscetível a estouro usa primitivas seguras como
mulDiv - Funções administrativas são controladas por acesso
- Existe pausa de emergência e ela é 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