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.
...