# [ERC7674] ERC20の一時承認の仕組みを理解しよう！

> ERC7674は、ERC20トークンを「同一トランザクション内だけ」一時的に承認（approve）するための最小限のインターフェースを定義しています。

- URL: https://cardene.dev/articles/cd9ac988145b8dc29758
- 公開日: 2025-12-28
- 更新日: 2025-12-28
- トピック: Blockchain
- タグ: ethereum, solidity, smartcontract, ブロックチェーン

## はじめに

『DApps開発入門』という本や色々記事を書いているかるでねです。

https://amzn.asia/d/gxvJ0Pw

今回は、**ERC20**トークンの承認を同一トランザクション内だけ有効にし、不要な承認をチェーン上に残さない仕組みを提案している**ERC7674**についてまとめていきます！

:::message
以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。
:::

https://eips.ethereum.org/EIPS/eip-7674

他にも様々なEIP・BIP・SLIP・CAIP・ENSIP・RFC・ACPについてまとめています。

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4

## 概要

**ERC7674**は、**ERC20**トークンを「**同一トランザクション内だけ**」一時的に承認（`approve`）するための最小限のインターフェースを定義しています。
ここでいう承認とは、あるコントラクトがユーザーのトークンを移動できるように許可する仕組みのことです。

通常の**ERC20**では、`approve` を呼び出すとその承認は明示的に取り消すまで永続的に残ります。
**ERC7674**はこの問題に対して、「**一度の処理が終わったら自動的に消える承認**」を実現することを目的としています。

この仕様は、トランザクションが完了すると同時に承認が無効になることを前提に設計されています。
そのため、ユーザーや開発者が後処理として承認を取り消す必要はありません。

## 動機

**ERC20**トークンを使ったDeFiやNFT、ブリッジなどの操作では、トークンの承認が頻繁に必要になります。
しかし、その多くは一度しか使わない承認です。

:::message
**ERC20**については以下の記事を参考にしてください。
:::

[\[ERC20\] ERC20を1からわかりやすく解説](/articles/aeefe2d89dd5332c9f43)

例えば、以下のようなケースです。

* DEXで1回だけスワップする
* コントラクトに一度だけトークンを預ける
* NFTミントのために一度だけ支払う

これらの場合でも、通常の**ERC20**では承認がブロックチェーン上に残り続けます。
結果として、意図しない承認が残りセキュリティリスクになることがあります。

#### 残り続ける承認の問題点

承認が残ることで、以下のような問題が発生します。

| 問題点       | 説明                                         |
| --------- | ------------------------------------------ |
| セキュリティリスク | 承認先のコントラクトに脆弱性があった場合、トークンを不正に移動される可能性があります |
| ユーザー体験の悪化 | 承認を取り消すために追加のトランザクションとガス代が必要になります          |
| 状態管理の複雑化  | 実際には使われない承認がチェーン上に残り、状態が無駄に増えます            |

このように、「**一度しか使わない承認**」を永続的に保存する設計自体が、現在のユースケースと合っていません。

#### EIP1153とTSTOREの役割

**ERC7674**の背景には、**EIP1153**で導入された新しい仕組みがあります。

**EIP1153**は、**一時的ストレージ（Transient Storage）**をEthereumに追加する提案です。
この一時的ストレージでは、次の特徴があります。

:::message
**EIP1153**については以下の記事を参考にしてください。
:::

[\[EIP1153\] EVMの一時ストレージの仕組みを理解しよう！](/articles/58a056298e327f7a3604)

* トランザクションの実行中だけデータを保存できる
* トランザクションが終わると自動的に消える
* 通常のストレージ（`SSTORE`）よりガスコストが低い

このとき使われる命令が `TSTORE` です。
`TSTORE` は、ブロックチェーンに永続化しないデータを書き込むための命令です。

**ERC7674**は、この `TSTORE` を使うことで、「**その場限りのトークン承認**」を効率よく扱えるようにしています。

#### ERC7674が解決すること

**ERC7674**によって、以下のような改善が可能になります。

* 承認がトランザクション終了時に自動で消える
* 承認の取り消し操作が不要になる
* 不要な承認が残らないため安全性が高まる
* ガスコストを抑えつつ、柔軟なトークン操作ができる

つまり**ERC7674**は、現在の**ERC20**運用で当たり前になっている無駄やリスクを、プロトコルレベルで解消するための仕様です。
一度きりの操作が多い現代のスマートコントラクト利用に合わせた、現実的で扱いやすいアプローチと言えます。

## 仕様

#### 追加で実装が必須となる関数

**ERC7674**に準拠するコントラクトは、既存の**ERC20**に加えて1つの新しい関数を必ず実装する必要があります。

```js
function temporaryApprove(address spender, uint256 value)
    public
    returns (bool success);
```

この関数は、通常の `approve` とは異なり、一時的な承認を作成します。

#### `temporaryApprove` の基本的な動作

`temporaryApprove(spender, value)` を呼び出すと、以下のような挙動になります。

* `msg.sender` が `spender` に対して、同一トランザクション内のみ有効な承認を与えます
* `spender` は、そのトランザクション中であれば何度でも `transferFrom` を呼び出せます
* 引き出せる合計量は `value` 以下に制限されます

ここで重要なのは、この承認が通常の**ERC20**の承認（永続的な承認）とは別枠で管理されるという点です。

#### 一時承認と通常承認の関係

**ERC7674**では、一時承認と通常の承認が同時に存在できる設計になっています。

トランザクション中に `spender` が使える上限は以下の合計です。

* 一時承認（temporary allowance）
* 永続的な**ERC20**の承認（persistent allowance）

つまり、そのトランザクション内で使える最大量は、**一時承認 + 通常承認**です。

#### `allowance` の消費ルール

`transferFrom` が呼ばれたとき、どの承認から消費されるかについても明確に定義されています。

**ERC7674**では、以下のルールが推奨されています。

* まず一時承認を消費します
* 一時承認だけで足りる場合、通常承認は参照も更新もしません
* 一時承認が不足している場合にのみ、通常承認を消費します

この設計には理由があります。
通常承認はストレージに保存されているため、読み書きにガスコストがかかります。一方、一時承認はトランザクション中だけ存在するため、ストレージアクセスを減らせるという利点があります。

処理の流れを図にすると、以下のようになります。

```mermaid
flowchart TD
    A[transferFrom 呼び出し] --> B{一時承認は十分か}
    B -->|Yes| C[一時承認のみを消費]
    B -->|No| D[不足分を通常承認から消費]
```

#### 一時承認の有効期間

一時承認には、明確な寿命があります。

* 作成されたトランザクションの終了まで有効です
* 同じトランザクション内であれば何度でも利用できます
* 以下の条件で消滅します
  * `transferFrom` によって使い切られた場合
  * 同じ `spender` に対して再度 `temporaryApprove` が呼ばれた場合
  * トランザクションが終了した場合

特に重要なのは、トランザクション終了時に必ず消去されるという点です。
これにより、承認が意図せず残ることはありません。

#### `allowance` 関数の戻り値の扱い

**ERC7674**に準拠する場合、`allowance(owner, spender)` の戻り値にも変更が必要です。

この関数は、以下の合計値を返さなければなりません。

* 永続的な承認量
* 一時承認量

つまり、外部から見たときに「**今この `spender` はどれだけ使えるのか**」を正確に表す値を返します。

#### オーバーフロー時のルール

一時承認と通常承認を足した結果が `uint256` の最大値を超える場合も考慮されています。

この場合の挙動は明確です。

* `type(uint256).max` を返します

これは、**ERC20**でよく使われている「**無限承認**」と同じ扱いになり、実装者や利用者が直感的に理解しやすい挙動です。

## 補足

**ERC7674**は、既存のトークンや周辺インフラに組み込みやすくするために、インターフェースの拡張を最小限にしています。
具体的には、**ERC20**に対して新しく追加するのは `temporaryApprove` の1関数だけ、という設計です。

最小拡張にすると、ウォレットやSDK、既存コントラクトなど「**すでにある仕組み**」の多くをそのまま活かしやすくなります。
一方で、この判断は `allowance` 関数の後方互換性に影響します。
理由は、**ERC7674**では `allowance(owner, spender)` が「**通常の永続承認**」だけでなく「**一時承認**」も足した値を返す必要があるためです。

ただし、`transferFrom` の実装側で「**明示的に `spender` を承認したうえでしか移転できない**」という要件を満たすように実装変更が必要になるため、承認の考え方として破綻しないように作られています。
要は、`allowance` の見え方が変わっても、`transferFrom` が勝手に動くわけではなく、承認が前提である点は守られます。

## 互換性

**ERC20**の機能のうち、後方互換性が崩れるのは `allowance` だけです。
その他の挙動は後方互換です。

ここでいう「**互換性が崩れる**」とは、今まで `allowance` が返していた値（永続承認のみ）と、**ERC7674**に準拠した後の値（永続承認 + 一時承認）が一致しない可能性があるという意味です。

影響が出やすいケースを表にまとめます。

| 対象  | 何が変わるか        | どう困る可能性があるか     |
| ----------------- | ----------- | ------------------------- |
| `allowance(owner, spender)` を監視するUI/分析ツール | 一時承認がある瞬間だけ値が大きく見える | 「**承認が増えた**」と誤認する可能性があります（ただしトランザクション内だけです）         |
| `allowance` の値を前提にロジックを組む外部コントラクト         | 一時承認込みの値を見てしまう      | 実行中の文脈次第で想定と異なる値に見える可能性があります（ただし同一トランザクション限定です） |

一方、`approve` や `transfer`、通常の `transferFrom` の呼び出し自体が壊れるわけではありません。
壊れるのは主に「**`allowance` の返り値の意味が変わる**」点です。

## 参考実装

#### 一時ストレージの使用

**ERC7674**では、一時承認（temporary allowance）を保存する場所を、通常の承認（regular allowance）と必ず分ける必要があります。
ここでいう「**分ける**」は、同じキーや同じスロットを流用して混ざらないようにする、という意味です。

そのうえで、**ERC7674**に準拠したコントラクトは**EIP1153**の transient storage（一時ストレージ）を使って一時承認を保持してもよいとしています。

* transient storage（**EIP1153**）はトランザクション中だけ有効で、終了時に自動的に消える領域です
* `TSTORE` / `TLOAD` を使う前提のストレージです
* これに一時承認を置くと「**自動で消える承認**」と相性が良いです

ただし、保存するスロット（slot）の決め方が雑だと、別の用途で使っているスロットと衝突（slot collision）して壊れます。
そこで、`owner` と `spender` の組み合わせごとに一意なスロットを必ず選ぶ必要があります。

スロットの導出は以下の形が推奨されています。

```text
keccak256(spender . keccak256(owner . p))
```

* `.` はバイト列の連結（concatenation）
* `p` は「**このコントラクト内で `temporary allowances` を一意に定義する文字列**」を `keccak256` したもの

つまり、コントラクトの名前空間の中で「**`temporary allowance` 用だ**」とわかる識別子になります

この式の狙いは、`owner`/`spender` に加えて「**`temporary allowance` 用**」という領域識別子も混ぜることで、同じ `transient storage` の空間内でも衝突しにくくする点です。

#### イベント

**ERC7674**では、一時承認を設定したときにイベントを出すことは必須ではありません。
ただし、準拠したコントラクトは任意で以下のイベントを発行できます。

```js
event TransientApproval(
    address indexed owner,
    address indexed spender,
    uint256 value
);
```

イベントがあると、ウォレットやインデクサーが「**一時承認が発生した**」ことを追いやすくなります。
一方で、イベントはログとして残るため、用途によっては「**ログが増える**」、「**追跡されやすくなる**」といった性質もあります。
必須にしていないのは、このトレードオフを実装者に委ねる意図があると理解すると自然です。

## セキュリティ

**ERC7674**のセキュリティ上の重要点は、一時承認を保存するスロット識別子の導出方法が、同じ空間内の他スロットと衝突しないことです。

以下の事故を避ける必要があります。

* `temporary allowance` の保存先スロットが、別のデータ（例えば、別の一時変数、別の機能の `transient storage`**）と同じになってしまう
* その結果、一時承認が上書きされたり、逆に他のデータが壊れたりする
* さらに悪いと、意図しない承認量が読み出され、`transferFrom` の判定が狂う

そのため、スロットの導出には `owner` と `spender` だけでなく、`temporary allowance` 用の領域だと分かる識別子（`p`）も混ぜ、`keccak256` をネストして一意性を高める、という設計が求められています。

要点は「**一意なスロットを作る**」と「**同じ空間（例: transient storage）内で衝突しない**」です。
ここが守れないと、**ERC7674**の前提である「**同一トランザクション内だけ安全に使える一時承認**」が崩れます。

## 引用

Xenia Shape (@byshape), Mikhail Melnik (@ZumZoom), Hadrien Croubois (@Amxx), "ERC-7674: Temporary Approval Extension for ERC-20 [DRAFT]," Ethereum Improvement Proposals, no. 7674, April 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7674.

## 最後に

今回は「**ERC20**トークンの承認を同一トランザクション内だけ有効にし、不要な承認をチェーン上に残さない仕組みを提案している**ERC7674**」についてまとめてきました！
いかがだったでしょうか？

質問などがある方は以下のTwitterのDMなどからお気軽に質問してください！

[Twitter @cardene777](https://twitter.com/cardene777)

他の媒体でも情報発信しているのでぜひ他も見ていってください！

https://zenn.dev/heku

https://cardene.substack.com/

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4
