-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ERC-721 Transfer Fee Extension #2665
Comments
Why was #2664 opened and closed? |
Competing EIP : |
Updated the OP to include suggestions from the community. |
Added Royalties as percentage of sales. |
FYI: This will be 2664. Vanity number inflation is punished by not getting the number you want. 😄 Recommend simplifying the spec to just extend/implement EIP-721 rather than re-implementing it. |
Because of existing projects already published on-chain, ERC2665 will be kept as an interface name and usage name, even though it refer to what is formally accepted as ERC-2664. If need be and if you want full formalism, ERC-2664 can be rewritten as simply being an alias to something called ERC-2665 (ERC here meaning Ethereum Renaming Circumvention) containing the standard described above. 😄😄😄 I would also be very glad if you could point me to where such a consensus for ERC-2665 renaming has been decided, and what the appeal process is as this decision comes nearly a year after initial submission and would just confuse users while seemingly coming from a single voice that had no personal cost associated with taking an unilateral decision. 🤔 As an early comment and decision it would be fair, but now that contracts exist implementing it, this causes retrocompatibility issues that are not technically justified.
Then the standard would lose of it's accuracy, as there is no way currently in solidity to describe an "override" of already described functions predicates and postulates. (in that an interface cannot override another interface, as interfaces simply cannot inherit). |
This isn't even EIP yet, it is just an idea for an EIP which generally receives no un-solicitied review. To create an EIP you need to create a pull request against this repository and add a new EIP file that follows the template. It will get reviewed for structure, and then you can work it through the review process. Normally when people start with an idea issue we let them use that number for the follow-up EIP when it is created, but we historically have taken a somewhat hard stance against number squatting. |
Sorry about that, I was not aware it was frowned upon given the number of issues that were created instead of repoened when talking about the same subject. There is no guideline about it in the given documentation, it's a cultural thing that is unknown to first time contributors. If your comment was shortly after the initial post, when the interface name was still ERCXXXX, there would be no issue with it. Outside of formalism, the "brand" name of this proposal is ERC-2665 as this is how a layman understand it and a name was necessary for interface naming. Given that published code is using this interface name and associated ERC165 hash, the brand name will stay ERC-2665 to allow for better retro-compatibilities on what is ultimately an administrative formalism. This standard is still under construction as big changes are happening for NFT and more specifically things related to layer 2/Migrations, and hence it is far from ready to be an ERC, which will most likely happen post sharding. Recommend adding naming guidelines in documentation on issue/EIP/ERC track, as there is currently a chicken and egg problem if the standard name is used in an ERC165 hash. (Not a problem in other cases) Do you have comments/suggestions that are relative to the content rather than the form ? More spefically because I see you are active here and might have good insight related to the interaction between NFT ownership change and shards/layer2. |
I personally generally don't review EIPs in the "idea" phase, especially ERCs, because I am already way too busy just trying to keep up with EIPs going through the EIP process. Once you are ready to start the EIP process an editor will review it, but really just for structural/process compliance. |
Re: How is the number chosen: https://eips.ethereum.org/EIPS/eip-1#eip-header-preamble and https://raw.githubusercontent.com/ethereum/EIPs/master/eip-template.md The EIP number is assigned by an EIP Editor (e.g., me) when the EIP enters the draft stage. |
This is a problem costing real money to innocent third parties when dealing with ERC-165 hash. More transparency or at least an earlier discussion would be appreciated as to not undermine efforts to champion a standard by forcing a rename due to implicit culture. I do believe your goal is to deincentivize number squatting. Lesson learned. However I also believe your goal is to promote ERC as being relevant and clear standards that attract quality contributors. |
Generally speaking, no one should be implementing "standards" until they are actually standardized. 😄 There is value in experimental implementations (as seen in browsers), but they are usually setup in a provisional way so that changes to them are not hard. In this case, this is just an idea (from a process standpoint) and not a standard at all. If people are implementing a standard before it has gone through a standardization process, then either the standard bends (usually resulting in a poor standard) or the implementations bend (resulting in non-standard implementations). |
Irrelevant to the championship/naming of it. A standard only has value if people use it. A name is necessary to gather people that are gonna work together on this standardization. Renaming a standard (wip or not) is effectively forking it. A standard can bend with additional, optional features that are still retro-compatible (USB...). |
Tôi khong hiểu tiếng anh và cũng hông rành về mảng này? Bạn giup toi nhé |
EIP number does not changes function signatures nor deny all the good work put in place to produce this nice proposition. (It's just a pain to rename everything) It seems to be a good alternative to the market locked-in royalties alternative #2907 and superseed #2571 which follow the same idea of embedding the fee calculation within the token contract. |
My bandwidth is currently quite full, but a reformatting of this EIP to make it easy to implement (and working cross chain) is currently in the work. Function would stay the same, except there is gonna be a "developper readable" deliverable (with example sample implementation) + a full formal specification. |
There has been no activity on this issue for two months. It will be closed in a week if no further activity occurs. If you would like to move this EIP forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review. |
A lot of the feedback on it is how to make it both marketplace and chain transfer compatible. We are currently working on bridging NFT from EVM to EVM, which ultimately ties in in this fee feature. |
There has been no activity on this issue for two months. It will be closed in a week if no further activity occurs. If you would like to move this EIP forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review. |
This issue was closed due to inactivity. If you are still pursuing it, feel free to reopen it and respond to any feedback or request a review in a comment. |
eip: 2665 ?
title: ERC-721 Transfer Fee Extension
author: Guillaume Gonnaud g.gonnaud@perpetual-altruism.org
discussions-to: #2665 ethereum-magicians Thread
status: WIP
type: Standards Track
category: ERC
created: 2020-05-21
In the following, it is assumed that the attributed EIP number will be 2665, as it is traditionnally the issue number of this thread. However, an EIP number has yet to be formally attributed.
Simple Summary
An ERC-721 extension allowing publishers to specify if a transfer fee should be paid with every transfer. The fee currency is defaulted to ETH, but ERC-20 tokens or even non-crypto currencies are within the scope of the standard.
Abstract
The following standard is an extension of the ERC-721 standard. It exposes a queryable Transfer Fee that needs to be paid for a transfer to be processed.
In order to allow for the same transaction flow as a non-payable Transfer ERC-721 implementation, an eval to 0 remanence guarantee on the Transfer Fee is introduced, as well as the possibility for an operator/owner to use the
approve
function to pay the Transfer Fee.Motivation
Some processes and products require third parties to be properly incentivized in order to be perennial. E.g. gas fee and block reward paid to miners on the Ethereum blockchain. Content creator remuneration is not a new problem, with multi-billion dollar industries being created and destroyed around the various solutions that have emerged to tackle it. Ethereum, and blockchains in general, are most likely going to be the backbone of the next paradigm shift.
Previous ERC-721 extension EIPs describe new ways to incentivise content creators. However, they often require a fundamental change in the transaction flow of NFTs. The current NFT ecosystem and standards are already proven, and fundamental changes are not needed to solve this issue.
A very minor extension of the ERC-721 specification would allow both wide interoperability and strong creator incentivization.
Author's note: As the NFT ecosystem is developing at an astonishing pace, a standard that allows a reliable incentivization structure may be what is needed to unlock a trustless digital ownership revolution pushed by media majors, marketplaces and creators.
ERC-721 allows for
safeTransferFrom
andtransferFrom
to be payable as a weak mutability guarantee; it allows, for example, the creator of the token to collect a fee. However the payable being the weakest guarantee and the lack of specification for an explorable fee led to most ERC-721 token ending up being transferrable for free.Approve
also has payable as the weakest guarantee. WhileApprove
has a different use case thanTransferFrom
, sellers could useApprove
to pay in advance a potential transfer fee on behalf of the operator.Specification
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" are to be interpreted as described in RFC 2119.
Every ERC-2665 compliant contract MUST implement the
ERC721
,ERC165
andERC2665
interfaces (subject to "caveats" below):Every ERC-2665 compliant contract SHOULD implement the following interface if they wants to provide a standardized way for marketplaces to provide a royalty fee as a percentage of a sale :
A wallet/broker/auction application MUST implement the wallet interface if it will accept safe transfers.
The following "ERC2665 Metadata JSON Schema" is proposed as an extension to the "ERC721 Metadata JSON Schema". ERC-2665 compliant tokens implementing the ERC-721 Metadata extension MUST return this schema instead of the one described in "ERC721 Metadata JSON Schema".
Please refer to EIP-721 for the metadata extension and enumeration extension.
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
Due to the nature of payable fees, the metadata extension SHOULD be implemented in order to inform users about the nature and amount of the fees.
Caveats
The 0.6.6 Solidity interface grammar is not expressive enough to document the ERC-2665 standard. A contract which complies with ERC-2665 MUST also abide by the following:
A contract that implements ERC-2665 MUST also abide by the ERC-721 standard. Functions defined in
interface ERC721
are all overridden by the function and specifications defined ininterface ERC2665
above.If
getTransferFee(uint256)
is implemented as something else than apure
function always returning0
, thensafeTransferFrom
(both versions),transferFrom
andapprove
MUST be implemented aspayable
. This takes precedence over the mutability guarantees of ERC-721.Any function call MUST throw if the conditions described in their interface are met. They MAY throw in other, additional conditions too.
Non specified functions in the standard that contracts should implement for full functionality.
The interface defined above exist for inter-operability purposes. However, smart contract publishers are reminded to implement the following features in their contracts :
Standard ERC-721 features, such as minting, and desirable genric smart contract features, such as an "owner" property.
A way to set up and modify fixed and percent based trading fee for their tokens. eg :
setPercentSaleFees(uint256 _tokenId, uint256 _saleFeeNumerator, uint256 _saleFeeDenominator) external
A way to nominate and edit marketplaces trusted to handle royalties are percent of sales. eg :
function setTrustedMarketplace(address _marketplace) external
Rationale
This EIP is a first draft on how to give publishers more options on what kind of NFTs can be created and the fees that can be collected whilst still maintaining the same flow of trade for users, platforms and wallet providers. Only minimal changes to existing code would be necessary to implement this EIP to previous ERC-721 compatible software solutions.
Summarized additions compared to the ERC-721 Specification
A new function :
getTransferFee(uint256 _tokenId) external view returns (uint256)
. It is overloaded withgetTransferFee(uint256 _tokenId, string _currencySymbol) external view returns (uint256)
if the fee need to be paid with a different currency than ETH.If a call to
getTransferFee(_tokenId, _currencySymbol)
would have returned0
at any point, then any posterior call with the same arguments MUST return0
until aTransfer
event has been emitted for_tokenId
. This is called in the rest of this EIP the eval to 0 remanence guarantee.Successfully calling
approve{value : getTransferFee(_tokenId)}(address _approved, uint256 _tokenId)
will atomatically makegetTransferFee(_tokenId)
eval to0
.All
safeTransferFrom
variants now callonERC2665Received
instead of the ERC-721 specific function.ERC2665TokenReceiver
is derived fromERC721TokenReceiver
accordingly.Changing the mutability of
safeTransferFrom
& overloads,transferFrom
andapprove
to always be payable ifgetTransferFee
can return non-zero values.Changing the sufficient throw conditions of the
transferFrom
functions. More specifically adding:Throws if msg.value < getTransferFee(_tokenId)
."ERC2665 Metadata JSON Schema" extended from the "ERC721 Metadata JSON Schema" to provide fee information without polluting the description of an NFT.
Extension compatibility preserved. If something extends ERC-721, it can extend ERC-2665.
Discussion
Whether ERC-2665 follows ERC-721 could be debated because of change Add a Gitter chat badge to README.md #4. This change is important, as some smart contracts designed to only handle free
Transfer
ERC-721 tokens could get an ERC-2665 stuck. The actual consequence of the spec extension is that thesafeTransferFrom
functions will throw more than the minimum required by ERC-721, which is already covered in the ERC-721 spec itself. Therefore, ERC-2665 follows ERC-721 and is simply an extension of it.The
getTransferFee
function is where most of the engineering work for publishers lies. The function isview
, meaning no state changes can happen when it's being called. Moreover, the eval to 0 remanence guarantee is extremely important in order for an ecosystem to be built around this standard, as it guarantees that the next Transfer can follow feeless ERC-721 behavior and that a Transfer Fee can be paid in advance.A more subtle consequence of
getTransferFee
beingview
is that it shall not depend onmsg.sender
, but rather only of non-manipulable parameters such as the current owner and operators of the token.The eval to 0 remanence guarantee is specifically worded so that the change of ownership could be done through a mechanism that is not related to ERC-2665 (e.g. the publisher’s own trading system). However, the specifications of
Transfer
must still be respected even if the change of ownership is not done through a call to an ERC-2665 related function. ERC-2665 does not specify any Transfer Fee refund mechanism should the token change owner through a mechanism other than ERC-2665.getTransferFee
can be restricted to pure (e.g : if the fee is static like always 0 wei, aka typical ERC-721 tokens).While publishers are free to implement whatever behavior they want behind the
getTransferFee
function, it is impossible to guarantee a fee calculated as a direct percentage of an actual sale price. The money exchange for that transfer, if any, could simply be happening off-chain. Therefore, rather than implementing a complex "fee calculation and distribution" protocol, ERC-2665 is generic enough to be easily interactable by third parties. This gives publishers the freedom to specify the fee, which can be complex, variable and potentially oraclized (e.g. the fee is always 10 USD), and standardized entry-points for the fee to be paid and distributed.getTransferFee
can be implemented to return 0 if the token is owned/operated by an address owned by a partner of the publisher. This incentivizes publishers and marketplaces to partner-up : The publisher gets more exposure and an UX tailored to its product, and the marketplace becomes cheaper than its competitors for these tokens. The Transfer Fee could then be supplanted by a real-world commercial contract, or something in chain, like for example, a direct percentage of the sales proceeds. This allow token publishers to guarantee a fee in trustless environments while pushing trades to happens on marketplace that is gonna remunerate them fairly.As long as an ERC-2665 smart contract is accessed in a read-only fashion or that the
safeTransfer
functions are not used, any software designed to interact with feeless ERC-721 can interact with ERC-2665 without any update necessary. However, if theTransfer
functions were assumed to always be free/non-payable (i.e. if the software implementation was only compatible with a subset of ERC-721), then problems might arise. A few ways to mitigate such issues are suggested in the Backwards Compatibility section below.Due to the addition of
getTransferFee
, the ERC-165 signature of theERC2665
interface is different from the one of theERC721
interface. However, all of the ERC-721 function signatures are implemented unchanged. Should an ERC-2665 smart contract be declared as implementingERC721
when being asked about it through ERC-165supportsInterface
? The answer is yes, as ERC-2665 is fully ERC-721 compliant, and only limitations in the Solidity language (Namely lack of Interface inheritance and design-by-contract programming abilities) or the chosen method of computing ERC-165 identifiers could suggest a different answer that ultimately do not have a use case.What should be the gas limit of
getTransferFee
, if any ? Its behaviour needs to be implementable as more complex than an ERC-165 check, but nonetheless gas spending should be kept low to prevent accidental locking in a custodian wallet.Regarding non-ETH currency fees, the Standard is on purpose extremely generic, as there is no limit on what these currencies could be, nor would they need to be in-chain currencies.
If the fee is not in ETH, token publishers SHOULD implement the ERC-721 metadata extension with the ERC2665 Metadata Json Schema and provide informations on how to pay the fee there.
Suggested flow for ERC-20 fees is that the fee payer gives an
allowance
of the currency to the ERC-2665 contract, then a subsequent call totransferFrom
orapprove
will make the ERC-2665 collect the fee frommsg.sender
. An implementation example of a contract requiring such a fee will be provided.Backwards Compatibility
Every ERC-2665 contract is fully compliant with the ERC-721 standard, meaning backwards compatibility issues can only arise if the software interacting with an ERC-2665 contract was in fact not ERC-721 compliant in the first place.
Upgrading from ERC-721 to ERC-2665
Token publisher
ERC-2665 is an extension of ERC-721, meaning that any ERC-721 contract can be extended to be also ERC-2665. The minimal work necessary is to implement
getTransferFee()
, the relevant ERC-165 codes and the proper handling of the fee in the approval/transfer functions, as well as changing anyonERC721Received
call toonERC2665Received
.getTransferFee
could be reading a price oracle smart contract averaging the last transactions on a marketplace, relying on an original price discovery mechanism, be it a fixed wei amount, or be it obtained by calling a smart contract specified by the token creator, depends on a complex interaction with another marketplace, simply set to 0, etc...The fee MUST be able to be paid either using
approve()
ortransferFrom()
if the fee is in ETH, but apart from this you MAY implement any extra fee collection and distribution mechanism you want. e.g : give the ability for a marketplace you trust is gonna give you 10% of the sale the ability to pay 0 wei as an actual transfer fee.No particular behavior for overpaying/refunding a fee is specified in ERC-2665. The only real constraint is the eval to 0 remanence guarantee of
getTransferFee
.ERC-2665 token publishers SHOULD make it so that sending more than the
TransferFee
when transferring a token makes it so that the next TransferFee can be waived. The exact behavior is left to the creativity of the publisher, but atomicity of theTransfer{value}() => getTransferFee() == 0
sequence is sought after for an ERC-2665 token to be easily traded at custodial third party marketplaces.Similarly, ERC-2665 token publishers SHOULD also make it possible for
Approve()
to pay the subsequent Transfer Fee, so thatApprove{value}() => Transfer(){0} => getTransferFee() == 0
can also be an atomic sequence.Frontend, UX, and other off-chain interactions.
Minimal implementation
Make users send a
value
ofgetTransferFee(_tokenId)
Wei when callingTransfer
orApprove
functions if the token is ERC-2665.Suggested implementation for Wallet/Broker/Auction applications
Due to the very nature of a transfer fee, gasless listings would place the burden of paying the transfer fee on the buyer. Informations on the amount and nature of this fee SHOULD be clearly communicated to any potential sellers and buyers. There is no guarantee in the ERC-2665 standard that any two subsequent, non atomic
getTransferFee()
calls will return the same value, except if this value is0
due to the eval to 0 remanence guarantee .If you want for a seller to pay the transfer fee in advance, you might have to simulate a post-transactions state so that a potential future recipient of the token can receive it without having to pay the transfer fee. This is of course non-trivial and varying with ERC-2665 implementations, but some paths are explored below.
Wallet/Broker/Auction Smart Contracts
Subsequent Transfer Fee paid by the seller (if any)
The simplest way to make your (awesome) decentralized auctioning smart contract that was working just fine with feeless ERC-721 compatible with ERC-2665 is to add an implementation of
onERC2665Received
just like this :Keep in mind though that the safeTransferFunction is now calling
onERC2665Received
on any potential new owners, which might require a few more changes in your code. Do not forget about updating your ERC-165 code either.Transfer Fee paid by the buyer (if any)
Assuming you have some
win(uint256 _tokenId, address _tokenContract, address _from, address _to, uint _fee, bytes _data)
function that is used by the buyer to get the token. (Unoptimized code and separated cases for clarity).This function signature is just given as an example, and it's parameters could come from other sources such as internal variables/function calls/msg.sender/etc...
Test Cases
To be provided once sufficient discussion happened
Implementations
References
Copyright
Copyright and related rights waived via CC0.
The text was updated successfully, but these errors were encountered: