僅供教育參考,不構成投資建議;投資可能產生損失。
直接答案
有些 ERC-20 實作會在現有授權額度和 newAmount 都非零時拒絕 approve(spender, newAmount)。對於這類代幣,應先提交 approve(spender, 0) 並等待確認,然後才能提交新的非零授權。
並非所有 ERC-20 代幣都必須這樣做。ERC-20 將 approve 定義為覆寫目前額度,並建議用戶端介面先歸零,以緩解修改授權時的競態;但為了相容性,標準同時說明代幣合約本身不應強制這項流程。部分已部署代幣仍然實施了該限制。因此,先歸零既是相容性步驟,也是一個有用的檢查點,但不能保證舊額度在歸零交易確認前不會被使用。
完成核查不代表資產、交易或系統已經安全。
運作方式
- 核對鏈、代幣合約、所有者、支出方和預期金額。直接從代幣合約讀取
allowance(owner, spender),不要只相信錢包顯示的標籤。 - 如果額度已經是
0,只需提交一次目標授權。如果額度非零,直接替換為另一個非零值可能在標準實作上成功,也可能在要求先歸零的代幣上回滾。 - 採用先歸零流程時,提交
approve(spender, 0)並等待成功回執。隨後再次讀取同一個所有者與支出方的額度,確認它是0。 - 重新檢查代幣餘額、支出方和授權用途。只有確認無誤後,才提交
approve(spender, newAmount),並等待確認後再把新額度視為生效。 - 核驗最終額度,並檢查期間發生的
Transfer和Approval事件。成功的交易回執證明呼叫已執行,而目前合約狀態才顯示尚存的權限。
OpenZeppelin 的 SafeERC20.forceApprove 為合約實作了相容性回退:它先嘗試目標值;如果呼叫失敗,則依序嘗試 0 和目標值。這個輔助函式修改的是呼叫合約自身的授權額度,不會自動修復使用者錢包的授權,也不能取代對交易順序和最終狀態的核驗。
範例
某所有者給支出方的額度為 1000 枚代幣,希望降到 100。對於要求先歸零的代幣,直接呼叫 approve(spender, 100) 會回滾,因此鏈上額度仍是 1000;回滾的呼叫不會只完成部分狀態更新。
所有者改為提交 approve(spender, 0)。在這筆交易確認前,支出方使用了 400,額度剩下 600;隨後確認的歸零交易把剩餘額度替換為 0。所有者檢查減少後的代幣餘額,再決定是否授予新的 100。如果授予,支出方已經使用 400,之後還可最多使用 100。先歸零讓所有者在新權限授出前發現了中途支出,但不會撤銷這筆支出。
風險
- 舊額度在歸零交易執行前仍可使用。支出方可能搶在待處理的撤銷或降額交易前支出。
- 如果不等待第一筆確認就同時廣播歸零與替換交易,預期的檢查點就會消失,也可能掩蓋中途發生的支出。
- 鏈、代幣地址或支出方地址錯誤,會建立或撤銷另一項權限。代幣符號不是唯一識別碼。
- 必須分兩步時會產生兩筆交易成本,而且任一筆都可能失敗、被替換或長期等待處理。不能僅憑已提交簽章推斷鏈上狀態。
- 無限授權以及可升級或已被攻破的支出方可能危及未來存入的代幣。應使用實際可行的最小額度,並在用完後核對剩餘額度。
- 合約整合必須明確處理非標準回傳值和授權行為。相容性封裝無法讓不可信的支出方變得安全。
常見誤解
- 每種 ERC-20 都要求先歸零。 標準建議用戶端採用這項順序,但說明代幣合約不應強制執行;只有部分實作拒絕從非零值直接改為非零值。
- 先歸零能徹底解決授權競態。 支出方仍可在歸零交易確認前使用舊額度。
- 替換授權回滾後,舊額度就被清除了。 回滾會撤銷本次嘗試的狀態變更,因此原額度通常仍然存在。
- 同時傳送兩筆交易等同於等待確認。 安全檢查點來自確認並檢查零額度狀態,然後再決定是否提交替換授權。
- 中斷網站連線就會撤銷授權。 錢包連線狀態與代幣合約中的鏈上授權額度彼此獨立。
相關主題
來源
- ERC-20:代幣標準 - Ethereum Improvement Proposals(查閱日期:2026-08-21)
- ERC20 | OpenZeppelin 文件 - OpenZeppelin(查閱日期:2026-08-21)
- SafeERC20.sol - OpenZeppelin(查閱日期:2026-08-21)