I've been struggling using web3j (the web 3 Java library, not JS) transferring ERC721 tokens from one user to another, using an operator. I get that we need to approve the operator from the user that owns the token by using setApprovalForAll or approve methods. I have a few queries.
I really am confused on how, where and when to use these approve functions.
Do I need to call them from my web3j app, or can this all be done in solidity?
I would like to use safeTransferFrom which uses the receiver interface. From there, I would like to get the id of the token that was just transferred and get its URI. I can use the _transfer() method, but safeTransferFrom creates an error when I try and execute my transfer functions.
Here's my solidity code so far (btw all done in Remix)
approveOperator.sol
pragma solidity ^0.8.0;
import 'https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol';
import 'https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Counters.sol'
import "./example.sol";
import "./ERC721Received.sol";
contract apop is Example, received{
using Counters for Counters.Counter;
Counters.Counter private tokIds;
string tokenName = "";
string tokenSymbol = "";
constructor() Example(tokenName, tokenSymbol) public {
}
function ap(address operator, address owner) public{
// setApprovalForAll(op, true);
IERC721(operator).setApprovalForAll(owner, true);
}
function mintToken(address _to, string memory _tokenURI) public returns (uint256) {
tokIds.increment()
uint256 newTokenId = toUint256(response);
// _mint(_to, newTokenId);
// safeMint(_to, newTokenId);
// setApprovalForAll(msg.sender, true);
safeMint(msg.sender, tokIds.current());
_setTokenURI(newTokenId, _tokenURI);
return newTokenId;
}
function tr(address from, address _to, uint256 tokenId, address opAddr) public payable{
// setApprovalForAll(_to, true);
// _transfer(ownerOf(tokenId), _to, tokenId);
IERC721(opAddr).transferFrom(from, _to, tokenId); // call operator's approve function from user's account
// safeTransferFrom(msg.sender, _to, tokenId);
}
}
Here's my operator contract
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/IERC721Receiver.sol";
// import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "./example.sol";
import "./ERC721Received.sol";
contract ExampleToken is Example, received {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
string tokenName = "";
string tokenSymbol = "";
uint256 tokenID1 = 0;
constructor() Example(tokenName, tokenSymbol) public {
}
function mintToken(address _to, string memory _tokenURI) public returns (uint256) {
tokIds.increment()
uint256 newTokenId = toUint256(response);
// _mint(_to, newTokenId);
// safeMint(_to, newTokenId);
// setApprovalForAll(msg.sender, true);
safeMint(msg.sender, tokIds.current());
_setTokenURI(newTokenId, _tokenURI);
contractAddress.call(abi.encodeWithSignature("incrementCounter()"));
return newTokenId;
}
function returnaddress() public view returns(address){
return address(this);
}
function ap(address op) public{
setApprovalForAll(op, true);
}
function tr(address from, address _to, uint256 tokenId) public payable {
// setApprovalForAll(_to, true);
// _transfer(ownerOf(tokenId), _to, tokenId);
safeTransferFrom(from, _to, tokenId);
}
}
Happy to provide any more info, and thanks for the help!