Somente para fins educacionais; não constitui recomendação nem aconselhamento de investimento. Investir pode causar perdas.
Resposta direta
Uma incompatibilidade de casas decimais ocorre quando um contrato interpreta um inteiro bruto com o expoente de unidade, a direção do preço ou a escala interna errados. As casas decimais do feed, do token e do token de cotação, as escalas de taxa de wrappers ou cotas e as convenções WAD ou RAY do protocolo são independentes. Uma interface com aparência correta não prova que o contrato consumidor execute a mesma aritmética.
Para uma quantidade bruta do token-base A_raw com d_t casas e uma resposta positiva P_raw que cota um token-base em tokens de cotação com d_p casas, a quantidade bruta do token de cotação com d_q casas é V_raw = round(A_raw * P_raw * 10^d_q / 10^(d_t + d_p)). A fórmula só vale para essa direção e após validar feed, unidades, tipos e regra de arredondamento. Um adapter que já normalizou o valor não pode escalá-lo novamente.
No ERC-20, decimals() é metadado opcional de exibição, não garantia universal de 18 casas. O decimals() de um feed descreve sua resposta, não a escala do token nem do protocolo. A aritmética verificada pode interromper um overflow com revert, mas não detecta fórmula dimensionalmente errada e pode transformar um resultado representável em negação de serviço se um produto intermediário transbordar.
Como funciona
- Fixe rede, bloco, consumidor, adapter, proxy e agregador do feed, token ou vault, versões do compilador e da biblioteca matemática e estado do upgrade.
- Inventarie cada inteiro com tipo e unidade: quantidade bruta, casas do token, resposta assinada e casas do feed, orientação base/cotação, taxa de wrapper ou cota, escala interna e casas do token de saída.
- Valide a fonte antes da conversão: endereço e direção corretos, resposta positiva, timestamp e status, idade e faixa aceitáveis, semântica do fallback e regras de carência do sequenciador L2.
- Derive uma única fórmula dimensional das unidades brutas de entrada às de saída. Separe explicitamente aumento e redução de escala, limite cada expoente de dez e normalize cada parcela uma única vez.
- Use multiplicação-divisão de precisão total comprovada ou cancelamento limitado. Evite truncamento por dividir antes, overflow intermediário, wraparound unchecked e casts assinados ou estreitos inseguros.
- Defina arredondamento para baixo, para cima ou ao mais próximo em cada ação. Garantia, dívida, empréstimo, emissão, resgate, taxas, liquidação e conversão de cotas podem exigir direções conservadoras diferentes.
- Teste vetores conhecidos e propriedades com valores extremos, combinações de casas, recíprocos, feeds compostos, respostas zero, negativas e desatualizadas, upgrades e dust; compare onchain com modelo independente de alta precisão e limite a exposição.
Normalização é análise dimensional, não formatação. BTC/USD e USD/BTC exigem fórmulas recíprocas; trocar o rótulo não inverte o preço. Feeds compostos exigem escala e timestamp de cada parcela. A divisão inteira em Solidity trunca em direção a zero, portanto rearranjos algebricamente equivalentes podem produzir resultados onchain distintos. Um mulDiv de precisão total resolve o problema de largura intermediária, mas ainda exige numerador, denominador, unidades, limites e direção de arredondamento corretos.
Exemplos resolvidos
- Oito contra dezoito casas. Um feed BTC/USD retorna
6,000,000,000,000comd_p = 8, logo o preço é60,000 USD/BTC. Tratar a resposta como 18 casas produz0.000006 USD/BTC, subavaliação de10^10, não10^9. Escalar para WAD resulta em6,000,000,000,000 * 10^(18 - 8) = 60,000,000,000,000,000,000,000. - Unidades de quantidade, preço e saída.
A_raw = 2,500,000representa2.5tokens comd_t = 6;P_raw = 200,000,000representa2tokens de cotação comd_p = 8. Para valor interno de 18 casas,2,500,000 * 200,000,000 * 10^18 / 10^(6 + 8) = 5,000,000,000,000,000,000, ou5 quote tokens. Omitir o denominador do token superavalia a posição em10^6. - Recíproco e truncamento. ETH/USD em WAD é
2,000 * 10^18. USD/ETH na mesma escala éfloor(10^36 / (2,000 * 10^18)) = 500,000,000,000,000, ou0.0005 ETH/USD. Separadamente, comA_raw = 999,999,d_t = 6e preço2 * 10^18, multiply-divide completo produz1,999,998,000,000,000,000; dividir a quantidade por10^6primeiro produz0e perde todo o valor. - Overflow intermediário e arredondamento. Sejam
x = 2^200,y = 2^100e denominador2^100. O resultado exato é2^200, que cabe emuint256, masx * y = 2^300não cabe. A multiplicação verificada reverte e a unchecked faz wrap;mulDivde precisão total retorna2^200. A divisão inteira5 / 2arredonda para baixo em2, enquanto teto retorna3; o arredondamento integra o invariante econômico.
Riscos
- Endereço errado de rede, feed, proxy, adapter, token, vault ou consumidor.
- Orientação base/cotação invertida sem conversão recíproca.
- Supor 18 casas para o token ou metadado opcional indisponível ou errado.
- Supor 8 casas para o feed em vez de lê-las e fixá-las.
- Confundir casas do token de cotação com escala WAD, RAY, de mercado ou contábil.
- Omitir casas de wrapper, cota, índice ou taxa de câmbio.
- Aplicar escala duas vezes após normalização pelo adapter.
- Omitir fator de escala ou denominador necessário.
- Converter resposta assinada para unsigned antes de validar positividade.
- Aceitar resultado zero, desatualizado, incompleto, limitado ou inválido.
- Expoente decimal ou potência de dez sofre underflow, overflow ou excede limites.
- Produto intermediário transborda embora o quociente final caiba.
- Aritmética unchecked, shifts ou casts estreitos fazem wrap ou truncam silenciosamente.
- Dividir antes de multiplicar destrói precisão ou transforma dust em zero.
- Arredondamento para baixo, cima ou próximo é inadequado para a ação.
- Conversões repetidas acumulam perda ou vazamento sistemático de valor.
- Preços, caps, proporções, percentuais, pontos-base, WAD e RAY são comparados em unidades diferentes.
- Upgrades de feed, token, proxy, adapter ou vault invalidam premissas em cache.
- Formatação de interface, wallet, RPC ou indexador esconde cálculo onchain diferente.
- Avaliação errada amplifica empréstimos, emissões, resgates, liquidações, caps, dívida incobrável ou emissão injusta de cotas.
Equívocos comuns
- “Todo token ERC-20 usa 18 casas decimais.” O método de metadados é opcional, e ativos implantados usam valores e comportamentos distintos.
- “Todo feed de preço em USD usa 8 casas.” A precisão pertence à interface do deployment exato e deve ser lida e versionada.
- “Um inteiro bruto grande prova manipulação.” A magnitude não significa nada sem unidades, direção, casas, timestamp e escala do consumidor.
- “Solidity 0.8 torna a escala correta.” Overflow verificado pode reverter, mas não corrige unidades, truncamento, cast nem política de arredondamento.
- “Multiplicar antes de dividir ou adicionar casas sempre melhora a precisão.” Pode transbordar, duplicar escala ou preservar a unidade errada; até aritmética de precisão total exige fórmula correta.
Tópicos relacionados
Fontes
- Data Feeds API Reference - Chainlink Documentation (acesso: 2026-08-13)
- Chainlink Data Feeds - Chainlink Documentation (acesso: 2026-08-13)
- ERC-20: Token Standard - Ethereum Improvement Proposals (acesso: 2026-08-13)
- Types - Solidity Documentation (acesso: 2026-08-13)
- Expressions and Control Structures - Solidity Documentation (acesso: 2026-08-13)
- Utils - OpenZeppelin Contracts Documentation (acesso: 2026-08-13)
- Oracles - Aave Protocol Documentation (acesso: 2026-08-13)
- Compound v2 Price Feed - Compound Documentation (acesso: 2026-08-13)