0

I'm trying to create a smart contract for raffling a NFT between users. Whenever an user tries create a raffle they need to specify the tokenContract which is the contract address of the NFT, and the tokenId which will be the corresponding id. I'm using a simple minting contract to simulate sending a token to the contract. However, when sending the raffle contract the minted token, and having onERC721Received set up, the State doesn't get changed to 1.

According to etherscan the raffle contract did successfully receive the ERC721 token.

Relevant part of raffle contract:

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

...

contract Raffle is VRFConsumerBase, IERC721Receiver {

    enum State {
        Pending,
        Active,
        Calculating,
        Finished
    }

    State public state;

    ...
    ...

    function onERC721Received(address, address, uint256, bytes calldata) external override returns (bytes4) {
        state = State.Active;
        
        return IERC721Receiver.onERC721Received.selector;
    }

Minting contract:

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
 
contract TestToken is ERC721URIStorage, Ownable {
     using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    constructor() ERC721("TestToken", "TST") {}
 
    function mintNFT(address recipient)
        public onlyOwner
        returns (uint256)
    {
        _tokenIds.increment();
 
        uint256 newItemId = _tokenIds.current();
        _mint(recipient, newItemId);
 
        return newItemId;
    }
}

1 Answer 1

0

Why don't you internalize the transfer process and use the standard ERC721 library?

function transferNFT(address _nft, uint256 _tokenId) public {
    // Check if sender approved contract to use _tokenId
    require(ERC721(_nft).getApproved(_tokenId) == address(this) ||
        isApprovedForAll(tx.origin, address(this)) == true,
        "Not approved to transfer NFT");
    // Check if sender is the owner of _tokenId
    require(ERC721(_nft).ownerOf(_tokenId) == tx.origin, "Not owner of token");

    // Process transaction
    ERC721(_nft).transferFrom(tx.origin, address(this), _tokenId);

    // Check that transaction was successful
    require(ERC721(_nft).ownerOf(_tokenId) == address(this), "Transfer failed");
}

You can utilize the standard ERC721 ownerOf function to verify that the transfer completed after calling the transfer function.

Your Answer

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

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