# [ERC8273] Agentの操作を1回のトランザクションだけ認可する仕組みを理解しよう！

> ERC8273では、AttestorがAgentの操作を事前に評価します。評価に通ったら、AttestorはRegistryコントラクトのattestAndCallを呼びます。

- URL: https://cardene.dev/articles/b913add46e84735fefba
- 公開日: 2026-08-16
- 更新日: 2026-08-16
- トピック: Blockchain
- タグ: blockchain, erc, ethereum, smartcontract

## はじめに

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

https://amzn.asia/d/gxvJ0Pw

以下でも情報発信しているので、興味ある記事があればぜひ読んでみてください！

https://cardene.notion.site/EIP-2a03fa3ea33d43baa9ed82288f98d4a9

https://twitter.com/cardene777

https://zenn.dev/heku

https://cardene.substack.com/

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

Agentがオンチェーンで資産を動かす時、「**そのAgentが存在する**」と分かるだけでは足りません。
資金の送付や交換では、そのAgentに実行を任せてよいかを、操作ごとに確認する必要があります。

ERC8273は、信頼する確認者が評価した結果を使い、1回のトランザクションの間だけAgentの操作を認可するためのinterfaceです。
この記事では、認可が残る場所、実行時に何を照合するか、DAppがどの呼び出しで認可を確認するかを順に説明します。

仕様は以下です。

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

## 概要

#### 提案の簡単な理解

ERC8273では、`Attestor`がAgentの操作を事前に評価します。
評価に通ったら、`Attestor`はRegistryコントラクトの`attestAndCall`を呼びます。
Registryコントラクトは、監査用の記録を残し、今のトランザクションだけ有効な認可を一時ストレージへ書き込みます。
続いてAgentのウォレットからDAppを呼び出します。

DAppは、呼び出し元のウォレットと、許可された操作を指定してRegistryコントラクトへ照会します。
認可があれば処理を続けます。
認可がなければトランザクション全体をrevertします。
トランザクションが終わると一時ストレージはEVMによって消去されます。
監査用の記録だけがオンチェーンに残ります。

![erc8273-overview.png](/images/qiita-432e343f-02dc-4389-970e-1ecab493dcd1.webp)

この仕組みは、長期間使える権限を発行するものではありません。
評価した1回の操作だけを通すための認可です。

#### アテステーションと認可の違い

`attestation`は、確認者が「**この対象は条件を満たす**」と記録するオンチェーンの証跡です。
ERC8273の`AttestationRecord`は、誰を評価したか、誰が評価したか、何を許可したかを永続ストレージに残します。

一方で、DAppが今すぐ操作を許可するかは、永続レコードだけでは判断しません。
現在のトランザクションに限って作られた一時認可を確認します。

```mermaid
flowchart LR
  A[Attestorの評価] --> B[監査レコードを保存]
  B --> C[一時認可をTSTORE]
  C --> D[DAppが認可を照会]
  D --> E[操作を実行]
  E --> F[トランザクション終了]
  F --> G[一時認可を自動消去]
  B --> H[監査レコードは残る]
```

## 動機

AgentのIDは、どのAgentを指すかを示します。
しかし、IDだけでは今回のスワップ、mint、管理操作を実行してよいかは判断できません。

ERC8273は、対象のIDと、操作ごとの認可を分けます。
`capability`は「**DeFiの操作を許可する**」のような大きな権限区分です。
`actionDigest`は、どのコントラクトのどの関数を、どの引数で呼ぶかをハッシュ化した値です。

![erc8273-scope.png](/images/qiita-017559ba-e14d-40f5-b340-56c0e68b3c7d.webp)

例えば、1,000USDCまでをWETHへ交換する操作を許可する時は、対象コントラクト、関数セレクタ、交換額、受取先、nonceを`actionDigest`へ含めます。
金額や受取先を変えるとハッシュ値が変わるため、DAppは別の操作として拒否できます。

`actionDigest`が`0`の場合は、具体的な呼び出しを結び付けない認可です。
この形式は「**認証済みAgentか**」のような粗い確認には使えます。
送付、特権的な状態変更、トランザクション中の再入を利用できる金融操作には使えません。

## 仕様

### 認可に使うデータ

認可範囲は、対象、`capability`、`actionDigest`の組で決まります。
RegistryコントラクトとDAppは同じ組を使って書き込みと照会を行います。

```js
// 交換を1回だけ認可する時の値
subjectId: 42
subjectType: keccak256("ERC8004_AGENT")
capability: keccak256("DEFI_SWAP_V1")
actionDigest: keccak256(abi.encode(<交換コントラクト>, <呼び出しデータ>, <nonce>))
wallet: <Agentウォレット>
```

`subjectId`と`subjectType`からは、検索用の`subjectHash`を計算します。
`wallet`はDAppが`msg.sender`として確認するウォレットです。
`evidenceHash`には、`Attestor`が参照した評価報告書や署名付き証跡のハッシュ値を入れられます。

![erc8273-storage-boundary.png](/images/qiita-2de35e7a-6019-42b6-acdd-e314e75b3ec8.webp)

#### `AttestationStatus`

```js
enum AttestationStatus { None, Recorded }
```

`None`は、存在しないレコードを読む時の初期値です。
標準のレコードはすべて`Recorded`です。
この値は、現在の操作が認可されているかを表しません。
操作中の認可は一時ストレージで確認します。

#### `SubjectRef`

```js
struct SubjectRef {
    uint256 subjectId;
    bytes32 subjectType;
}
```

`SubjectRef`は、評価対象を指定する入力値です。
`subjectId`だけではIDの発行元が分からないため、`subjectType`で名前空間も指定します。

- **フィールド**

| フィールド | 詳細 |
| --- | --- |
| `subjectId` | 評価対象を識別する数値です。 |
| `subjectType` | IDの種類を区別するハッシュ値です。 |

#### `ExecutionRequest`

```js
struct ExecutionRequest {
    bytes32 profileId;
    bytes32 actionDigest;
    bytes data;
}
```

`ExecutionRequest`は、RegistryコントラクトがAgentウォレットからDAppを呼ぶ方法と、実行する操作を指定します。
`data`の形式は`profileId`ごとに決まります。

- **フィールド**

| フィールド | 詳細 |
| --- | --- |
| `profileId` | 実行プロファイルを選ぶ識別子です。 |
| `actionDigest` | 具体的な操作を固定するハッシュ値です。`0`は権限区分だけを使います。 |
| `data` | 実行プロファイルが復号する呼び出しデータです。 |

#### `AttestationRecord`

```js
struct AttestationRecord {
    uint256 subjectId;
    bytes32 subjectType;
    address attestor;
    bytes32 capability;
    bytes32 actionDigest;
    uint64 issuedAt;
    AttestationStatus status;
    bytes32 evidenceHash;
    address wallet;
}
```

`AttestationRecord`は、発行済みアテステーションを監査するための永続レコードです。
現在有効な認可を保存する場所ではありません。

- **フィールド**

| フィールド | 詳細 |
| --- | --- |
| `subjectId`、`subjectType` | 評価した対象とIDの種類です。 |
| `attestor` | レコードを発行した確認者です。 |
| `capability`、`actionDigest` | 許可する権限区分と、必要な時は具体的な操作です。 |
| `issuedAt` | 発行時刻です。 |
| `status` | 永続レコードの状態です。標準レコードは`Recorded`です。 |
| `evidenceHash` | 評価に用いたオフチェーン証跡を識別するハッシュ値です。 |
| `wallet` | DAppが認可対象として照会するAgentウォレットです。 |

### `IERC165`

#### `supportsInterface`

```js
function supportsInterface(bytes4 interfaceId) external view returns (bool);
```

`supportsInterface`は、RegistryコントラクトがどのERC8273 interfaceを実装しているかを確認する呼び出しです。
DAppは、認可を照会する前に必要なinterfaceがあるかを確認します。

1. **interface IDを渡す**

    DAppが必要とする`IERC8273WalletAttestation`などのinterface IDを渡す。

2. **対応可否を受け取る**

    Registryコントラクトが実装していれば`true`を返す。

- **引数**

| 引数 | 詳細 |
| --- | --- |
| `interfaceId` | 確認したいinterfaceを表す4バイトの識別子です。 |

- **戻り値**

| 戻り値 | 詳細 |
| --- | --- |
| `bool` | interfaceを実装している時に`true`です。 |

- **実行条件**

- **呼び出し元**

    認可照会を使うDAppや、対応状況を表示するアプリケーションです。

### `IERC8273`

`IERC8273`は、監査レコード、イベントログ、参照用の呼び出しをまとめるコアinterfaceです。

#### `Attested`

```js
event Attested(
    uint256 indexed attestationId,
    address indexed wallet,
    bytes32 indexed capability,
    bytes32 actionDigest,
    bytes32 subjectHash,
    address attestor,
    uint256 subjectId,
    bytes32 subjectType,
    bytes32 evidenceHash
);
```

`Attested`イベントは、アテステーションを発行した時にイベントログへ残ります。
Indexerは`wallet`や`capability`でログを検索し、監査画面を更新できます。

- **フィールド**

| フィールド | 詳細 |
| --- | --- |
| `attestationId` | Registryコントラクト内で増えるレコードIDです。 |
| `wallet` | 認可に結び付くAgentウォレットです。 |
| `capability` | 許可した権限区分です。 |
| `actionDigest` | 具体的な操作を固定するハッシュ値です。 |
| `subjectHash` | `subjectId`と`subjectType`から計算する検索用ハッシュ値です。 |
| `attestor` | 発行した確認者です。 |
| `subjectId`、`subjectType` | 評価対象とIDの種類です。 |
| `evidenceHash` | オフチェーン証跡を識別するハッシュ値です。 |

`attestationId`はチェーンやRegistryコントラクトをまたいで一意ではありません。
Indexerは`chainId`、Registryアドレス、`attestationId`を組にして記録します。

#### `isAttested`

```js
function isAttested(
    SubjectRef calldata subject,
    bytes32 capability,
    bytes32 actionDigest
) external view returns (bool);
```

`isAttested`は、対象をキーにして、現在のトランザクションに一時認可があるかを`bool`で返します。
画面表示やオフチェーンの確認に使います。

1. **対象のキーを計算する**

    `subject`、`capability`、`actionDigest`から一時ストレージのキーを決める。

2. **一時認可を読む**

    値があれば`true`、なければ`false`を返す。

- **引数**

| 引数 | 詳細 |
| --- | --- |
| `subject` | 評価対象を指定する`SubjectRef`です。 |
| `capability` | 権限区分です。 |
| `actionDigest` | 具体的な操作のハッシュ値、または`0`です。 |

- **戻り値**

| 戻り値 | 詳細 |
| --- | --- |
| `bool` | 現在のトランザクションに認可がある時に`true`です。 |

重要なオンチェーン操作の認可には使いません。
認可がない時にrevertする`getActiveAttestation`を使います。

#### `latestAttestationId`

```js
function latestAttestationId(
    SubjectRef calldata subject,
    bytes32 capability,
    bytes32 actionDigest
) external view returns (uint256);
```

`latestAttestationId`は、同じ対象と認可範囲で最後に発行した監査レコードIDを返します。
現在有効な認可を返す呼び出しではありません。

1. **永続レコードを検索する**

    対象、権限区分、操作ハッシュが同じレコードを探す。

2. **最後のIDを返す**

    レコードがなければ`0`を返す。

- **引数**

| 引数 | 詳細 |
| --- | --- |
| `subject` | 評価対象です。 |
| `capability` | 権限区分です。 |
| `actionDigest` | 操作ハッシュ、または`0`です。 |

- **戻り値**

| 戻り値 | 詳細 |
| --- | --- |
| `uint256` | 最後の監査レコードIDです。 |

#### `getAttestation`

```js
function getAttestation(uint256 attestationId)
    external view returns (AttestationRecord memory record);
```

この呼び出しは、IDを指定して監査レコード全体を返します。

1. **IDで永続ストレージを読む**

    `attestationId`に対応する`AttestationRecord`を取得する。

- **引数**

| 引数 | 詳細 |
| --- | --- |
| `attestationId` | 取得する監査レコードIDです。 |

- **戻り値**

| 戻り値 | 詳細 |
| --- | --- |
| `record` | 発行者、対象、認可範囲、証跡ハッシュ、ウォレットを含む監査レコードです。 |

### `IERC8273ActiveAttestation`

#### `getActiveAttestation`

```js
function getActiveAttestation(
    SubjectRef calldata subject,
    bytes32 capability,
    bytes32 actionDigest
) external view returns (AttestationRecord memory record);
```

`getActiveAttestation`は、対象をキーにして現在のトランザクションの認可を取得します。
認可がなければrevertするため、DAppの認可チェックに使えます。

1. **一時ストレージを照会する**

    対象、権限区分、操作ハッシュに対応する認可を読む。

2. **レコードを返すかrevertする**

    認可IDがあれば永続レコードを返す。
    なければDAppの呼び出しをrevertする。

- **引数**

| 引数 | 詳細 |
| --- | --- |
| `subject` | 評価対象です。 |
| `capability` | 権限区分です。 |
| `actionDigest` | 操作ハッシュ、または`0`です。 |

- **戻り値**

| 戻り値 | 詳細 |
| --- | --- |
| `record` | 現在有効な認可に対応する監査レコードです。 |

### `IERC8273WalletAttestation`

#### `isAttestedAddress`

```js
function isAttestedAddress(
    address wallet,
    bytes32 capability,
    bytes32 actionDigest
) external view returns (bool);
```

`isAttestedAddress`は、ウォレットをキーにした`bool`の照会です。
画面表示やIndexerの処理には使えますが、DAppの重要操作だけをこの戻り値に任せません。

1. **ウォレットの一時認可を読む**

    `wallet`、`capability`、`actionDigest`に対応するスロットを読む。

2. **有無を返す**

    スロットに認可IDがあれば`true`を返す。

- **引数**

| 引数 | 詳細 |
| --- | --- |
| `wallet` | Agentウォレットです。 |
| `capability` | 権限区分です。 |
| `actionDigest` | 操作ハッシュ、または`0`です。 |

- **戻り値**

| 戻り値 | 詳細 |
| --- | --- |
| `bool` | 現在のトランザクションに認可があれば`true`です。 |

#### `getActiveAttestationByWallet`

```js
function getActiveAttestationByWallet(
    address wallet,
    bytes32 capability,
    bytes32 actionDigest
) external view returns (AttestationRecord memory record);
```

`getActiveAttestationByWallet`は、DAppが`msg.sender`をAgentウォレットとして確認する時に使う認可チェックです。
認可がなければrevertします。

1. **DAppが操作内容をハッシュ化する**

    action-bound modeでは、DAppが呼び出し先、関数、引数、nonceから同じ`actionDigest`を再計算する。

2. **ウォレットをキーに照会する**

    `msg.sender`、`capability`、再計算したハッシュ値でRegistryコントラクトを照会する。

3. **認可がなければ処理を中止する**

    空のスロットならrevertする。

- **引数**

| 引数 | 詳細 |
| --- | --- |
| `wallet` | DAppが`msg.sender`として確認するウォレットです。 |
| `capability` | 権限区分です。 |
| `actionDigest` | DAppが再計算した操作ハッシュです。 |

- **戻り値**

| 戻り値 | 詳細 |
| --- | --- |
| `record` | 現在有効な監査レコードです。 |

![erc8273-gating.png](/images/qiita-b94ff714-d276-490d-bb01-aa802d87c9df.webp)

### `IERC8273AtomicAttestation`

#### `attestAndCall`

```js
function attestAndCall(
    SubjectRef calldata subject,
    bytes32 capability,
    bytes32 evidenceHash,
    address wallet,
    ExecutionRequest calldata exec
) external payable returns (uint256 attestationId, bytes memory result);
```

`attestAndCall`は、アテステーションの発行、一時認可の書き込み、DAppの呼び出しを1つにまとめた唯一の発行入口です。
許可された`Attestor`だけが呼び出します。

1. **入力と権限を確認する**

    呼び出し元が`Attestor`であること、`wallet`、`capability`、`profileId`がゼロでないことを確認する。

2. **監査レコードを作る**

    永続ストレージへ`AttestationRecord`を保存し、`Attested`イベントを発行する。

3. **現在のトランザクションだけ認可する**

    対象用とウォレット用の一時ストレージへ`attestationId`を書き込む。

4. **AgentウォレットからDAppを呼ぶ**

    `profileId`に対応する実行プロファイルで、DAppから見た`msg.sender`が`wallet`になるよう実行する。

5. **失敗を全体へ戻す**

    実行、プロファイル検証、成功確認のどれかが失敗したら、監査レコードと一時認可を含むトランザクション全体をrevertする。

- **引数**

| 引数 | 詳細 |
| --- | --- |
| `subject` | 評価対象です。 |
| `capability` | 権限区分です。 |
| `evidenceHash` | 評価証跡を識別するハッシュ値です。 |
| `wallet` | 認可とDApp呼び出しに結び付くAgentウォレットです。 |
| `exec` | 実行プロファイル、操作ハッシュ、実行データです。 |

- **戻り値**

| 戻り値 | 詳細 |
| --- | --- |
| `attestationId` | 作成した監査レコードIDです。 |
| `result` | 実行プロファイルが返した結果です。 |

- **実行条件**

- **呼び出し元**

    Registryコントラクトが許可した`Attestor`です。

- **操作ハッシュ**

    `msg.value`を送る場合は、金額を結び付けるため`actionDigest`をゼロにしません。

### `IAgentExecute`

#### `AgentCall`

```js
struct AgentCall {
    address target;
    uint256 value;
    bytes data;
}
```

`AgentCall`は、Agentウォレットが呼び出すDApp操作を表します。
複数の呼び出しを配列にして`executeFromRelayer`へ渡せます。

- **フィールド**

| フィールド | 詳細 |
| --- | --- |
| `target` | 呼び出すDAppコントラクトです。 |
| `value` | 呼び出しとともに送るネイティブトークン量です。 |
| `data` | 関数セレクタと引数を含む呼び出しデータです。 |

#### `executeFromRelayer`

```js
function executeFromRelayer(
    AgentCall[] calldata calls,
    bytes calldata authData
) external payable returns (bytes[] memory results);
```

`executeFromRelayer`は、直接実行プロファイルでRegistryコントラクトから呼ばれるAgentウォレット側の入口です。
ウォレット自身が`target`へ呼び出すため、DAppは`msg.sender`としてウォレットを受け取ります。

1. **認可データを検証する**

    ウォレットが`authData`でチェーン、ウォレット、Registry、プロファイル、操作ハッシュ、nonce、有効期間を確認する。

2. **呼び出し配列を実行する**

    ウォレットが各`target`へ`value`と`data`を渡して呼び出す。

3. **結果を返す**

    各呼び出しの戻り値を配列として返す。

- **引数**

| 引数 | 詳細 |
| --- | --- |
| `calls` | ウォレットから実行するDApp呼び出しの配列です。 |
| `authData` | 呼び出しを承認する署名やセッション情報です。 |

- **戻り値**

| 戻り値 | 詳細 |
| --- | --- |
| `results` | 各呼び出しの戻り値です。 |

- **実行条件**

- **認可データ**

    ウォレットが`authData`を検証して、呼び出し元、操作ハッシュ、nonce、有効期間を結び付けます。

- **呼び出し元**

    対応する実行プロファイルを選んだRegistryコントラクトです。

### 実行プロファイル

実行プロファイルは、RegistryコントラクトがAgentウォレットからDAppを呼び出す方法を定めます。
認可の寿命はどちらも同じです。

![erc8273-profiles.png](/images/qiita-c8ddee2b-5995-4d26-ba74-6780acda8514.webp)

#### 直接ウォレット実行

`AGENT_EXECUTE_V1`は、`IAgentExecute`を実装したスマートウォレットやERC7702のウォレットで使います。
Registryコントラクトが`executeFromRelayer`を呼び、ウォレットがDAppを呼びます。

`actionDigest`がゼロ以外なら、少なくとも呼び出し配列と`attestationId`を含めて計算します。
`authData`は、チェーンID、ウォレット、Registry、プロファイル、操作ハッシュ、nonce、有効期間を結び付けます。

#### ERC4337のUserOperation実行

`ERC4337_USEROP_V1`は、既存のERC4337ウォレットを使うための実行プロファイルです。
RegistryコントラクトはEntryPointへUserOperationを渡します。
EntryPointは`validateUserOp`と`execute`を実行します。

プロファイルは、UserOperationの`sender`が`wallet`と一致することを確認します。
さらに、低レベルの`handleOps`がrevertしなかっただけで成功と判断せず、DAppの受領結果やイベント証明などで対象操作が成功したことを確認します。

```mermaid
sequenceDiagram
  participant A as Attestor
  participant R as Registry
  participant W as Agentウォレット
  participant D as DApp
  A->>R: attestAndCall
  R->>R: 監査レコードを保存
  R->>R: 一時認可をTSTORE
  R->>W: 実行を依頼
  W->>D: 操作を呼び出す
  D->>R: getActiveAttestationByWallet
  R-->>D: レコードを返す
  D-->>W: 操作結果
  Note over R: トランザクション終了時に一時認可を消去
```

## 補足

#### 永続の監査記録と一時認可を分ける理由

永続レコードは、後から誰が何を評価したかを確認するために残します。
一時認可は、同じ操作を後のトランザクションで再利用できないように、トランザクション終了時に消します。

#### 例外ではなくrevertで認可を止める理由

`getActiveAttestation`と`getActiveAttestationByWallet`は、認可がなければrevertします。
重要操作で`bool`を受け取り、実装側が確認を忘れる事故を減らすためです。

#### Registryコントラクトを信頼する理由

ERC8273は、どのRegistryコントラクトも同じ信頼性を持つとは定めません。
DAppは、対応するinterfaceだけでなく、信頼するRegistryアドレス、`Attestor`の集合、認可方針を明示します。

## 互換性

#### 既存の規格へ加える役割

ERC8273は既存のID、トークン、アカウント規格の動作を変更しません。
DAppはERC165で必要なinterfaceを確認してから、対応する認可照会を呼びます。

ERC8004はAgentのID登録や非同期の検証結果を扱います。
ERC8273は、1回のオンチェーン操作を止めるための同期的な認可を補います。

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

https://qiita.com/cardene/items/6a280877dca6e1fc87af

EIP1153は、トランザクションが終わると消える一時ストレージを提供します。
ERC8273はこの仕組みで、現在のトランザクションだけの認可を保持します。

## 参考実装

#### 発行と実行を1つにする流れ

参考実装は、監査レコードを保存してから、対象用とウォレット用の一時スロットへ同じ`attestationId`を書き込みます。
その後で実行プロファイルを選びます。

```js
function attestAndCall(...) external payable returns (uint256 attestationId, bytes memory result) {
    attestationId = _nextId++;
    _records[attestationId] = AttestationRecord(...);
    emit Attested(...);
    _attestTransient(...);
    result = _executeProfile(...);
}
```

実行に失敗した時はトランザクション全体がrevertします。
そのため、操作だけ失敗して認可や監査レコードだけが残る状態にはなりません。

## セキュリティ

#### `actionDigest`に操作とnonceを入れる

`actionDigest`がゼロ以外なら、対象コントラクト、関数セレクタ、引数、nonceなどの一意な値を含めます。
ネイティブトークンを送る場合は金額も含めます。
DAppは同じ規則で再計算し、違う値なら認可を通しません。

#### 再入を別に防ぐ

一時認可はトランザクションの間は残ります。
特に`actionDigest == 0`では、認可チェックだけで同一トランザクション中の再入を防げません。
重要な操作を行うDAppコントラクトはreentrancy guardを持ちます。

#### Attestorの侵害を監視する

侵害された`Attestor`は、権限範囲内で何度も新しい認可を発行できます。
1回の認可が後のトランザクションへ残らないことと、侵害期間の総被害は別の問題です。
運用者は`Attested`イベントを監視し、`Attestor`の権限を狭くし、停止と削除の手順を用意します。

#### チェーンをまたぐIDを混同しない

`attestationId`は、1つのRegistryコントラクトと1つのチェーンの中でだけ増加します。
監査ツールやブリッジは、`chainId`、Registryアドレス、`attestationId`を一組で記録します。

#### 証跡の参照先を変えない

`evidenceHash`はオフチェーンの評価証跡を識別する値です。
内容が変わるHTTP URLだけを証跡の唯一の参照先にしません。
IPFSのように内容から識別できる保存先や、署名済みの証跡を使います。

## 最後に

ERC8273は、AgentのIDそのものではなく、1回のオンチェーン操作を許可してよいかを確認するためのinterfaceです。
`Attestor`が評価し、Registryコントラクトが一時認可を作り、AgentウォレットがDAppを呼び出す流れを1つのトランザクションで完結させます。

長く残る権限を発行せず、操作と結び付いた認可だけを使える点が、この提案の中心です。

他でも色々記事を書いているのでぜひよろしければ読んでいってください！

https://amzn.asia/d/gxvJ0Pw

https://cardene.notion.site/EIP-2a03fa3ea33d43baa9ed82288f98d4a9

https://zenn.dev/heku

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

https://twitter.com/cardene777

https://cardene.substack.com/
