はじめに

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

今回は、ERC7540の非同期リクエストに対して、保留中のポジションを別アドレスへ移せるようにするERC8161についてまとめていきます!

以下にまとめられているものを解説しながらまとめていきます。

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

概要

ERC8161は、ERC7540の非同期入金リクエストと非同期償還リクエストに対して、Pending状態の残高だけを別のcontrollerへ譲渡できるようにする拡張仕様です。

ERC7540では、リクエストはrequestDepositやrequestRedeemで作成されたあと、Pending、Claimable、Claimedという順で進みます。 しかし標準のERC7540だけでは、Pendingのあいだにウォレットを移したい時や、別アカウントへポジションを付け替えたい時に、その保留中ポジションを直接移せません。 ERC8161は、その隙間を埋めるための拡張です。

ERC7540については以下の記事を参考にしてください。

[ERC7540] ERC4626の入金と償還のリクエストと処理実行を分離する仕組みを理解しよう!

以下の図は、ERC7540の通常フローのどこにERC8161の譲渡が差し込まれるかを示しています。

概要の図

この図で重要なのは、譲渡が許されるのはPendingの間だけだという点です。 Claimableに入った残高はそのまま請求できる状態にあるため、ERC8161はそこへ手を触れません。

動機

ERC7540の非同期Vaultでは、リクエストが長時間Pendingのまま残ることがあります。 現実資産を扱うVault、償還の処理に時間がかかるVault、清算や審査をはさむVaultでは、リクエストの完了まで待機時間が発生しやすいです。

このあいだに、利用者側ではいくつかの不都合が生まれます。 たとえばウォレットを新しいアドレスへ移したい場合、保留中のリクエストだけは古いcontrollerに残り続けます。 会計上の都合でアカウントを分けたい場合や、保留中ポジションを他プロトコルへ受け渡したい場合も、標準のERC7540だけでは扱いづらいです。

ERC8161は、この問題をキャンセルと再申請で回避するのではなく、保留中残高そのものを移すという形で解決します。 これにより、ウォレット移行、アカウント再編、保留中ポジションの受け渡しがやりやすくなります。

なぜ入金用と償還用を分けるのか

ERC8161は、入金側の譲渡と償還側の譲渡を1つの必須インターフェースにまとめていません。 これは、元になっているERC7540自体が、非同期入金と非同期償還を独立して採用できる設計だからです。

入金リクエストでは、すでに基礎資産がVaultへ入っていることが多いです。 一方で償還リクエストでは、シェアが焼却済みか、あるいは一時的にロックされているかなど、会計上の扱いが実装ごとに異なります。 そのため、片方だけ譲渡を許したいVaultがあっても不自然ではありません。

以下の表は、ERC8161が想定する実装の選択肢です。

実装パターン 内容
入金だけ対応 IERC7540DepositTransferableだけ実装する
償還だけ対応 IERC7540RedeemTransferableだけ実装する
両方対応 2つのインターフェースを両方実装する
非対応 ERC7540のまま運用する

以下の図は、入金側と償還側を分けている理由を整理したものです。

なぜ入金用と償還用を分けるのかの図

この図で見たいのは、どちらも「待機中の権利を移す」という点では似ていても、背後にある会計や資産拘束の事情が同じではないことです。 そのため提案は、両方を一括で必須にせず、Vaultが片方だけ対応する余地を残しています。

仕様

この提案では、まず「どの残高が動くのか」を固定し、そのうえで入金用と償還用の2つのインターフェースを定義しています。 流れとしては、requestIdとcontrollerで識別されるERC7540の保留中リクエスト残高に対して、譲渡メソッドがその残高を旧controllerから新controllerへ付け替える形です。

どの残高が移るのか

ERC7540では、同じrequestIdでもcontrollerが違えば別のリクエストとして管理されます。 ERC8161は、この識別方法をそのまま前提にします。 つまり、requestIdとoldControllerで指されるPending残高を、newController側へ移す仕様です。

ただしERC7540には、requestId == 0を常に返す実装もあります。 その場合はrequestIdで細かく分けず、controller単位で保留中残高を集約して扱います。 ERC8161でも、そのVaultが採用しているERC7540側の識別ルールに従って、実際に移る残高が決まります。

譲渡の対象になるのは、左から右へ進む流れのうちPendingにいる間の残高です。 requestDepositやrequestRedeemで作られた保留中残高は別アドレスへ移せますが、Vaultの処理が終わってClaimableへ進んだ後は、通常の受け取りフローへ戻ります。

以下の図は、requestIdとcontrollerの組み合わせで残高が分かれる場合と、requestId == 0としてcontroller単位で集約する場合の違いを整理したものです。

どの残高が移るのかの図

この違いがあるため、同じ譲渡メソッドでも「どの単位の残高が移るのか」はVaultのERC7540実装に依存します。 ERC8161は、その識別規則を上書きせず、そのVaultがもともと持っている保留中残高の切り方を前提にします。 統合側が見るべきなのは、requestIdの値そのものより、「そのVaultがどの粒度で保留中残高を持っているか」です。 図の左側のようにrequestIdとcontrollerの組ごとに切る実装もあれば、右側のようにcontroller単位で集約する実装もあります。

IERC7540DepositTransferable

入金リクエストの譲渡に対応するVaultは、IERC7540DepositTransferableを実装します。 このインターフェースでは、メソッド1つとイベント1つが追加されます。

js
interface IERC7540DepositTransferable {
    event TransferDepositRequest(uint256 indexed requestId, address indexed from, address indexed to);

    function transferDepositRequest(
        uint256 requestId,
        address oldController,
        address newController
    ) external;
}

transferDepositRequest

この呼び出しは、指定したrequestIdに属する保留中の入金リクエスト残高を、oldControllerからnewControllerへ丸ごと移します。 部分移転ではなく、その時点の保留中残高を全量移すのが前提です。

  • 引数
項目 型 内容
requestId uint256 対象リクエストの識別子
oldController address いま保留中残高を持っている側
newController address 譲渡先

実行後は、pendingDepositRequest(requestId, oldController)が減少し、pendingDepositRequest(requestId, newController)が同額ぶん増えます。 ただし提案本文では、Vaultが手数料を差し引く設計もあり得るため、増加量は「同額または手数料控除後」として扱われています。

msg.senderになれるのは、oldController本人か、oldControllerからオペレーター権限を与えられたアカウントだけです。 勝手な第三者が保留中ポジションを横取りできないように、呼び出し主体はここで制限されます。

以下の図は、誰が譲渡メソッドを呼べて、誰が呼べないのかを整理したものです。

transferDepositRequestの図

この境界があるため、譲渡は自由な売買APIというより、まずcontroller本人の意思か、その委任を受けたoperatorの操作として扱われます。 この図が示しているのはメソッドを叩ける主体です。 後のセキュリティ節で出てくる図は、承認済みのoperatorが持つ権限の重さを示していて、こちらとは役割が違います。

TransferDepositRequest

入金リクエストの譲渡が成功した時は、TransferDepositRequestイベントを発火しなければなりません。 インデックス付きの項目は、requestId、from、toの3つです。

  • 引数
項目 型 内容
requestId uint256 どのリクエストを動かしたか
from address 元のcontroller
to address 新しいcontroller

このイベントがあることで、インデクサーやフロントエンドは、保留中ポジションの持ち主が切り替わったことを追跡できます。

IERC7540RedeemTransferable

償還リクエストの譲渡に対応するVaultは、IERC7540RedeemTransferableを実装します。 構造は入金版と同じですが、対象がpendingRedeemRequestになる点だけが違います。

js
interface IERC7540RedeemTransferable {
    event TransferRedeemRequest(uint256 indexed requestId, address indexed from, address indexed to);

    function transferRedeemRequest(
        uint256 requestId,
        address oldController,
        address newController
    ) external;
}

transferRedeemRequest

この呼び出しは、指定したrequestIdに属する保留中の償還リクエスト残高を、oldControllerからnewControllerへ丸ごと移します。 ここでも、動いてよいのはPending状態の残高だけです。

  • 引数
項目 型 内容
requestId uint256 対象リクエストの識別子
oldController address いま保留中残高を持っている側
newController address 譲渡先

実行後は、pendingRedeemRequest(requestId, oldController)が減少し、pendingRedeemRequest(requestId, newController)が増加します。 こちらもmsg.senderはoldController本人か、そのオペレーターである必要があります。

償還側では、すでにシェアが焼却済みであるか、あるいは一時的にロックされているだけかが実装ごとに違います。 そのため提案は、譲渡メソッドの形だけを標準化し、内部会計の方法までは固定していません。

TransferRedeemRequest

償還リクエストの譲渡が成功した時は、TransferRedeemRequestイベントを発火しなければなりません。 項目構成は入金版と同じです。

  • 引数
項目 型 内容
requestId uint256 どのリクエストを動かしたか
from address 元のcontroller
to address 新しいcontroller

全量移転だけにしている理由

提案は、部分的な残高移転を許さず、保留中残高の全量移転だけを定めています。 これは、同じrequestIdのリクエストがERC7540上では同質として扱われるためです。 同じグループの保留中残高を細かく分割し始めると、実装側は端数処理、部分的な請求可能化、追跡ロジックの複雑化に向き合うことになります。

以下の図は、提案が避けたい複雑さを示しています。

全量移転だけにしている理由の図

この設計なら、保留中ポジションを「いまの持ち主から別の持ち主へ付け替える」という目的に絞れます。 Claimableまで含めた完全な権利売買基盤にするのではなく、あくまでPendingの管理改善に範囲を限定しています。

ERC165サポート

この拡張を実装するコントラクトは、ERC165のsupportsInterfaceも実装しなければなりません。 そのうえで、どちらの譲渡インターフェースを持っているかをinterfaceIdで外部から判定できるようにします。

ERC165については以下の記事を参考にしてください。

[ERC165] コントラクトが特定のインターフェースをサポートしているか確認する仕組みを理解しよう!

インターフェース supportsInterfaceで返すべきID
IERC7540DepositTransferable 0x53b3bb0a
IERC7540RedeemTransferable 0x7846f5bd

インテグレーターはこの判定によって、そのVaultが入金リクエストの譲渡に対応しているのか、償還リクエストの譲渡に対応しているのか、両方なのかを実行前に確認できます。

以下の図は、supportsInterfaceでどの譲渡機能が使えるかを事前に見分ける流れを示しています。

ERC165サポートの図

この判定を先に入れておけば、入金側だけに対応したVaultへ償還側の譲渡呼び出しを送る、といった無駄を避けられます。 同時に、UI側でも「このVaultではどの譲渡ボタンを見せるべきか」を安全に分けられます。

補足

Claimableを譲渡対象にしない理由

提案は、譲渡対象をPendingだけに限定しています。 Claimableの残高は、すでに請求可能量と交換比率が決まっており、controllerが通常のクレーム呼び出しをすれば受け取れる状態です。 ここまで来た残高をさらに譲渡対象へ含めると、部分請求との競合や、どの時点の価値で受け渡したのかという論点が増えます。

そのためERC8161は、値決めがまだ確定していない待機中ポジションの移動だけを扱い、請求可能になった残高は既存のフローへ委ねます。 範囲を絞ることで、インターフェースの責務も明確になります。

以下の図は、PendingとClaimableで譲渡の扱いを分けている理由をまとめたものです。

Claimableを譲渡対象にしない理由の図

この切り分けによって、ERC8161は「待機中の権利の移動」だけを担当し、請求可能になった後の受け取りや価値確定までは既存フローに任せています。 左側は、まだ結果が確定していない待機中権利だからこそ「持ち主を変えたい」という需要があります。 右側は、すでに受け取りに進める段階なので、ここまで譲渡対象に含めると、請求処理と権利移転がぶつかりやすくなります。

二次流通では価格参照を自前で持つ必要がある

VaultシェアにはconvertToSharesやconvertToAssetsのような参照点がありますが、保留中リクエストにはそれがありません。 とくにPendingの償還リクエストでは、最終的にどれだけの資産が返るかが、処理完了まで確定しないことがあります。

そのため、保留中ポジションを売買する二次市場を作る場合は、価格の決め方を別途設計する必要があります。 標準は譲渡の手段を与えるだけで、価格発見や決済の方法までは定めません。

以下の図は、通常のVaultシェアと違って、保留中リクエストには標準の価格参照が付いていないことを示しています。

二次流通では価格参照を自前で持つ必要があるの図

ここで言いたいのは、譲渡可能になったことと、すぐ適正価格が分かることは別だという点です。 通常のVaultシェアならその時点の参照値を価格の出発点にできますが、保留中リクエストにはその共通の物差しがありません。 そのため二次流通を作る側は、待機時間、手数料、将来の受取量の不確実性まで織り込んだ価格モデルを自前で設計しなければなりません。

後方互換性

ERC8161は、ERC7540に対する後方互換な拡張です。 この拡張を実装しないVaultは、従来どおり非同期リクエストを扱えます。 つまり、既存のERC7540実装を壊さずに、必要なVaultだけが譲渡機能を追加できます。

利用側は、譲渡メソッドの存在を決め打ちせず、ERC165のsupportsInterfaceで確認してから使えば十分です。 標準に対応していないVaultへ誤って譲渡呼び出しを送る必要はありません。

セキュリティ

オペレーター権限は保留中ポジションの持ち出し権限でもある

ERC7540と同様に、controllerが認可したオペレーターは、その人の代わりにリクエストを操作できます。 ERC8161では、この権限の中に「保留中リクエストを別アドレスへ移す」能力も含まれます。

以下の図は、その権限関係を示しています。

オペレーター権限は保留中ポジションの持ち出し権限でもあるの図

そのため利用者は、オペレーター承認を単なる補助操作権限としてではなく、待機中の資産やシェア相当の権利を外へ動かせる権限として理解する必要があります。 ウォレットやフロントエンドも、どこまで権限が及ぶかを明確に見せた方が安全です。 前の図が「第三者は呼べない」という入口の境界を示していたのに対して、この図は「承認してしまった相手はどこまでできるか」という深さを示しています。 つまり安全性の論点は、無関係な第三者を防げるかだけでなく、承認済みoperatorにどこまで任せるかにもあります。

保留中ポジションは価格が固定されていない

保留中リクエストには、オンチェーンで確定した標準価格参照がありません。 とくに償還側では、requestRedeemした時点のconvertToAssets相当値が、そのまま最終受取額になる保証はありません。

このため、譲渡可能になったからといって、そのポジションの価値が自明になるわけではありません。 マーケットプレイスや仲介プロトコルがこれを扱うなら、どの時点の期待価値を前提に売買するか、処理失敗や遅延をどう価格へ織り込むかを慎重に設計する必要があります。

最後に

今回は「ERC7540の非同期リクエストに対して、保留中のポジションを別アドレスへ移せるようにするERC8161」についてまとめてきました!

ERC8161は大きな新機能を増やす仕様ではなく、ERC7540で長く残り得るPendingポジションに移転手段を与える小さな拡張です。 ただしこの小ささが重要で、ウォレット移行、アカウント再編、二次流通、プロトコル合成といった実務上の困りごとに直接効きます。 一方で、譲渡できるのはPendingだけであり、価格参照も標準には含まれないため、実装側はオペレーター権限と価格設計を丁寧に扱う必要があります。

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