代幣標準與 NFT

ERC-20 額度

額度是 ERC-20 代幣為每一組(擁有者、花用者)配對所記錄的可用預算:該花用者還被允許拉走擁有者多少代幣。它以巢狀映射 allowance[owner][spender] 儲存,型別為 uint256。擁有者用 approve 設定它,任何人都能用 allowance(owner, spender) 讀取它,而花用者每成功執行一次 transferFrom,就會從中扣掉所搬動的數量。正是這套「先 approve、再 transferFrom」的兩步舞,讓合約得以拉取代幣——因為合約無法從一個它並不擁有的帳戶把代幣推出去。

最著名的缺陷是「授權競態」。假設 Alice 已授權 Bob 100 枚代幣,現在想調降為 50,於是送出 approve(Bob, 50)。若 Bob 正盯著記憶池,他可以搶在這次更新之前先以 transferFrom 花掉舊的 100,待 Alice 的 approve 確認後,再花掉新的 50——總共搬走 150,遠超 Alice 在任何單一時間窗內所願意給的數量。標準裡的 approve 只是單純覆寫數值,本身並不提供任何保護。

緩解之道幾經演進。經典建議是先把額度設為零、等它確認後再設定新值,如此就不存在可被利用的舊額度。函式庫又新增了 increaseAllowance 與 decreaseAllowance,以「增減差量」而非「覆寫」的方式調整預算(OpenZeppelin 後來在 v5 棄用了它們,因為這個競態在實務上鮮少能被利用,且更偏好改用 permit)。透過 ERC-2612 permit 的簽章式授權,則乾脆完全省去那筆獨立的 approve 交易。

allowance[owner][spender] -= amount // on each transferFrom

這個競態要能發生,須花用者既存惡意又手腳夠快,且你正把一個非零額度調降為另一個非零值。先設為零、或改用 permit,就能消除這個時間窗。

又稱
approve/transferFrom modelapprove/transferFrom 模型