0

I am developing an ERC721. I want the NFT to be approved and to do transactions. When I call getApproved() the address is the Smart Contracts address, but when I try to do a transaction by calling the safeTransferFrom() method, it doesnt work. I think thats probably because a Contract address is no EOA and you cant pay gas fees for a Smart Contract. But arent transactions on Exchanges also administrated by Smart Contracts, how does that work? Do I need to create a second Smart Contract?

Greetings Luca

1 Answer 1

1

If i understand your question, you want to send a ERC721 transaction from contract to another contract address and you use approve() and safeTransferFrom() methods on the sender contract. So you need to implement in the receiver contract, the onERC721Received() method. look at this example

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";


contract Sender is ERC721 {
    
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIdCounter;
    
    address public receiver;

    constructor(  ) ERC721("shx", "shx") {
    }
    
    
    function createNFT(address _receiver) public returns (uint) {
        require(_receiver != address(0), "Shx: zero address");
        receiver = _receiver;
        _tokenIdCounter.increment();
        uint256 tokenId = _tokenIdCounter.current();
        _mint(msg.sender, tokenId);
        approve(receiver, tokenId);
        // or you could use:  setApprovalForAll(b, true)
        // setApprovalForAll(b, true);
        return tokenId;
    }
    
     function createNFT2(address _receiver) public returns (uint) {
        receiver = _receiver;
        _tokenIdCounter.increment();
        uint256 tokenId = _tokenIdCounter.current();
        _mint(msg.sender, tokenId);
        setApprovalForAll(receiver, true);
        return tokenId;
    }
    
    function sendTokenToSC(uint256 tokenId) public returns(bool){
        safeTransferFrom(msg.sender, receiver, tokenId);
        return true;
    }

}

contract Receiver is  IERC721Receiver{
    address public contractSenderAddress;

     function first( address _nft) public {
         contractSenderAddress = _nft;
         
     }
     
     function ownerOf(uint256 tokenId ) public view returns(address) {
          return IERC721(contractSenderAddress).ownerOf( tokenId);
          
     } 
  
    
    function onERC721Received(address , address , uint256 , bytes memory) external pure override returns (bytes4){
        return bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));
    }
    
    
}
6
  • I know my I didnt formulate my question quite good :D . What I just dont understand is, when User 1 approves SC 1 for for token 1. Now the SC initiates the transaction safeTransferFrom(User 1, User 2, token 1).send(from: SC1). This doesnt work for me and Im asking should that even work, and when yes, how. Another question which just came up, when I set ApprovalForAll for an address2, will the address2 be capable of transferring tokens, which address1 doesnt have yet, for example tokens address1 will get later? Im looking forward to an answer :)
    – Luex
    Sep 13, 2021 at 9:15
  • If the receiver is a wallet address you should use transferFrom(), If the receiver is a contract, you need to use safeTransferFrom() read it from here : docs.openzeppelin.com/contracts/2.x/api/token/… . setting ApprovalForAll for an address2 means all tokens will be allowed to be transferred even if those tokens do not exist yet, check it by using isApprovedForAll(address owner, address operator). then use the transferFrom() method.
    – anwar
    Sep 13, 2021 at 17:04
  • Thank you so much, this really helped alot. Last question: Can I approve a Smart Contract? And if yes, who pays for the transaction when sending the token from the Smart Contract
    – Luex
    Sep 13, 2021 at 17:35
  • Yes you can, check the example on the top and you can use similar to sendTokenToSC() method but if you want to implement it in the receiver contract, you need to use something like IERC721(contractSenderAddress).safeTransferFrom(msg.sender, address(this), tokenId) this will allow the owner to send the token. For your question, after a token gets approved, only the owner or approved address can transfer the token. You could include cryptographic primitives onto your methods, check the lazy mint methods and how it works
    – anwar
    Sep 13, 2021 at 17:56
  • check this eip712 standard eips.ethereum.org/EIPS/eip-712 and docs.openzeppelin.com/contracts/2.x/utilities
    – anwar
    Sep 13, 2021 at 18:09

Your Answer

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

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