2

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!

2 Answers 2

0
public  boolean mintNFTByAmountAndAddress(Web3j web3j, Credentials credentials, String contractAddress, int amount) {
        if (web3j == null) return false;
        if (credentials == null) return false;
        String methodName = "mint";
        String fromAddr = emptyAddress;
        Function function = new Function(
                methodName,
                Arrays.asList(new Address(credentials.getAddress()), new Uint256(amount)),
                Arrays.asList(new TypeReference<Type>() {
                }));

    String data = FunctionEncoder.encode(function);
    Transaction transaction = Transaction.createEthCallTransaction(fromAddr, contractAddress, data);

    EthCall ethCall;
    try {
        ethCall = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).sendAsync().get();
        //List<Type> results = FunctionReturnDecoder.decode(ethCall.getValue(), function.getOutputParameters());
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }
    return true;
}
0

If you transfer() your own tokens from the account that owns them, you don't need to call approve(). If you want to transferFrom() tokens you don't own as a spender, then the owner needs to approve() you to spend the tokens beforehand.

Approving and transferring tokens is split into these two separate transactions for security reasons.

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.