﻿---
title: "一部のトークン承認で最初にゼロへ戻す必要があるのはなぜか"
description: "一部の ERC-20 トークンは、非ゼロの allowance から別の非ゼロ値への直接変更を拒否します。ゼロへのリセットが必要な場面、2 件のトランザクションを順に確認する理由、残るリスクを説明します。"
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 実装は、既存の allowance と `newAmount` がともに非ゼロのとき、`approve(spender, newAmount)` を拒否します。そのようなトークンでは、まず `approve(spender, 0)` を送信して確定を待ち、その後に新しい非ゼロの承認を送信します。

この制約はすべての ERC-20 トークンに必須ではありません。ERC-20 は `approve` を現在の allowance の上書きとして定義し、承認変更の競合を緩和するためクライアント画面にゼロ優先を推奨する一方、互換性のためトークンコントラクト自体は強制すべきでないとしています。それでも一部のデプロイ済みトークンは強制します。したがってゼロ優先は互換性の手順であり有用な確認地点でもありますが、ゼロ化トランザクションの確定前に旧 allowance が使われないことを保証しません。

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

## 仕組み

1. チェーン、トークンコントラクト、所有者、spender、予定額を確認します。ウォレットの表示名だけに頼らず、トークンコントラクトから `allowance(owner, spender)` を読み取ります。
2. allowance がすでに `0` なら、目的の承認を一度送信します。非ゼロなら、非ゼロ値への直接変更は標準的な実装では成功しても、ゼロ優先トークンでは revert する場合があります。
3. ゼロ優先の流れでは `approve(spender, 0)` を送信し、成功した receipt を待ちます。その後、同じ所有者と spender の allowance を再読込し、`0` であることを確認します。
4. トークン残高、spender、目的を再確認します。それから `approve(spender, newAmount)` を送信し、確定するまで新 allowance を有効とみなしません。
5. 最終 allowance を確認し、途中の `Transfer` と `Approval` イベントも調べます。成功した receipt は実行を示し、現在のコントラクト状態は残存する権限を示します。

OpenZeppelin の `SafeERC20.forceApprove` はコントラクト向けの互換フォールバックです。目的値を試し、失敗すれば `0`、目的値の順で試します。この補助関数が変更するのは呼出元コントラクト自身の allowance です。ユーザーのウォレット承認を自動修復するものではなく、トランザクション順序と最終状態の確認も不要にはなりません。

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

## 例

所有者が spender に `1000` トークンの allowance を与えており、`100` に減らしたいとします。ゼロ優先トークンでは `approve(spender, 100)` が revert するため、オンチェーン allowance は `1000` のままです。revert した呼出しが状態を部分的に更新することはありません。

代わりに所有者は `approve(spender, 0)` を送信します。その確定前に spender が `400` を使い、`600` が残りました。その後、確定したゼロ化トランザクションが残額を `0` に置き換えます。所有者は減少した残高を確認してから、新たな `100` を付与するか判断できます。付与すれば spender はすでに `400` を使っており、後からさらに最大 `100` を使えます。ゼロ優先により新しい権限の付与前に途中の支出を発見できますが、その支出を取り消すことはできません。

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

## リスク

- 旧 allowance はゼロ化トランザクションが実行されるまで使用可能です。spender が保留中の取消しや減額に先回りする場合があります。
- 最初の確定を待たずゼロ化と再設定を送信すると、意図した確認地点が失われ、途中の支出を見落とす可能性があります。
- チェーン、トークンアドレス、spender アドレスを誤ると、意図と異なる権限を作成または取り消します。トークンシンボルは一意の識別子ではありません。
- 二段階が必要なら二件分の費用がかかり、どちらも失敗、置換、長期保留の可能性があります。署名を送信しただけで状態を推測してはいけません。
- 無制限承認や、アップグレード可能または侵害された spender は将来の入金も危険にさらします。実用上最小の額を使い、利用後に残りの allowance を確認します。
- コントラクト連携では非標準の戻り値と承認動作を明示的に扱う必要があります。互換ラッパーは信頼できない spender を安全にはしません。

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

## よくある誤解

- **すべての ERC-20 がゼロ優先を要求する。** 標準はクライアント側の順序を推奨しますが、コントラクトでの強制は避けるよう述べています。非ゼロから非ゼロへの変更を拒否するのは一部の実装だけです。
- **ゼロ優先で承認競合を完全に解決できる。** ゼロ化トランザクションの確定前なら spender は旧 allowance を使えます。
- **再設定が revert すれば旧 allowance も消える。** revert は試みた状態変更を巻き戻すため、通常は以前の allowance が残ります。
- **二件を同時に送ることは確定を待つことと同じである。** 安全上の確認地点は、ゼロ状態を確定して調べた後に再設定を判断することで生まれます。
- **サイトとの接続を切れば承認も取り消される。** ウォレット接続状態とトークンコントラクト上の allowance は別物です。

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

## 関連トピック

- [ERC-20 承認の競合状態](/ja/crypto/erc20-approval-race-condition/)
- [ウォレット承認](/ja/crypto/wallet-approval/)
- [ERC-2612 Permit の nonce と deadline](/ja/crypto/erc2612-permit-nonce-deadline/)
- [Permit2 署名のリスク](/ja/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/ja/crypto/token-approval-zero-first/index.mdx
