1

I have Caller and ERC721 contract just like this :

contract SampleToken is ERC721MetadataMintable {
    string private name;
    string private symbol;
    constructor (address _creator, string _name, string _symbol, string _tokenURI)
    ERC721MetadataMintable()
    ERC721Metadata(_name, _symbol) public {
        uint256 _tokenId = 0;
        mintWithTokenURI(_creator, _tokenId, _tokenURI);
    }
}

and I want this Caller to be able to transfer the NFT to the person who is msg.sender. Caller behave like factory contract of FRC721 contract.

contract Caller {
    mapping(uint256 => address) public ERC721Address;
    using Address for address;
    bytes4 constant ERC721_RECEIVED = 0xf0b9e5ba;

    struct ERCs {
        address owner;
    }

    ERCs[] public ercs;

    function create(
        string _name,
        string _symbol,
        string _tokenURI
    ) public returns(bool) {
        ERCs memory _ercs = ERCs({
            owner: msg.sender
        });
        uint256 contractId = ercs.push(_ercs) -1; 
        ERC721Address[contractId] = new SampleToken(msg.sender, _name, _symbol, _tokenURI);
        return true;
    }

    function tokenTransferTo(
        address _to,
        uint256 _contractId,
        uint256 _tokenId,
        bytes _data
    ) public {
        require(msg.sender == ownerAddress(_contractId, _tokenId), "You do not have a right to mint token.");
        SampleToken(ERC721Address[_contractId]).setApprovalForAll(msg.sender, true);
        safeTransferFrom(msg.sender, _to, _contractId, _tokenId, _data);
    }

    function ownerAddress(uint256 _contractId, uint256 _tokenId) public view returns(address) {
        return SampleToken(ERC721Address[_contractId]).ownerOf(_tokenId);
    }

    function safeTransferFrom(
        address _from,
        address _to,
        uint256 _contractId,
        uint256 _tokenId,
        bytes _data
    ) public {
        SampleToken(ERC721Address[_contractId]).transferFrom(_from, _to, _tokenId);
        // solium-disable-next-line arg-overflow
        require(checkAndCallSafeTransfer(_from, _to, _tokenId, _data));
    }

    function checkAndCallSafeTransfer(
        address _from,
        address _to,
        uint256 _tokenId,
        bytes _data
    ) internal returns (bool) {
        if (!_to.isContract()) {
          return true;
        }
        bytes4 retval = ERC721Holder(_to).onERC721Received(address(this), _from, _tokenId, _data);
        return (retval == ERC721_RECEIVED);
    }
}

Every time I try to call tokenTransferTo after calling create() function I get the error message like below. Does anyone knows what's wrong with this?

transact to Caller.tokenTransferTo errored: VM error: revert.
revert  The transaction has been reverted to the initial state.
Note: The constructor should be payable if you send value.  Debug the transaction to get more information. 
1

I guess there are no current solutions for this situation besides implementing Dapps layer to directly call transferFrom(msg.sender, {Caller.contractAddress}, _tokenid) from ERC721 contract side. Since it's always revert when checking require(_isApprovedOrOwner(msg.sender, tokenId)); part.

https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC721/ERC721.sol

So you should do as follows:

  1. transfer token from msg.sender to caller contract address from ERC721 contract.
  2. transfer token from contract address to msg.sender with owner check of ERC721(address).ownerOf({contractAddress})
  • Another option is for the token owner to call setApprovalFor for the contract, ie ERC721Token.setApprovalForAll(Caller.contractAddress, true, { from: tokenOwner }). (This has to be done by the token owner not Caller contract) – Ismael Jan 17 at 7:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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