はじめに
ERC-721とは、Ethereum上でNon-Fungible Token(NFT)を実現するための現実的な標準規格です。
以下のEventとFunctionのインターフェースを実装することで、様々な発行者のNFTを共通に取り扱うことができるようになります。
interface ERC721 /* is ERC165 */ {
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
function balanceOf(address _owner) external view returns (uint256);
function ownerOf(uint256 _tokenId) external view returns (address);
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
function approve(address _approved, uint256 _tokenId) external payable;
function setApprovalForAll(address _operator, bool _approved) external;
function getApproved(uint256 _tokenId) external view returns (address);
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}
この規格があることにより、OpenSeaといったNFT取引所はいくつものNFTを同じように取り扱うことができます。
transfer
ERC-721にてトークンの所有情報を譲渡する場合には、ERC-721コントラクトへtransferFrom
関数を実行することで実現されます。
通常、そのトークンの所有者であれば、相手がEOA(秘密鍵によるアカウント)であっても、コントラクトアカウントであっても、譲渡が可能です。
下図は、EOAであるAliceからEOAのBobもしくは、コントラクトCarolにトークンの譲渡を行うイメージです。
ここで、トランザクションの発行対象は、ERC-721のコントラクトになります。
approve
Charlieコントラクトという預け入れコントラクトがあったとします。
ここで、ERC-721へのtransferFrom
ではなく、Charlieコントラクトのdeposit
機能を使って預けたい場合があります。
このとき、Charlieコントラクトでは、deposit
機能内で、ERC-721コントラクトに向けてtransferFrom
の内部トランザクションを発行しますが、当然トークンの所有者でないため失敗します。
そこで、「転送の許可」であるapprove
を実行し前もってCharlieへ譲渡を許可します。
具体的なユースケースとしては、トークンのマーケットプレイスがあります。
マーケットコントラクトに対して事前にトークンのapprove
を実行し、出品exhibit
をします。
トークンの買い手Bobが現れた際には、指定の金額を送付し1つのトランザクションでトークンの売買が成立します。
setApprovalForAll
前述のapprove
によって、トークンの譲渡を自動化することができ、条件によって転送させることができるようになりました。
NFTにおいてトークン一つ一つは代替不可能なものであり、トークン1つごとにapprove
の必要があります。
そこで、ERC-721では、setApprovalForAll
が規定されています。
これは、特定のアカウントに対して、所有する全てのトークンの転送を許可することができます。
つまり、マーケットコントラクト上で煩わしいapprove
は不要になります。
また、Ethereum上では、全てのトランザクションにGasというコストがかかります。
すでに、setApprovalForAll
により譲渡の許可がされているのであれば、
信頼できるマーケットの管理者が、代理で出品を行うことで販売者はコストを0にし、利便性が上がるでしょう。
悪意のあるsetApprovalForAll
さて、煩わしいapprove
と、それを一気に解決してくれるsetApprovalForAll
ですが、
悪意のあるコントラクトへ許可してしまった場合はどうでしょう?
Evilコントラクトは、Aliceの保有トークンを好きに動かせるようになります。
つまり、悪意のあるアカウントであるMalloryは、Evilコントラクトを経由して、Aliceのトークンを盗み出すことができます。
さいごに
Ethereumは、非中央集権である部分がもてはやされていますが、現実的なサービスは管理者が存在しユーザーの利便性のためsetApprovalForAll
を利用しているケースがあります。
setApprovalForAll
は全権の移譲です。全てを自己責任とすることもできます。
しかしながら、第三者によるソースコードの保証があり悪意の働けないコントラクトになっていることが確認できる場合や、信頼できるサービス提供者であることを確認した上でsetApprovalForAll
を実行するほうが良いでしょう。
また、サービス提供者も、最低限のソースコード公開は必須だと思います。