背景
NFTがこれだけ注目された理由の一つが、二次流通の際にアーティストに支払われるロイヤリティでした。普通のアート作品は、一度アーティストの手を離れたら、どんなに二次流通市場で値段が上がったとしても、その見返りはありません。
アーティストに対するロイヤリティの仕組みを作ったのは、NFTの取引所のOpenSeaでしたが、その仕組みは、ブロックチェーンの外で行われるものであり、スマートコントラクトにより自動化されたものではありませんでした。
それでも、OpenSeaが圧倒的なシェアを持っている間は良かったのですが、ロイヤリティを支払わない競合が、(ロイヤリティを支払わなくて良い分の)手数料の安さを売りにOpenSeaから奪い始めたので、徐々に問題が大きくなって来ました。
この状況を受けて、OpenSeaが、新たな仕組みを発表したのですが、それも根本的なものではなく、ロイヤリティを支払わない悪質な取引所をブラックリストに入れて、そこでの取引を不可能にする、というものでした。
問題に対する対策案
A major flaw of ERC721
While NFT is playing a very important role to bring more people into the Web3 ecosystem and even create new income opportunities for artists, the protocol itself, ERC721, is still very immature and has a few fundamental issues.
Royalties are not enforceable.
Many NFTs are stolen.
It is not decentralized.
Because royalties are not part of ERC721, it is up to the marketplaces, such as OpenSea, to pay royalties.
As the result, many royalty-free were born, and the “Race to the Bottom” has started.
A lot of NFTs are stolen by scam sites, which ask the user to connect his/her wallet, let him/her call ApprovalForAll (without understanding what it means), and steal NFTs.
The fundamental flaw of ERC721 is in this “approve & transfer” model, which gives too much power to the marketplace, far from the beauty of Web3’s “decentralized and trustless” model.
Once the token owner calls Approval or ApprovalForAll, the marketplace can do whatever they want to do to the token (or tokens).
This is why royalty-free marketplaces were born, and so many NFTs are stolen.
In order to solve this problem, we need to create a new mechanism, which performs transactions without trusted third parties (P2P transactions), and makes it possible to enforce royalties.
P2P/Trustless transactions
Decentralized transactions will become possible by adding three methods to ERC721.
interface ERC721P2PCore {
function setPriceOf(uint256 _tokenId, uint256 _price) external;
function getPriceOf(uint256 _tokenId) external view returns(uint256);
function purchase(uint256 _tokenId, address _wallet) external payable;
}
The token owner calls setPriceOf method to set the asking price of a specific token he/she owns.
Anybody can access this asking price by calling the getPriceOf method (it returns 0 if it is not specified).
Anybody can buy it by calling the purchase method by paying the asking price.
The smart contract that receives this money (via purchase method) distributes it between the token owner and the artist, enforcing the royalty payment agreement between them.
Please notice that this transaction happens just between the seller and the buyer, without involving any third party. Because of that, it is possible to make a trade by using Etherscan.
This is already a huge improvement over the current “approval & transfer” mode, but we need to solve another scenario where the buyer makes an offer first (or makes an offer lower than the asking price).
“Offer and Accept” scenario
There are a few possible ways to support this scenario, but I think the decentralized marketplace is the most reasonable solution.
interface IERC721Marketplace {
function makeAnOffer(ERC721P2PCore _contract, uint256 _tokenId, uint256 _price) external payable;
function withdrawAnOffer(ERC721P2PCore _contract, uint256 _tokenId) external;
function getTheBestOffer(ERC721P2PCore _contract, uint256 _tokenId) external view
returns(uint256, address);
function acceptOffer(ERC721P2PCore _contract, uint256 _tokenId, uint256 _price) external;
}
interface ERC721P2PCore {
function setPriceOf(uint256 _tokenId, uint256 _price) external;
function getPriceOf(uint256 _tokenId) external view returns(uint256);
function purchase(uint256 _tokenId, address _wallet) external payable;
function acceptOffer(uint256 _tokenId, IERC721Marketplace _dealer, uint256 _price) external;
}
The buyer makes an offer by calling the makenAnOffer method at an autonomous market place, staking the amount of money he/she is willing to pay.
The seller (or other buyers) can see the current best offer (on that particular marketplace) by calling the getTheBestOffer method.
The buyer accepts this offer by calling the acceptOffer method of the ERC721P2PCore contract, which matches the asking price to the offer price, and calls the acceptOffer method of the specified autonomous marketplace.
The autonomous marketplace calls back the purhase method with the money from the buyer, and let it complete the transaction.
ERC721 compatibility
For a smooth transition, it makes sense to make the new protocol compatible with ERC721, simply inheriting it. We, however, need to disable (or partially disable) the approval and approvalForAll method, in order to prevent transactions on royalty-free marketplaces.
During the transition period, it makes sense to have a whitelist of marketplaces, so that traditional “approval and transfer” style transactions can happen only on trusted marketplaces that pay royalties appropriately.
We don’t need to disable the transfer method, which allows token owners to transfer their tokens to other wallets. We don’t need to eliminate off-the-market transactions completely.
Security Concerns
With this change, scam sites will attempt to let the user call the acceptOffer method at a very low price. We certainly need a special UI on the wallet (such as Metamask), which presents the meaning of this transaction (the NFT and the offer price).
Incentive for Marketplave
A few people have pointed out that we need to come up with an incentive mechanism for existing marketplaces to continue to serve their roles.
We can add an optional facilitator parameter to the purchase() method, and distribute a fixed amount (such as 2.5%) to that address as a reward.
function purchase(uint256 _tokenId, address _wallet, address _facilitator) external payable;
WithdrawAnOffer abuse
Although it makes sense to immediately cancel the existig offer when a higher bid was made to the same contract, this implementation allows hackers to make a very high offer to kick the current offer out, then, withdraw that offer immediately and make a lower offer.
We can prevent this behavior by adding a certain period (such as 24 hours), which does not allow the bidder to withdraw the bit.
【日本語訳】
ERC721の大きな欠点
NFTは、より多くの人をWeb3のエコシステムに取り込み、さらにはアーティストに新たな収入機会を創出するために非常に重要な役割を果たしていますが、ERC721というプロトコル自体はまだ非常に未熟で、いくつかの根本的な問題を抱えています。
ロイヤリティに強制力がない。
多くのNFTが盗用されている。
非中央集権的でない。
ロイヤリティはERC721の一部ではないため、ロイヤリティの支払いはOpenSeaなどのマーケットプレイス次第となります。
その結果、多くのロイヤリティフリーが生まれ、「底辺への競争」が始まっている。
ウォレットを接続させ、ApprovalForAllを呼ばせ(意味を理解せず)、NFTを盗むという詐欺サイトによって、多くのNFTが盗まれているのである。
ERC721の根本的な欠陥はこの「承認&送金」モデルにあり、Web3の「分散型・トラストレス」モデルの美点とは程遠い、マーケットに力を与えすぎている点にあります。
トークン所有者がApprovalまたはApprovalForAllを呼び出すと、マーケットプレイスはそのトークン(またはトークン)に対してやりたいことを何でもできるようになります。
これが、ロイヤリティフリーのマーケットプレイスが生まれた理由であり、多くのNFTが盗まれている理由です。
この問題を解決するためには、信頼できる第三者を介さない取引(P2P取引)を行い、ロイヤリティの強制を可能にする、新たな仕組みを作る必要があるのです。
P2P/トラストレス・トランザクション
ERC721に3つの方式を追加することで、分散型取引が可能になります。
interface ERC721P2PCore { (インターフェースERC721P2PCore)
function setPriceOf(uint256 _tokenId, uint256 _price) external.SetPriceOf(uint256_tokenId、uint256 _price)関数。
function getPriceOf(uint256 _tokenId) external view returns(uint256);
関数購入(uint256 _tokenId、アドレス_wallet)外部支払う。
}
トークン所有者は、setPriceOfメソッドを呼び出して、彼/彼女が所有する特定のトークンの希望価格を設定します。
誰でもgetPriceOfメソッドを呼び出すことで、この提示価格にアクセスできます(指定されていない場合は0を返します)。
purchaseメソッドを呼び出すことで、希望価格を支払って購入することができます。
このお金を受け取ったスマートコントラクトは(購入メソッドを介して)トークン所有者とアーティストの間でお金を分配し、両者間のロイヤルティ支払い契約を実施します。
この取引は、第三者を介することなく、売り手と買い手の間だけで行われることに注意してください。そのため、Etherscanを使用することで取引を行うことが可能です。
これはすでに現在の “承認&譲渡 “モードと比較して大きな改善ですが、買い手が先にオファーを出す(または提示価格よりも低いオファーを出す)別のシナリオを解決する必要があります。
“オファー&アクセプト “シナリオ
このシナリオをサポートする方法はいくつか考えられますが、分散型マーケットプレイスが最も合理的な解決策だと思います。
interface IERC721Marketplace { (インタフェースIERC721マーケットプレイス)
function makeAnOffer(ERC721P2PCore _contract, uint256 _tokenId, uint256 _price) 外部支払い可能です。
function withdrawAnOffer(ERC721P2PCore _contract, uint256 _tokenId) external;
関数 getTheBestOffer(ERC721P2PCore _contract, uint256 _tokenId) 外部の表示
は(uint256, address)を返します。
function acceptOffer(ERC721P2PCore _contract, uint256 _tokenId, uint256 _price) external;
}
interface ERC721P2PCore { (英語)
function setPriceOf(uint256 _tokenId, uint256 _price) external; } interface ERC721P2PCore { function setPriceOf(uint256 _tokenId) external;
function getPriceOf(uint256 _tokenId) external view returns(uint256);
関数purchase(uint256 _tokenId、アドレス_wallet) external payable;
function acceptOffer(uint256 _tokenId, IERC721Marketplace _dealer, uint256 _price) external.関数名:acceptOffer(uint256 _tokenId, IERC721Marketplace _dealer)
}
買い手は、自律型マーケットプレイスで makenAnOffer メソッドを呼び出して、彼/彼女が支払うことを望む金額を賭けてオファーを行います。
売り手(または他の買い手)は、getTheBestOfferメソッドを呼び出すことで、(その特定の市場で)現在のベストオファーを見ることができます。
買い手は、ERC721P2PCoreコントラクトのacceptOfferメソッドを呼び出してこのオファーを受け入れ、提示価格をオファー価格に一致させ、指定された自律型マーケットプレイスのacceptOfferメソッドを呼び出します。
自律型マーケットプレイスは、買い手からの資金でpurhaseメソッドをコールバックし、取引を完了させます。
ERC721の互換性
スムーズな移行のために、新しいプロトコルをERC721と互換性を持たせ、単にそれを継承することは理にかなっています。ただし、ロイヤリティフリーのマーケットプレイスでの取引を防止するために、承認およびapprovalForAllメソッドを無効にする必要があります(または部分的に無効にする)。
移行期間中は、従来の「承認と譲渡」式の取引を、ロイヤリティを適切に支払う信頼できるマーケットプレイスでのみ行えるように、マーケットプレイスのホワイトリストを用意することは理にかなっています。
トークン所有者が他のウォレットにトークンを転送できるようにする転送方法を無効にする必要はありません。市場外取引を完全に排除する必要はありません。
セキュリティ上の懸念
この変更により、詐欺サイトがユーザーにacceptOfferメソッドを非常に安い価格で呼び出させようとするでしょう。この取引の意味(NFTとオファー価格)を提示するウォレット上の特別なUI(Metamaskなど)が確かに必要です。
Marketplaveのインセンティブ
何人かの人が、既存のマーケットプレイスがその役割を果たし続けるためのインセンティブメカニズムを考え出す必要があることを指摘しています。
purchase()メソッドにオプションでfacilitatorパラメータを追加し、そのアドレスに報酬として一定額(2.5%など)を分配すればいいのです。
function purchase(uint256 _tokenId, address _wallet, address _facilitator) external payable;
WithdrawAnOfferの乱用
同じ契約に対してより高い入札が行われた場合、既存のオファーを直ちにキャンセルすることは理にかなっていますが、この実装では、ハッカーが非常に高いオファーを出して現在のオファーを追い出し、その後、そのオファーを直ちに取り消してより低いオファーを出すことができます。
この動作は、入札者がビットを撤回できない一定の期間(24時間など)を追加することで防ぐことができます。