Swap ERC20 tokens from ERC721

Hello to all of you. We are struggling with this:

He have deploy an ERC20 token. Everything works perfectly. Now we want holders to spend ERC20 tokens to mint an ERC721 . So far so good

On mint function we want some percent to send to charity wallet as ETH or BNB. We implement the Uniswap Factory ( or Pancake for BSC) and we try to call the swaptokens for ETH but we get SafeMath: subtraction overflow Our ERC721 has the receive function and we gave allowance to the contract to spend the tokens. Also try allowance with the user.

Any help??

Hi, welcome! :wave:

If possible, please share your contract code at here.

Hi and thanks for the reply.

This is the debug error

The contracts is in BSC test net

Ohhhh, this tool is really very good. And it seems like when you want to swap token, it will call transferFrom, so you need to have a check whether the caller has enough approval amount.

We check before the swap. I think it has to do with the transferFrom on ERC721.

@dev See {IERC721-transferFrom}.

function transferFrom(address from, address to, uint256 tokenId) public virtual override {
    //solhint-disable-next-line max-line-length
    require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");

    _transfer(from, to, tokenId);
}

We call this function before the swap

    token.approve(address(uniswapV2Router), tokenAmount);

    // make the swap
    uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens(
        tokenAmount,
        0, // accept any amount of ETH
        path,
        devWallet,
        block.timestamp
    );

We are calling this function in ERC721 contract and it has its own transferFrom but with token id.

Do we need to overide the transferFrom and call transferFrom on ERC20 ?
Does the router call back the msg.sender () ? <-- sender is ERC721

This is the function on PancakeRouter

function safeTransferFrom(
        address token,
        address from,
        address to,
        uint256 value
    ) internal {
        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
        require(
            success && (data.length == 0 || abi.decode(data, (bool))),
            'TransferHelper::transferFrom: transferFrom failed'
        );
    }
    function safeTransferETH(address to, uint256 value) internal {
        (bool success, ) = to.call{value: value}(new bytes(0));
        require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');
    }
}

We found the solution

It was on approval as @Skyge mention

    Atoken.approve(address(this), tokenAmount);
    Atoken.approve(address(uniswapV2Router), tokenAmount);
    Atoken.approve(ATokenAddr, tokenAmount);
    Atoken.increaseAllowance(address(uniswapV2Router), tokenAmount);
1 Like