Transferring ERC721 tokens

Hi, I have a question about ERC721 safetransferfrom(address from, address to, uint256 tokenid, bytes memory _data). What’s the “_data” and how can I input data when I transfer ERC721 to a contract address?
BTW,
I have added the onERC721Receiver() in my contract, but fail to transfer ERC721 from my eoa address.
I’m not sure that have I understood the step of interacting contract address with ERC721 token. Are the following steps correct?
1 setting a onERC721Receiver() in contract
2 transfer ERC721 token to the contract. And the caller is the owner of this ERC721 token.
3 The contract will mark the received ERC721 token and deposit it into the contract.

Please tell more information about the ERC721 interaction. Thanks in advance.

1 Like

Hi @uua,

From the EIP: https://eips.ethereum.org/EIPS/eip-721

/// @param data Additional data with no specified format, sent in call to `_to`

So you can included any additional data you want in here.

Yes.

I would describe it as follows:

The token holder calls safeTransferFrom and if the recipient is a contract it must implement IERC721Receiver and return its Solidity selector to confirm the token transfer.

I would recommend trying it out with a simple example.

I created a simple ERC721 (please note there is no access control on the minting), along with two other contracts, one that is setup to receive ERC721 and the other which isn’t.

Using safeTransferFrom works when transferring to MyContract which supports and fails when trying to transfer to MyOtherContract.

GameItem.sol

// contracts/GameItem.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

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

contract GameItem is ERC721 {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    constructor() public ERC721("GameItem", "ITM") {}

    function awardItem(address player, string memory tokenURI)
        public
        returns (uint256)
    {
        _tokenIds.increment();

        uint256 newItemId = _tokenIds.current();
        _mint(player, newItemId);
        _setTokenURI(newItemId, tokenURI);

        return newItemId;
    }
}

MyContract.sol

// contracts/MyContract.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

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

contract MyContract is IERC721Receiver {

    /**
     * Always returns `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) {
        return this.onERC721Received.selector;
    }
}

MyOtherContract.sol

// contracts/MyOtherContract.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract MyOtherContract {

}
truffle(develop)> token = await GameItem.new()
undefined
truffle(develop)> myContract = await MyContract.new()
undefined
truffle(develop)> myOtherContract = await MyOtherContract.new()
undefined
truffle(develop)> token.awardItem(accounts[0],'https://example.com/token/1')
{ tx:
...
truffle(develop)> token.awardItem(accounts[0],'https://example.com/token/2')
{ tx:
...
truffle(develop)> await token.safeTransferFrom(accounts[0], myContract.address, 1)
{ tx:
...
truffle(develop)> await token.safeTransferFrom(accounts[0], myOtherContract.address, 2)
Thrown:
{ Error: Returned error: VM Exception while processing transaction: revert ERC721: transfer to non ERC721Receiver implementer -- Reason given: ERC721: transfer to non ERC721Receiver implementer.
...
1 Like

Thanks for replying. The problem has been solved.

1 Like