I have an ERC-721 token, and I want to implement a condition in the transferFrom function that prevents the token from being traded on the blockchain once a certain condition is met. Specifically, I want the token to have a limited lifespan of trading, let's say 5 trades, after which it should not be able to be listed on any kind of exchange.

However, I'm concerned that implementing this condition might make the ERC-721 token non-compliant with the standard followed by exchanges. I want to ensure that the token remains compatible with other exchanges while enforcing this trading limitation.

How can I implement this condition in a way that does not violate the ERC-721 standard and keeps the token available for trading on other exchanges?

Note: I am using Solidity and considering modifying the transferFrom function to enforce the trading limitation.

1 Answer 1


First things first, you need to understand what ERC721, or for that matter, any interface standard is - it is simply a set of functions and events that the smart-contract needs to implement to be compliant.IERC721 from OpenZeppelin

The actual implementation is something that's left to the developer - for example, when transferFrom is called, usually this is handled by updating some internal mapping(uint256 => address) such that the tokenId points to a new wallet address. But there is no enforcement on this at all - if you decide to use an array with indexes instead, no one can stop you. You'll also see that the restriction that only the tokenId owner should be able to transfer it is not something that's defined on the interface level. What I'm trying to say with all of this is, an interface is just a promise, an "external thing" third-party contracts (or marketplaces) can only check by calling supportsInterface(interfaceId). Whether you actually fulfill the promise (or make a malicious contract), that's a whole different thing.

To get back to your original question, yes, you certainly can impose a transfer restriction (we already have NFTs with on-chain royalty enforcement).

For your scenario, you would have to override the internal _transfer function which is used in all three (safe)transferFrom variants and add a mapping to store how many times each token was transferred. Perhaps something like this:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract TransferRestrictedNFT is ERC721 {
    uint256 private immutable MAX_TOKEN_TRANSFERS;
    mapping(uint256 => uint256) private _tokenTransfers;

        string memory name,
        string memory symbol,
        uint256 maxTokenTransfers
    ) ERC721(name, symbol) {
        MAX_TOKEN_TRANSFERS = maxTokenTransfers;

    function _transfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual override {
            _tokenTransfers[tokenId] < MAX_TOKEN_TRANSFERS,
            "<YOUR ERROR MESSAGE>"
        super._transfer(from, to, tokenId);

I've given you a general example here, but you can probably modify it to only count "trades" if the operator is one of the major marketplaces.

  • Thanks for your help. Your explanation clarified the issue, but it raised another question. If I add a maximum price for NFT trades, wouldn't that make the contract non-compliant with marketplaces? They don't use the price argument in the _transfer function's definition so they will discard the NFT collection. Unless they allow deploying my own exchange contract for my NFT collection, what can I do to ensure compliance to enforce the maximum price?
    – J code
    Commented Jun 2, 2023 at 12:32
  • You can't add restrictions on the price as that's completely handled by the marketplace smart-contract.
    – Ape Toshi
    Commented Jun 2, 2023 at 12:55
  • Appreciate your help , thanks mate .
    – J code
    Commented Jun 2, 2023 at 14:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.