0

I’m experimenting with a presale contract based on the BSC testnet, and in the contract I’m attempting to achieve the purchase of my token with USDT.

Using my own code within the contract itself, I cannot get approval to go through properly for the contract to spend my USDT. However if I use the approve function within the “write contract” section of the USDT token on BSCSCAN, it does work - and I can buy tokens after approval went through.

Example of my approval code which does not work:

function approveUSDT() public {
            
IERC20 usdtToken = IERC20(0x337610d27c682E347C9cD60BD4b3b107C9d34dDd);
    
require(usdtToken.approve(address(this), tokenAmount), "Approval failed");
            
emit ApprovalSuccessful(msg.sender, tokenAmount);
    
}

What am I missing here?

3 Answers 3

1

If I understood correctly, you want the contract to withdraw usdt from your wallet and send you back tokens in exchange for that USDT.

If that's correct, then your doing it wrong.

You need to go to the USDT contract and approve your deployed contract to spend your USDT. On etherscan, you can put the USDT address in and navigate to contract and there's write functions that allow you to do this.

This would permit your deployed contract to withdraw USDT from your eg metamask wallet.

Your deployed contract itself, would have a function such as this (I code in vyper but solidity logic would be similar).

@external
def buy_tokens(amount: uint256): 
   ERC20(USDT).transferFrom(msg.sender,self,amount)
   token-amount: uint256 = some-logic-to-calculate-fx-between-usdt-and-your-token-fx-to-usdt
   ERC20(self).send(msg.sender,token-amount)
4
  • Thanks for responding! As I mentioned in my original post, I'm aware that I can approve the presale contract to spend my tokens via BSCSCAN/ETHSCAN, however this would not be practical for other users who wish to use my presale contract/dapp. Perhaps I didn't focus in on this, but I needed an approve function within my presale contract that can be actioned by users of the presale contract (without having to visit a blockchain explorer. My issue is that any approve snippets I use don't seem to work. Do you have any knowledge or suggestions here? :) Thanks again!
    – HAT0ken
    Commented Nov 10, 2023 at 13:43
  • You would need to do this in ethers.js in your dapp. Your dapp would need to check if the user has allowance on your contract and then pop up metamask so that they approve your contract to withdraw their tokens as a first step and as a second step to call the buy_tokens method. Check this ethereum.stackexchange.com/questions/112921/… (ignore my question, the code is correct, I was just executing on wrong network). Commented Nov 10, 2023 at 14:21
  • Thank you, that's somewhat helpful however isn't that JS stuff just for checking allowances? I need working smart contract code that handles the actual approval of token spending. So in my smart contract code there would first be approveUSDT function that the user can action, then actioning buyTokens from a separate function. Again, my issue is that the approve function I shared doesn't work properly
    – HAT0ken
    Commented Nov 10, 2023 at 14:42
  • A smart contract can not approve the token withdrawal on behalf of the user, this needs to be done by interfacing with the ERC20 token (in this case USDT) directly first (as suggested using the ethers.js code), replace allowance with approve in the sample js code and then calling your smart contract's deposit method. Unfortunately, this is the way it needs to be done. Good luck Commented Nov 10, 2023 at 15:06
1

USDT can be a weird token. It's better if you use the SafeERC20 library by openzeppelin. There's a function called safeIncreaseAllowance, which is basically approve, that solves some issues.

import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
using SafeERC20 for IERC20;


function approveUSDT() public {
    IERC20 usdtToken = IERC20(0x337610d27c682E347C9cD60BD4b3b107C9d34dDd);
    usdtToken.safeIncreaseAllowance(address(this), tokenAmount);
    emit ApprovalSuccessful(msg.sender, tokenAmount);
}
0

You are trying to call approve function of token contract in another contract("Pre Sale"). This wont work because it will try to approve Pre Sale contract for Pre Sale contract.You are trying:
Owner: Pre Sale contract
Spender: Pre Sale contract

So, you need to call approve function of token contract in token contract. You can do this on the frontend with ethers.js package or any other frontend package. This way:
Owner: user accounts
Spender: Pre Sale contract

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.