1

below is my contract for a simple dex that I am trying to debug. I am getting error of "Insufficient allowance" in remix IDE even after approving allowance for the token

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

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract Dex {

mapping(address => mapping(address => uint256)) public balances;

uint256 public tokenPrice = 100;

mapping(address => mapping(address => mapping(address => uint256))) private _allowances;

function allowance(address token, address owner, address spender) external view returns (uint256) {
    return _allowances[token][owner][spender];
}

function approve(address token, address spender, uint256 amount) external returns (bool) {
    _allowances[token][msg.sender][spender] = amount;
    return true;
}

function buyToken(address _token, uint256 amount) public payable {
    IERC20 token = IERC20(_token);
    require(token.balanceOf(address(this)) >= amount, "Not enough balance in exchange");

    uint256 ethAmount = amount * tokenPrice;
    require(msg.value >= ethAmount, "Send more ETH to purchase tokens");

    token.transfer(msg.sender, amount);
}

function sellToken(address _token, uint256 amount) public {
    IERC20 token = IERC20(_token);
    require(token.balanceOf(msg.sender) >= amount, "You don't have enough balance");

    uint256 ethAmount = amount * tokenPrice;
    require(address(this).balance >= ethAmount, "Not enough balance in exchange for tokens");
    require(_allowances[_token][msg.sender][address(this)] >= amount, "Not enough allowance");

    token.transferFrom(msg.sender, address(this), amount);
    payable(msg.sender).transfer(ethAmount);
}

function depositToken(address _token, uint256 amount) public {
    IERC20 token = IERC20(_token);
    require(token.balanceOf(msg.sender) >= amount, "You don't have enough balance");
    require(_allowances[_token][msg.sender][address(this)] >= amount, "Not enough allowance");

    token.transferFrom(msg.sender, address(this), amount);
    balances[msg.sender][_token] += amount;
}

function withdrawToken(address _token, uint256 amount) public {
    IERC20 token = IERC20(_token);
    require(balances[msg.sender][_token] >= amount, "You are withdrawing more than you deposited");

    token.transfer(msg.sender, amount);
    balances[msg.sender][_token] -= amount;
}

function depositEth() public payable {
    require(msg.value > 0, "You need to deposit some ETH");
    balances[msg.sender][address(0)] += msg.value;
}

function withdrawEth(uint256 amount) public {
    require(balances[msg.sender][address(0)] >= amount, "You haven't deposited enough ETH");

    payable(msg.sender).transfer(amount);
    balances[msg.sender][address(0)] -= amount;
}

}

1
  • When I call depositToken function this error is displayed
    – user122302
    Jun 11, 2023 at 16:35

2 Answers 2

3

First of all please point out the function which is throwing this error.

The most common reason for this problem is because of the msg.sender. What happens is, you allow a wallet address to spend your tokens, but when the allowed address tries to call the transfer function via another smart contract, the contract itself becomes the msg.sender, which means the contract needs to be allowed to spend the tokens.

I am not sure if this is the reason, I am only assuming unless you point out the function causing an error.

EDIT - The solution to this.

Approve the dex contract from the ERC20 token contract externally, keep in mind the address from which the dex will transfer the tokens needs to approve the dex. And this can't be done from within the contract.

4
  • When I call depositToken function this error is displayed
    – user122302
    Jun 11, 2023 at 16:36
  • The problem is the same as I told you, you have to allow the contract in the token contract so that this dex contract can transfer the tokens. Jun 12, 2023 at 3:34
  • Please suggest me how I can do it as I am a newbie and as you said I want to allow smart contract to spend tokens on behalf of the wallet
    – user122302
    Jun 12, 2023 at 4:24
  • I have added the on the answer itself, let me know if that helps you otherwise I can hop on a call to make it more clear. Jun 12, 2023 at 15:12
1

Having approval functionality in a non ERC20 contract does not make much sense. You should give allowance for the token from your dapp, calling approve() on the token contract, before calling depositToken() on your contract.

Then you can remove _allowances and all related line, as that will be checked on token.transferFrom()

3
  • Can you suggest me how to do it as I am a newbie in smart contract development. I mean how I can call approve() on token contract from my contract
    – user122302
    Jun 12, 2023 at 4:06
  • I tried approving the smart contract to spend tokens on behalf of the wallet using this function setAllowance(address _token,uint256 amount) public { IERC20 token = IERC20(_token); token.approve(address(this),amount); } But it then also doesn't work as error continues
    – user122302
    Jun 12, 2023 at 4:30
  • The thing is that any given address can only approve the spending of its own tokens. If the contract calls approve() on the token contract, it can only give approval for its own balance, not yours. Instead, you need to call approve from your wallet address for the token address. This is usually done from the dapp (web3.js, ethers...), just before you call the contract to spend them.
    – ceseshi
    Jun 12, 2023 at 14:39

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.