﻿---
title: "เหตุใดการอนุมัติโทเค็นบางชนิดจึงต้องปรับเป็นศูนย์ก่อน"
description: "โทเค็น ERC-20 บางชนิดปฏิเสธการเปลี่ยน allowance ที่ไม่ใช่ศูนย์ไปเป็นค่าอื่นที่ไม่ใช่ศูนย์โดยตรง บทความนี้อธิบายว่าเมื่อใดต้องปรับเป็นศูนย์ก่อน เหตุใดธุรกรรมทั้งสองจึงต้องยืนยันตามลำดับ และยังมีความเสี่ยงใดเหลืออยู่"
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 บางแบบจะปฏิเสธ `approve(spender, newAmount)` เมื่อ allowance เดิมและ `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 ที่สำเร็จ จากนั้นอ่าน allowance ของคู่เจ้าของ-spender เดิมอีกครั้งและยืนยันว่าเป็น `0`
4. ตรวจสอบยอดคงเหลือของโทเค็น spender และวัตถุประสงค์อีกครั้ง จากนั้นจึงส่ง `approve(spender, newAmount)` และรอการยืนยันก่อนถือว่า allowance ใหม่มีผล
5. ตรวจสอบ allowance สุดท้าย รวมทั้งเหตุการณ์ `Transfer` และ `Approval` ที่เกิดขึ้นระหว่างทาง receipt ที่สำเร็จพิสูจน์ว่ามีการดำเนินการ ส่วนสถานะปัจจุบันของสัญญาแสดงสิทธิ์ที่ยังเหลืออยู่

`SafeERC20.forceApprove` ของ OpenZeppelin เป็นทางเลือกสำรองด้านความเข้ากันได้สำหรับสัญญา โดยลองค่าที่ต้องการก่อน และถ้าการเรียกล้มเหลว จะลอง `0` ตามด้วยค่าที่ต้องการ ฟังก์ชันช่วยนี้เปลี่ยน allowance ของสัญญาที่เป็นผู้เรียกเอง ไม่ได้แก้การอนุมัติในกระเป๋าของผู้ใช้โดยอัตโนมัติ และไม่ได้ทำให้ไม่ต้องตรวจสอบลำดับธุรกรรมกับสถานะสุดท้าย

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

## ตัวอย่าง

เจ้าของให้ allowance แก่ spender จำนวน `1000` โทเค็นและต้องการลดเป็น `100` สำหรับโทเค็นที่กำหนดให้ปรับเป็นศูนย์ก่อน การเรียก `approve(spender, 100)` จะ revert ดังนั้น allowance บนเชนยังคงเป็น `1000` การเรียกที่ revert จะไม่อัปเดตสถานะเพียงบางส่วน

เจ้าของจึงส่ง `approve(spender, 0)` แทน ก่อนธุรกรรมจะยืนยัน spender ใช้ไป `400` ทำให้เหลือ `600` จากนั้นธุรกรรมปรับเป็นศูนย์ที่ยืนยันแล้วจะแทนที่ส่วนที่เหลือด้วย `0` หลังตรวจสอบยอดโทเค็นที่ลดลง เจ้าของจึงตัดสินใจได้ว่าจะให้ allowance ใหม่ `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](/th/crypto/erc20-approval-race-condition/)
- [การอนุมัติกระเป๋าสินทรัพย์ดิจิทัล](/th/crypto/wallet-approval/)
- [Nonce และ deadline ของ Permit ERC-2612](/th/crypto/erc2612-permit-nonce-deadline/)
- [ความเสี่ยงของลายเซ็น Permit2](/th/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/th/crypto/token-approval-zero-first/index.mdx
