Sale contract ERC20 to accept USDT

Hi,
I want to create smart contract which will sell ERC20 token for USDT. As I already saw in few topics, I need to use approve -> transferFrom mechanism, but cannot get this code to work. Also, don't know what is proper way to simulate all this on testnet, so I deployed copy of usdt on mumbai network and set its address in this contract.

Here is my contract code:

pragma solidity >=0.8.0;

import 'openzeppelin-solidity/contracts/token/ERC20/IERC20.sol';
import 'openzeppelin-solidity/contracts/token/ERC20/utils/SafeERC20.sol';
import 'openzeppelin-solidity/contracts/access/Ownable.sol';
import 'openzeppelin-solidity/contracts/utils/math/SafeMath.sol';


contract TokenSale is Ownable{
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    constructor(){}
    address public _usdt;
    address public _token;
    address public _marketing;
    address public _dev;
    uint256 private _rate = 1;

    function buyToken(address to, uint256 usdtAmount) external {
        uint256 tokenAmount = usdtAmount.mul(_rate);
        require(to == _marketing || to == _dev, "Address you want to fund is not valid");
        IERC20(_usdt).transferFrom(msg.sender, address(this), usdtAmount);
        IERC20(_perun).safeTransfer(msg.sender, tokenAmount);
    } 

    function setUsdt(address adr) public onlyOwner {
        _usdt = adr;
    }

    function setToken(address adr) public onlyOwner{
        _token= adr;
    }

    function setMar(address adr) public onlyOwner{
        _marketing = adr;
    }

    function setDev(address adr) public onlyOwner{
        _dev = adr;
    } 


}

What is exactly the error you are receiving? Do you have an error message? A transaction is? You’re not providing a lot of information to go on. The code you provided won’t even compile as your using variables that don’t even exist. So this isn’t even the real code.

As USDT doesn’t adhere to the ERC20 standard make sure to use the safeerc functions. You included it in your code and use it for the other token, but not for USDT

Hi,
thanks for reply and sorry for lack the of information.
So, I want to sell/swap ERC20 token from developer address for Usdt using this contract. While testing I manually approved contract address to use token and usdt, and contract will check if allowance is ok before transferring. I replicated usdt on testnet from this address:

0xdAC17F958D2ee523a2206206994597C13D831ec7

Just edited code a little bit, and still get the same error. I am using Remix and this is the error I get:

Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending? Returned error: {"jsonrpc":"2.0","error":"Internal JSON-RPC error.","id":4653967356771000}

I used Tenderly to trace where it breaks, and every time it is at transferFrom function, either it is usdt contract or ERC20 contract (Created by OpenZeppelin Wizard).

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/access/Ownable.sol";


contract TokenSale is Ownable {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    address public token;
    address public usdt;
    address public development;
    uint256 private rate = 1;

    constructor (address _tokenAddress, address _usdtAddress, address _developmentAddress){
        token = _tokenAddress;
        usdt = _usdtAddress;
        development = _developmentAddress;
    }

    mapping (address => mapping (address => uint256)) userTokenBalance;
    mapping (address => mapping (address => uint256)) userUsdtSpent;

    event usdtDepositComplete(address token, uint256 amount);
    event tokenSaleComplete(address token, uint256 amount);

    function buyToken(uint256 amount) public {
        require(IERC20(usdt).balanceOf(msg.sender) >= amount, "Usdt amount must be greater than deposit.");
        uint256 tokenAmount = amount.mul(rate).mul(1000000000000); //usdt have 6 and this token have 18 decimal places
        // require(IERC20(usdt).approve(address(this), amount));
        require(IERC20(usdt).allowance(msg.sender, address(this)) >= amount);
        require(IERC20(usdt).transferFrom(msg.sender, development, amount));
        userUsdtSpent[msg.sender][usdt] += amount;
        emit usdtDepositComplete(usdt, amount);
        // require(IERC20(token).approve(address(this), amount));
        require(IERC20(token).allowance(development, address(this)) >= tokenAmount);
        require(IERC20(token).transferFrom(development, msg.sender, tokenAmount));
        userTokenBalance[msg.sender][token] += tokenAmount;
        emit tokenSaleComplete(token, amount);
    }
}

Error was that I didn't use safeTranferFrom function, and also didn't know that id does not return bool like transferFrom function.

Also, what I was wrong is to try calling approve from contract and doing transfer after that, which just cannot work like that. So I will use JS with web3 so user can first approve contract to use their usdt tokens.

This version of code finally works.

pragma solidity ^0.8.9;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/access/Ownable.sol";


contract TokenSale is Ownable {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    address public token;
    address public usdt;
    address public development;
    uint256 private rate = 1;

    constructor (address _tokenAddress, address _usdtAddress, address _developmentAddress){
        token = _tokenAddress;
        usdt = _usdtAddress;
        development = _developmentAddress;
    }

    mapping (address => mapping (address => uint256)) userTokenBalance;
    mapping (address => mapping (address => uint256)) userUsdtSpent;

    event usdtDepositComplete(address token, uint256 amount);
    event tokenSaleComplete(address token, uint256 amount);

    function buyToken(uint256 amount) public {
        require(IERC20(usdt).balanceOf(msg.sender) >= amount, "Usdt amount must be greater than deposit.");
        uint256 tokenAmount = amount.mul(rate).mul(1000000000000); //usdt have 6 and this token have 18 decimal places
        require(IERC20(usdt).allowance(msg.sender, address(this)) >= amount);
        IERC20(usdt).safeTransferFrom(msg.sender, development, amount);
        userUsdtSpent[msg.sender][usdt] += amount;
        emit usdtDepositComplete(usdt, amount);
        require(IERC20(token).allowance(development, address(this)) >= tokenAmount);
        IERC20(token).safeTransferFrom(development, msg.sender, tokenAmount);
        userTokenBalance[msg.sender][token] += tokenAmount;
        emit tokenSaleComplete(token, amount);
    }

}