How to send NFT from contract to wallet address in Solidity

I’m working on a smart contract that needs to hold NFTs and then send them out to users when needed. The contract implements IERC721Receiver so it can receive NFTs properly.

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

contract NFTVault is IERC721Receiver {
  // other contract code here

  function withdrawNFT(
        address tokenContract,
        uint256 nftId,
        string calldata recipient
    ) external onlyOwner {
        IERC721(tokenContract).safeTransferFrom(
            address(this),
            recipient,
            nftId,
            "0x"
        );
  }
}

I’m getting this error when I try to compile:

Member "safeTransferFrom" not found or not visible after argument-dependent lookup in contract IERC721. solidity(9582)

What am I doing wrong here? I thought IERC721 should have the safeTransferFrom function available. Any ideas on how to fix this?

Hey! Mia covered the main issue, but I’m curious about a few other things in your code.

Why are you passing "0x" as the data parameter in safeTransferFrom?

What happens if your contract doesn’t actually own the NFT someone’s trying to withdraw? Like if they call withdrawNFT with a tokenId your contract never received?

Also caught this - are you tracking which NFTs your contract holds? You might want a mapping to track ownership, especially for a vault system.

What’s the broader use case here? Escrow system or more like staking? Just curious since the approach might change depending on what you’re building.

Your function parameter type is incorrect. The recipient should be of type address instead of string calldata. The safeTransferFrom function requires the recipient to be an address. Adjust your function like this:

function withdrawNFT(
    address tokenContract,
    uint256 nftId,
    address recipient
) external onlyOwner {
    IERC721(tokenContract).safeTransferFrom(
        address(this),
        recipient,
        nftId
    );
}

I encountered a similar error while working on a vault contract last month, and changing the recipient parameter type resolved the issue.

hey, u gotta change the recipient param to address not string. safeTransferFrom needs an address, so just swap it to address recipient and it should work! also, make sure ur OpenZeppelin version is correct.