OnERC721Received and Unstaking

Hi,
I have a question about staking and unstaking.
I have a ERC721 Contract where the user can mint and stake token in the same contract. So when the contract receives the token the onERC721Received function is called as it should. So everything is working fine so far. I write the original Owner and the tokenId into a mapping so I can retreive it later on.
Now comes the tricky part. When the user wants to unstake the token he or she staked earlier he/she is the caller of the safeTranferFrom function but not the owner. Rightfully the tx reverts. But how would I send the token from the contract back to the original Owner (retreived from my mapping). The owner of the token at that moment is the contract. So the caller is the user who is not the owner of the token so I would have to approve this transfer first. Where would I do that? How can I handle this? I thought about approving the transfer in the onERC721Received Function like so:


 function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external virtual returns (bytes4)


    {
      

       require(msg.sender == address(this),"address must be contract");
       approve(from, tokenId);
       return _ERC721_RECEIVED;

    }

Does this makes sense or is this a problem?

Any help would be appreciated.

UPDATE:
Here is the staking and unstaking function:

Staking:

  function stake(uint256 tokenId) external payable {
        require(msg.value >= stakingFee,"ether send is under staking price. ");
        require(canStake,"You can't stake at the moment. Try again later.");

        address gladiatorOwner = ownerOf(tokenId);

        require(gladiatorOwner == msg.sender ||msg.sender == owner(),
        "user ist not the owner of the token.");
        mapAccountToCompetingTokens[gladiatorOwner].add(tokenId);
        emit Staked(tokenId,gladiatorOwner);

// Sending the token from the owner to the contract
        safeTransferFrom(gladiatorOwner,address(this), tokenId);

     
    }

Unstaking:


   function unstake(uint256 tokenId) external {
       bool tokenBelongsToSender = false;
        uint senderOwned = mapAccountToCompetingTokens[msg.sender].length();
    
        for (uint i = 0; i<senderOwned;i++){
            if(tokenId == mapAccountToCompetingTokens[msg.sender].at(i)){
            tokenBelongsToSender = true;
            break;
            }
        }
        require(tokenBelongsToSender,"Token wasn't staked by you. Please choose another token");
        transferFrom(address(this),msg.sender,tokenId);
    
    }

You might get better help if you post the actual code that is currently causing the problem.

1 Like

can you share your unstake function? Better if you can share the whole code

1 Like

Thanks. I Updated my questio nand added the staking and unstaking function. It works as of now but the approve in the onERC721Received is what throws me off. I would like to know what the beste practice would be.

Thanks. I Updated my questio nand added the staking and unstaking function. It works as of now but the approve in the onERC721Received is what throws me off. I would like to know what the best practice for implementing unstaking would be.

For one, you may as well change this:

transferFrom(address(this), msg.sender, tokenId);

To this:

transfer(msg.sender, tokenId);

Then you don't even need the approve part (wherever you're doing it).

1 Like

Thanks for your answer.
I do the approve part in the "onERC721Received" function. It's added to my question.
When I'm trying to use justr "transfer(msg.sender, tokenId);" remix doesn't like it.

Is there anything i need to import for that? I can't find the function in the ERC721 Standrd from openzeppeling either.

Well, I was thinking of ERC20.
It might be working a little differently in ERC721.
You can view that contract's source code and find out for sure.

Oh yeah it hink using erc20 as a staking contract would be my other choice. Maybe I can get it to work with erc721. I would like using only one contract better.
Thanks for your help anyway