﻿---
title: "為什麼有些代幣授權必須先歸零？"
description: "有些 ERC-20 代幣拒絕將一個非零授權額度直接改為另一個非零值。本文說明何時必須先歸零、兩筆交易為何要依序確認，以及仍然存在的風險。"
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>

## 直接答案

有些 ERC-20 實作會在現有授權額度和 `newAmount` 都非零時拒絕 `approve(spender, newAmount)`。對於這類代幣，應先提交 `approve(spender, 0)` 並等待確認，然後才能提交新的非零授權。

並非所有 ERC-20 代幣都必須這樣做。ERC-20 將 `approve` 定義為覆寫目前額度，並建議用戶端介面先歸零，以緩解修改授權時的競態；但為了相容性，標準同時說明代幣合約本身不應強制這項流程。部分已部署代幣仍然實施了該限制。因此，先歸零既是相容性步驟，也是一個有用的檢查點，但不能保證舊額度在歸零交易確認前不會被使用。

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

## 運作方式

1. 核對鏈、代幣合約、所有者、支出方和預期金額。直接從代幣合約讀取 `allowance(owner, spender)`，不要只相信錢包顯示的標籤。
2. 如果額度已經是 `0`，只需提交一次目標授權。如果額度非零，直接替換為另一個非零值可能在標準實作上成功，也可能在要求先歸零的代幣上回滾。
3. 採用先歸零流程時，提交 `approve(spender, 0)` 並等待成功回執。隨後再次讀取同一個所有者與支出方的額度，確認它是 `0`。
4. 重新檢查代幣餘額、支出方和授權用途。只有確認無誤後，才提交 `approve(spender, newAmount)`，並等待確認後再把新額度視為生效。
5. 核驗最終額度，並檢查期間發生的 `Transfer` 和 `Approval` 事件。成功的交易回執證明呼叫已執行，而目前合約狀態才顯示尚存的權限。

OpenZeppelin 的 `SafeERC20.forceApprove` 為合約實作了相容性回退：它先嘗試目標值；如果呼叫失敗，則依序嘗試 `0` 和目標值。這個輔助函式修改的是呼叫合約自身的授權額度，不會自動修復使用者錢包的授權，也不能取代對交易順序和最終狀態的核驗。

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

## 範例

某所有者給支出方的額度為 `1000` 枚代幣，希望降到 `100`。對於要求先歸零的代幣，直接呼叫 `approve(spender, 100)` 會回滾，因此鏈上額度仍是 `1000`；回滾的呼叫不會只完成部分狀態更新。

所有者改為提交 `approve(spender, 0)`。在這筆交易確認前，支出方使用了 `400`，額度剩下 `600`；隨後確認的歸零交易把剩餘額度替換為 `0`。所有者檢查減少後的代幣餘額，再決定是否授予新的 `100`。如果授予，支出方已經使用 `400`，之後還可最多使用 `100`。先歸零讓所有者在新權限授出前發現了中途支出，但不會撤銷這筆支出。

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

## 風險

- 舊額度在歸零交易執行前仍可使用。支出方可能搶在待處理的撤銷或降額交易前支出。
- 如果不等待第一筆確認就同時廣播歸零與替換交易，預期的檢查點就會消失，也可能掩蓋中途發生的支出。
- 鏈、代幣地址或支出方地址錯誤，會建立或撤銷另一項權限。代幣符號不是唯一識別碼。
- 必須分兩步時會產生兩筆交易成本，而且任一筆都可能失敗、被替換或長期等待處理。不能僅憑已提交簽章推斷鏈上狀態。
- 無限授權以及可升級或已被攻破的支出方可能危及未來存入的代幣。應使用實際可行的最小額度，並在用完後核對剩餘額度。
- 合約整合必須明確處理非標準回傳值和授權行為。相容性封裝無法讓不可信的支出方變得安全。

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

## 常見誤解

- **每種 ERC-20 都要求先歸零。** 標準建議用戶端採用這項順序，但說明代幣合約不應強制執行；只有部分實作拒絕從非零值直接改為非零值。
- **先歸零能徹底解決授權競態。** 支出方仍可在歸零交易確認前使用舊額度。
- **替換授權回滾後，舊額度就被清除了。** 回滾會撤銷本次嘗試的狀態變更，因此原額度通常仍然存在。
- **同時傳送兩筆交易等同於等待確認。** 安全檢查點來自確認並檢查零額度狀態，然後再決定是否提交替換授權。
- **中斷網站連線就會撤銷授權。** 錢包連線狀態與代幣合約中的鏈上授權額度彼此獨立。

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

## 相關主題

- [ERC-20 授權競態](/zh-tw/crypto/erc20-approval-race-condition/)
- [錢包授權](/zh-tw/crypto/wallet-approval/)
- [ERC-2612 Permit 的 nonce 與 deadline](/zh-tw/crypto/erc2612-permit-nonce-deadline/)
- [Permit2 簽章風險](/zh-tw/crypto/permit2-signature-risk/)

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

## 來源

- [ERC-20：代幣標準](https://eips.ethereum.org/EIPS/eip-20) - Ethereum Improvement Proposals（查閱日期：2026-08-21）
- [ERC20 | OpenZeppelin 文件](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20) - OpenZeppelin（查閱日期：2026-08-21）
- [SafeERC20.sol](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/utils/SafeERC20.sol) - OpenZeppelin（查閱日期：2026-08-21）

Source: https://wiki.fcontext.com/zh-tw/crypto/token-approval-zero-first/index.mdx
