﻿---
title: "预言机小数位错配"
description: "小数位错配会对预言机答案、代币数量、封装汇率或协议数值采用错误单位缩放，导致借贷、铸造、赎回和清算出现数量级错误。"
image: "https://wiki.fcontext.com/og.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://wiki.fcontext.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 预言机小数位错配

> 仅供教育参考，不构成投资建议；投资可能产生损失。

<a id="answer"></a>

## 直接答案

当合约以错误的单位指数、价格方向或内部尺度解释原始整数时，就会发生预言机小数位错配。数据源小数位、代币小数位、报价代币小数位、封装或份额兑换率尺度，以及协议的 WAD 或 RAY 约定彼此独立。前端显示正确，不代表消费合约执行了相同运算。

对于基础代币原始数量 `A_raw`，其小数位为 `d_t`；正数数据源答案 `P_raw` 以小数位 `d_p` 表示“每个基础代币值多少报价代币”。若报价代币小数位为 `d_q`，其原始数量为 `V_raw = round(A_raw * P_raw * 10^d_q / 10^(d_t + d_p))`。该公式仅适用于所述报价方向，并须先验证数据源、单位、类型及舍入规则。适配器已归一化的数值不得再次缩放。

ERC-20 的 `decimals()` 是可选显示元数据，不保证统一为 18 位。数据源的 `decimals()` 描述该数据源响应，而非代币或协议尺度。检查型运算可通过回滚阻止溢出，但无法发现量纲错误的公式；若中间乘积溢出，还可能使原本可表示的结果变成拒绝服务。

<a id="mechanism"></a>

## 运作方式

1. 锁定链、区块、消费方、适配器、数据源代理与聚合器、代币或金库、编译器与数学库版本，以及升级状态。
2. 清点每个整数的类型与单位：原始代币数量、代币小数位、有符号数据源答案、数据源小数位、基础与报价方向、封装或份额汇率、协议内部尺度及输出代币小数位。
3. 转换前验证来源：地址与方向正确、答案为正、时间戳和状态有效、年龄与范围可接受、回退语义明确，并在适用时检查 L2 排序器宽限规则。
4. 从输入原始单位推导到输出原始单位的单一量纲公式。放大与缩小时明确分支，限制每个十次幂指数，每一项只归一化一次。
5. 使用经证明的全精度乘除法或有界约分策略。避免先除后乘截断、受检中间值溢出、unchecked 回绕，以及不安全的有符号或窄化转换。
6. 为每项经济操作规定向下、向上或最接近舍入。抵押品、债务、借款、铸造、赎回、费用、清算及金库份额转换可能需要不同的保守方向。
7. 对极端数量、小数位组合、倒数、复合数据源、零值、负值、过时答案、升级及尘埃值运行黄金向量与性质测试；用独立高精度模型核对链上结果，并限制受影响敞口。

归一化是量纲分析，不是格式化。`BTC/USD` 与 `USD/BTC` 需要倒数公式；改标签不会反转价格。复合数据源要求每一项的尺度与时间戳。Solidity 整数除法向零截断，因此代数上等价的重排可能产生不同链上结果。全精度 `mulDiv` 解决中间位宽问题，但调用方仍须提供正确的分子、分母、单位、边界与舍入方向。

<a id="example"></a>

## 计算示例

- **八位与十八位小数。** BTC/USD 数据源返回 `6,000,000,000,000`，且 `d_p = 8`，所以价格为 `60,000 USD/BTC`。把原始答案当作 18 位小数会得到 `0.000006 USD/BTC`，低估 `10^10` 倍，而非 `10^9`。将价格缩放至 WAD 得到 `6,000,000,000,000 * 10^(18 - 8) = 60,000,000,000,000,000,000,000`。
- **数量、价格与输出单位。** `A_raw = 2,500,000` 代表 `2.5` 个代币，其小数位为 `d_t = 6`；`P_raw = 200,000,000` 代表 `2` 个报价代币，其小数位为 `d_p = 8`。对于 18 位内部报价数值，`2,500,000 * 200,000,000 * 10^18 / 10^(6 + 8) = 5,000,000,000,000,000,000`，即 `5 quote tokens`。省略代币分母会高估 `10^6` 倍。
- **倒数与截断。** WAD 尺度的 ETH/USD 为 `2,000 * 10^18`。同尺度的 USD/ETH 为 `floor(10^36 / (2,000 * 10^18)) = 500,000,000,000,000`，即 `0.0005 ETH/USD`。另有 `A_raw = 999,999`、`d_t = 6`、价格 `2 * 10^18` 时，全精度乘除得到 `1,999,998,000,000,000,000`；若先将数量除以 `10^6`，结果为 `0`，全部价值丢失。
- **中间溢出与舍入。** 设 `x = 2^200`、`y = 2^100`、分母为 `2^100`。精确结果是 `2^200`，可放入 `uint256`，但 `x * y = 2^300` 无法放入。检查型乘法回滚，unchecked 乘法回绕；全精度 `mulDiv` 返回 `2^200`。整数 `5 / 2` 向下为 `2`，向上规则返回 `3`，因此舍入属于经济不变量。

<a id="risks"></a>

## 风险

- 链、数据源、代理、适配器、代币、金库或消费方地址错误。
- 基础与报价方向反转而未做倒数转换。
- 假定代币为 18 位，或可选元数据不可用或错误。
- 假定数据源为 8 位，而未读取并锁定。
- 混淆报价代币小数位与协议 WAD、RAY、市场或会计尺度。
- 遗漏封装、份额、指数或兑换率小数位。
- 适配器已归一化后重复应用缩放因子。
- 遗漏必要缩放因子或分母。
- 未检查正值便将有符号答案转为无符号。
- 接受零值、过时、不完整、封顶或无效数据源结果。
- 小数指数或十次幂计算下溢、溢出或越界。
- 最终商可表示，但中间乘积溢出。
- unchecked 运算、位移或显式窄化静默回绕或截断。
- 先除后乘破坏精度或使尘埃值归零。
- 经济操作采用错误的向下、向上或最接近舍入。
- 重复转换累积精度损失或系统性价值泄漏。
- 以不同单位比较价格、上限、比率、百分比、基点、WAD 与 RAY。
- 数据源、代币、代理、适配器或金库升级使缓存的小数位假设失效。
- 前端、钱包、RPC 或索引器格式化掩盖不同的链上运算。
- 错误估值放大借贷、铸造、赎回、清算、上限、坏账或不公平份额发行。

<a id="misconceptions"></a>

## 常见误区

- **“每个 ERC-20 代币都使用 18 位小数。”** ERC-20 元数据方法是可选的，已部署资产采用不同数值与行为。
- **“每个美元价格数据源都使用 8 位小数。”** 数据源精度是具体部署的接口属性，必须读取并纳入版本管理。
- **“原始整数很大就证明被操纵。”** 若不知道单位、方向、小数位、时间戳和消费尺度，原始数量没有意义。
- **“Solidity 0.8 会保证缩放正确。”** 检查型溢出可回滚，但不会修复错误单位、截断、类型转换或舍入政策。
- **“先乘后除或增加小数位总会提高精度。”** 这可能溢出、重复缩放或保留错误单位；全精度运算仍需要正确公式。

<a id="related"></a>

## 相关主题

- [代币小数位验证](/zh-cn/crypto/token-decimals-verification/)
- [预言机](/zh-cn/crypto/oracle/)
- [预言机攻击](/zh-cn/crypto/oracle-attack/)

<a id="sources"></a>

## 来源

- [Data Feeds API Reference](https://docs.chain.link/data-feeds/api-reference) - Chainlink Documentation（访问日期：2026-08-13）
- [Chainlink Data Feeds](https://docs.chain.link/data-feeds) - Chainlink Documentation（访问日期：2026-08-13）
- [ERC-20: Token Standard](https://eips.ethereum.org/EIPS/eip-20) - Ethereum Improvement Proposals（访问日期：2026-08-13）
- [Types](https://docs.soliditylang.org/en/latest/types.html) - Solidity Documentation（访问日期：2026-08-13）
- [Expressions and Control Structures](https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic) - Solidity Documentation（访问日期：2026-08-13）
- [Utils](https://docs.openzeppelin.com/contracts/5.x/api/utils) - OpenZeppelin Contracts Documentation（访问日期：2026-08-13）
- [Oracles](https://aave.com/docs/aave-v3/smart-contracts/oracles) - Aave Protocol Documentation（访问日期：2026-08-13）
- [Compound v2 Price Feed](https://docs.compound.finance/v2/prices/) - Compound Documentation（访问日期：2026-08-13）

Source: https://wiki.fcontext.com/zh-cn/crypto/oracle-decimal-mismatch/index.mdx
