はじめに
『DApps開発入門』という本や色々記事を書いているかるでねです。
今回は、一定期間後にノンファンジブルトークンからファンジブルトークンに変わる仕組みを提案しているERC5744についてまとめていきます!
以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。
他にも様々なEIPについてまとめています。
概要
ERC5744はERC20の拡張版で、代替性(ファンジブル)トークンが一定期間非代替性(ノンファンジブル)トークンになる仕組みを提案しています。
トークンは発行された直後は非代替性ですが、一定期間経ったのち代替可能になり、通常のERC20トークンと同じように自由に取引や移動ができるようになります。
動機
以下のようなユースケースがあります。
Receipt Tokens
特定の条件を満たすまで利用できないトークンとして活用できます。
例えば、レンディングプロトコルにおいて、最低預入期間を守るために一定期間ロックされるトークンとして機能できます。
Vesting Tokens
トークンが一定の期間を経過しないとtransfer
できない仕組みです。
例えば、企業が従業員に支給するトークン報酬(ストックオプションのようなもの)が、一定期間経過後に初めて自由に売買できるようになる場合に使えます。
このように、特定の期間や条件を満たした後に通常のERC20トークンと同じように機能するトークンを設計できることで、より柔軟なトークンの活用が可能になります。
仕様
ERC5744に従うトークンはERC20を実装する必要があります。
ただし、通常のERC20トークンとは異なり、トークンが一定期間経つまでノンファンジブルになります。
そのためにいくつか関数を追加する必要があります。
balanceOf
と totalSupply
balanceOf
と totalSupply
の関数は、一定期間経過後のトークンも含めて全てのトークンの総数を返します。
balanceOfMatured
新たに balanceOfMatured
という関数を追加する必要があります。
この関数は、指定されたアドレスが所有する一定期間経過後のトークンの残高を返します。
function balanceOfMatured(address user) external view returns (uint256);
getMints
getMints
という関数も新たに追加する必要があります。
指定されたアドレスがMintしたトークンの詳細情報を配列で返す関数です。
struct MintMetadata {
uint256 amount; // 発行されたトークンの数量
uint256 time; // 発行されたタイムスタンプ(秒単位)
uint256 delay; // 一定期間経過までの遅延時間(秒単位)
}
function getMints(address user) external view returns (MintMetadata[] memory);
delay
の値は、トークンが一定期間経過するまでに必要な時間です。
ただし、この時間が事前に決まっていない場合(例えば、外部の要因によって決まる場合)、この値は type(uint256).max
に設定する必要があります。
mints
オプションで mints
という関数を追加できます。
この関数は、指定されたアドレスとIDをもとに、特定のミントに関する詳細情報を取得します。
function mints(address user, uint256 id) external view returns (MintMetadata memory);
ここで id
の値は、必ずしも単純な配列のインデックスである必要はなく、他の方法で生成された識別子でも問題ないです。
一定期間経過前トークンの制限
トークンが一定期間経過する前に送付(transfer
)やBurn(burn
)を防ぐため、transfer
や transferFrom
の関数を変更できます。
一定期間経過前のトークンを送ろうとすると、トランザクションをrevert
させる仕組みを導入できます。
同様に、一定期間経過前のトークンをburn
しようとした場合も失敗させることが可能です。
メタデータの拡張
この標準を実装するトークンは、ERC20のメタデータ拡張(name
や symbol
の取得機能)もサポートする必要があります。
具体的には、name
と symbol
は元となるトークンの名称とシンボルを反映するように設定する必要があります
補足
mints
メソッドがオプションである理由
mints
メソッドは必須ではなく、オプションとして扱われています。
その理由は、IDの管理が必須ではない場合があるためです。
例えば、ベスティングトークン(一定期間ロックされるトークン)のように、ユーザーごとに最大1回しか発行されないケースではIDを使う必要がありません。
一方で、トークンの発行が頻繁に行われる場合は、mints
メソッドを実装することで、個々のミント情報を取得しやすくできます。
transfer
可能な設計の違い
この標準は、用途に応じてトークンのtransfer
ルールを変えられるように設計されています。
ベスティングトークンの場合、トークンが一定期間経過するまでtransfer
を禁止するのが一般的です。
これは、受け取った人が一定期間トークンを保持することを前提としているためです。
Receipt Tokensの場合、たとえ最低預入期間が設定されていたとしても、トークンのtransfer
を許可するケースがあります。
これは、担保として使うためなどユーザーに柔軟な運用をさせるためです。
このように、トークンの用途によってtransfer
ルールをカスタマイズできるようになっています。
大量のMint情報を返す問題
ユーザーが保有するMint情報が膨大になるケースを考慮すると、全てのデータを一度に取得するのは非効率です。
しかし、これはあまり現実的な問題ではないので仕様には含めていません。
もし特定のユースケースでこの問題が発生しそうな場合、実装者は以下のような実装が検討できます。
function getMints(address user, uint256 startId, uint256 endId) external view returns (MintMetadata[] memory);
ただし、IDが連番ではなく、別のルールで管理されている場合は、異なる取得方法が必要になる可能性があります。
そのため、このようなバリエーションは標準仕様には含めず実装者に判断を委ねています。
互換性
ERC5744はERC20標準と完全に互換性があり、他の標準との互換性の問題はありません。
セキュリティ
大量のデータ処理に関するリスク
トークンのMint情報が大量にある場合、それを一度に処理するとガスコストが大幅に増加します。
特に、全てのMint情報をループ処理して取得する実装は推奨されません。
なぜなら、処理にかかるガス量がブロックのガスリミットを超えてしまうと、トランザクションが失敗するためです。
最悪の場合、ユーザーがトークンを操作できなくなる可能性もあります。
対策の考え方
この問題を回避するためには、以下のような工夫が考えられます。
- 必要な情報だけを返すように設計する(全Mint情報を一括で取得しない)。
- ユーザーが保有するMint数が多い場合に備え、ページング(範囲を指定して取得)する仕組みを用意する。
- 計算コストが高くなりすぎないよう、オンチェーンで処理せずにオフチェーンのデータベースやインデックスサービスを活用する。
具体的な対策は実装の方法によりますが、大量のデータを一度に処理しないよう工夫することが重要です。
引用
Cozy Finance (@cozyfinance), Tony Sheng (@tonysheng), Matt Solomon (@mds1), David Laprade (@davidlaprade), Payom Dousti (@payomdousti), Chad Fleming (@chad-js), Franz Chen (@Dendrimer), "ERC-5744: Latent Fungible Token [DRAFT]," Ethereum Improvement Proposals, no. 5744, September 2022. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-5744.
最後に
今回は「一定期間後にノンファンジブルトークンからファンジブルトークンに変わる仕組みを提案しているERC5744」についてまとめてきました!
いかがだったでしょうか?
質問などがある方は以下のTwitterのDMなどからお気軽に質問してください!
他の媒体でも情報発信しているのでぜひ他も見ていってください!