Accepting USDT only for Smart contract

Currently, smart contracts are accepting ETH as the payment token.

Is it possible to only accept USDT for a smart contract instead? Are there simple examples for this?

Thank you.

1 Like

Yes, you can send USDT to your smart contract . If you want to withdraw from smart contract to your wallet , please set up USDT address on Ethereum inside constructor of your smart contract and get instance of ERC20 .

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.6;

import "./IERC20.sol" // import IERC20.sol from openzeppelin library
contract StoreContract {
IERC20 public usdt;
constructor (address _usdtAddress) {
usdt = IERC20(_usdtAddress);
}

receive() external payable{}
function deposit() external payable{

}

function withdraw() external{
usdt.transfer(msg.sender,amount);
}

}

3 Likes

Interesting!

I guess i'll go play around abit with that snippet.

Thank you so much!

1 Like

If I can just give an advice...

Payable keyword and fallback function is not needed if the contract only has to receive erc20 tokens. Leaving there the fallback can cause a lost of BNB

1 Like

Also, here is missing the third input: the amount

1 Like

Sorry, usdt.transfer(msg.sender,amount)

3 Likes

@ReactTop, @FreezyEx

I am facing a problem with exceeding allowance. I believe i have to increase said allowance somewhere within my contract, is that right?

Lets say

    /**
     * @dev Determines how usdt is stored/forwarded on purchases.
     */
    function _forwardFunds(address recipient, uint256 amount) internal {
        //reset allowance to 0
        usdt.safeApprove(_token, _msgSender(), 0);

        //increase allowance to transfer amount
        usdt.safeIncreaseAllowance(_token, _msgSender(), amount);
        
        //transfer usdt from msg sender to recipient
        usdt.transferFrom(_msgSender(), recipient, amount);

        //remove allowance of transfer amount
        usdt.safeDecreaseAllowance(_token, recipient, amount);
    }

is this how it works?

Or should i Deposit USDT into the contract, then using the contract to transfer USDT to recipient?

Yes mate, it is possible. You can. Simply accept an instance of type USDT contract you wish to accept or rather accept an address type and wrap it in IERC20 instance then use it in the required function. You might also need to inform your user that you are not accepting ETH, or better still make the function non-payable and reject any unsolicited ETH in the fallback but be mindful that your contract can still accept ETHER if another contract sets your contract address as the beneficiary in a selfdestruct action in their contract. But do not worry much if receiving ether would not cause a devastating effect on your contract.

//Pragma solidity ^0.7.0;
interface IERC20 {
    //Some interface non-implemented functions here
}
contract AcceptUSDTOnly {
     IERC20 accepted;
     
     constructor (IERC20 instanceAddress) {
          accepted = instanceAddress;
     }

     receive() external payable {
          //not accepting unsolicited ether
          revert("Reason")
     }

     function buySomeStuff() public {
         //use IERC20 instance to perform the exchange here
     }

}
1 Like

If you're calling usdt.safeApprove for instance, the msg.sender would be your contract and not your user because you're making an external call. So in this, case, you have no usdt balance in the usdt contract you're calling hence fails.

1 Like

I see,
The thing im doing is trying to modify the Crowdsale Contract to only accept USDT.

So in this case i should be depositing the USDT into the Crowdsale Contract first, then from Crowdsale Contract to transfer to the actual wallet address?

You have to think it twice. Assume I am the buyer and I need to buy from your contract using usdt . You need to have a way of extracting the usdt from me which will as well alert your contract that I have sent some amount. You might want to consider a manual method where you verify manually that I have paid some usdt and then send me some token if you can't find a way to automate the process or you just gotta make some external calls to the usdt contract.

1 Like

Hmm, I see.
I will go and experiment more. Thank you!

1 Like

I have been trying a few methods,
I think this should have been the best method as it transfers from Buyer to Funds Wallet

Method 1

/**
     * @dev Determines how usdt is stored/forwarded on purchases.
     */
    function _forwardFunds(uint256 amount) internal {

        usdt.increaseAllowance(address(this), amount);

        usdt.transferFrom(_msgSender(), _wallet, amount);

        usdt.decreaseAllowance(address(this), amount);
    }

But i always face with this error "ERC20: transfer amount exceeds allowance".

I have also tried
Method 2

/**
     * @dev Determines how usdt is stored/forwarded on purchases.
     */
    function _forwardFunds(uint256 amount) internal {
        usdt.approve(address(this), 0);
        usdt.increaseAllowance(address(this), amount);

        usdt.transfer(address(this), amount);
        usdt.transferFrom(address(this), recipient, amount);

        usdt.decreaseAllowance(address(this), amount);
    }

This method works IF i transfer some USDT in advance into the Crowdsale.
And that is because im transferring from Crowdsale > Wallet, Buyer > Crowdsale.
I believe only after the function has ended, then the buyer's USDT is transferred to the Crowdsale right?

  1. Do i have to seperate the approve function and purchase function before it works?
    I just want it to be as streamlined for my buyers.

EDIT : I tried splitting Approve function by itself before making a purchase. It still have the same exceed allowance error.
EDIT 2 : I found out if i wish to do approve and transferFrom all within one tx, i need the token to have a ApproveAndCall function. Which i cannot confirm USDT has, so i believe method 1 is not possible anymore. I shall move forward with separating everything.

  1. Worst comes to worst would be the Crowdsale holding all the USDT, then when Crowdsale ends, the owner withdraws the USDT at once. This way i wont need to call approve functions right?

Well, I found out firstly,
The Front End has to call the function to Approve the allowance for the contract to use.

This is probably not what we were looking for, so I guess we'll go back to use the Native Token instead.

Thanks everybody for the help!

For others who are looking for how this could or should be done.

Use frontend to approve Smart Contract allowance, then just use transferFrom within the Smart Contract as per normal.
I tried using Truffle and Hardhat but I have no idea how to call approve.

So just having a member IERC20 accepted; makes my contract able to get usdt? just using the fallback function?