僅供教育參考,不構成投資建議;投資可能產生損失。
直接答案
合約以錯誤的單位指數、價格方向或內部尺度解讀原始整數時,就會發生預言機小數位不相符。資料源小數位、代幣小數位、報價代幣小數位、封裝或份額兌換率尺度,以及協定的 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() 描述該資料源回應,而非代幣或協定尺度。檢查型運算可藉由回復阻止溢位,但無法發現量綱錯誤的公式;中間乘積溢位時,還可能使原本可表示的結果變成拒絕服務。
運作方式
- 鎖定鏈、區塊、使用端、轉接器、資料源代理與聚合器、代幣或金庫、編譯器與數學函式庫版本,以及升級狀態。
- 清點每個整數的型別與單位:原始代幣數量、代幣小數位、有符號資料源答案、資料源小數位、基礎與報價方向、封裝或份額匯率、協定內部尺度及輸出代幣小數位。
- 轉換前驗證來源:地址與方向正確、答案為正、時間戳與狀態有效、年齡與範圍可接受、備援語意明確,並在適用時檢查 L2 排序器寬限規則。
- 從輸入原始單位推導至輸出原始單位的單一量綱公式。放大與縮小時明確分支,限制每個十次方指數,每一項只正規化一次。
- 使用經證明的全精度乘除法或有界約分策略。避免先除後乘截斷、受檢中間值溢位、unchecked 回繞,以及不安全的有符號或窄化轉換。
- 為每項經濟操作規定向下、向上或最接近捨入。擔保品、債務、借款、鑄造、贖回、費用、清算及金庫份額轉換可能需要不同的保守方向。
- 對極端數量、小數位組合、倒數、複合資料源、零值、負值、過時答案、升級及微量值執行黃金向量與性質測試;以獨立高精度模型核對鏈上結果,並限制受影響曝險。
正規化是量綱分析,不是格式化。BTC/USD 與 USD/BTC 需要倒數公式;更改標籤不會反轉價格。複合資料源要求每一項的尺度與時間戳。Solidity 整數除法向零截斷,因此代數上等價的重排可能產生不同鏈上結果。全精度 mulDiv 解決中間位元寬度問題,但呼叫端仍須提供正確的分子、分母、單位、邊界與捨入方向。
計算範例
- 八位與十八位小數。 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,因此捨入屬於經濟不變量。
風險
- 鏈、資料源、代理、轉接器、代幣、金庫或使用端地址錯誤。
- 基礎與報價方向反轉而未做倒數轉換。
- 假定代幣為 18 位,或可選中繼資料無法取得或錯誤。
- 假定資料源為 8 位,而未讀取並鎖定。
- 混淆報價代幣小數位與協定 WAD、RAY、市場或會計尺度。
- 遺漏封裝、份額、指數或兌換率小數位。
- 轉接器已正規化後重複套用縮放因子。
- 遺漏必要縮放因子或分母。
- 未檢查正值便將有符號答案轉成無符號。
- 接受零值、過時、不完整、封頂或無效資料源結果。
- 小數指數或十次方計算下溢、溢位或超出邊界。
- 最終商可表示,但中間乘積溢位。
- unchecked 運算、位移或明確窄化靜默回繞或截斷。
- 先除後乘破壞精度或使微量值歸零。
- 經濟操作採用錯誤的向下、向上或最接近捨入。
- 重複轉換累積精度損失或系統性價值流失。
- 以不同單位比較價格、上限、比率、百分比、基點、WAD 與 RAY。
- 資料源、代幣、代理、轉接器或金庫升級使快取的小數位假設失效。
- 前端、錢包、RPC 或索引器格式化掩蓋不同的鏈上運算。
- 錯誤估值放大借貸、鑄造、贖回、清算、上限、壞帳或不公平份額發行。
常見誤解
- 「每個 ERC-20 代幣都使用 18 位小數。」 ERC-20 中繼資料方法是可選的,已部署資產採用不同數值與行為。
- 「每個美元價格資料源都使用 8 位小數。」 資料源精度是具體部署的介面屬性,必須讀取並納入版本管理。
- 「原始整數很大就證明遭操縱。」 若不知道單位、方向、小數位、時間戳與使用尺度,原始數量沒有意義。
- 「Solidity 0.8 會保證縮放正確。」 檢查型溢位可回復,但不會修正錯誤單位、截斷、型別轉換或捨入政策。
- 「先乘後除或增加小數位總會提高精度。」 這可能溢位、重複縮放或保留錯誤單位;全精度運算仍需要正確公式。
相關主題
資料來源
- Data Feeds API Reference - Chainlink Documentation(存取日期:2026-08-13)
- Chainlink Data Feeds - Chainlink Documentation(存取日期:2026-08-13)
- ERC-20: Token Standard - Ethereum Improvement Proposals(存取日期:2026-08-13)
- Types - Solidity Documentation(存取日期:2026-08-13)
- Expressions and Control Structures - Solidity Documentation(存取日期:2026-08-13)
- Utils - OpenZeppelin Contracts Documentation(存取日期:2026-08-13)
- Oracles - Aave Protocol Documentation(存取日期:2026-08-13)
- Compound v2 Price Feed - Compound Documentation(存取日期:2026-08-13)