Hi, I have created a custom token and created a object of the token and trying to invoke some functions from the token but the Customer contract address is not getting approved and hence the contract is not able to transfer any tokens.
By default approving 10 ERC20 token but its not getting approved.
approveToeknAllowance does not actually approving any tokens.
getAllowanceOfCustomerContract returns always 0 for above 2 calls.
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^ 0.8.0;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol";
interface IERC20{
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function totalSupply() external view returns (uint256);
function decimals() view external returns (uint8);
function balanceOf(address account) external view returns (uint256);
function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
}
contract Customer is Ownable{
IERC20 musicToken;
constructor(){
musicToken=IERC20(CUSOTM_ERC20_TOKEN_ADDRESS);
musicToken.approve(address(this),10000000000000000000);
}
function getBalance(address addr) public view returns(uint256){
return musicToken.balanceOf(addr);
}
function transferTokens(address addr,uint256 tokenAmount) public {
tokenAmount=tokenAmount*10**musicToken.decimals();
musicToken.transferFrom(owner(),address(this),tokenAmount);
}
function increaseTokenAlloeance(uint tokenAmount) public returns(bool){
tokenAmount=tokenAmount*10**musicToken.decimals();
return musicToken.increaseAllowance(address(this),tokenAmount);
}
function getAllowanceOfCustomerContract() public view returns(uint256){
return musicToken.allowance(owner(),address(this));
}
function getTokenDecimals() public view returns(uint256){
return musicToken.decimals();
}
function approveToeknAllowance() public returns(bool){
return musicToken.approve(address(this),10000000000000000000);
}
}
I think you make mistake with approve and transferFrom, generally speaking, it should be
Bob approve a contract with a token, so the contract can transferFrom his token.
So the owner should call musicToken.approve(Customer_address,10000000000000000000); separately rather than in the Customer contract
What @Skyge is saying is that the contract cannot approve on behalf of a user. When you call musicToken.approve(address(this),10000000000000000000) in your constructor, you're saying "I (the customer contract) wants to approve myself (address(this)) to transfer 10000000000000000000 tokens.".
To clarify, if the goal is for your customer contract be able to call transferFrom on behalf of your customers, your customer need to call the approve function. For example, bob has 1000 music tokens. He needs to interact with the musicToken contract and call musicToken.approve(Customer contract address, 1000). Subsequently if you call transferTokens(), you need to do musicToken.transferFrom(bob's address, destination, 1000).
Also note that you shouldn't try and call increase allowance through an intermediary contract because msg.sender will be that contract's address i.e. if bob tries to increase allowance from the customer contract, msg.sender will be the customer contract address so it is the customer contract that is giving allowance to the spender (which in this case is most likely going to be address(this) aka itself).
Not to hijack this topic, but I am facing a similar issue and just need to clarify one part. I am trying to write a contract that accepts my ERC20 token, so in this example, I understood musicToken.approve(address(this),10000000000000000000) is saying "I owner wants to approve myself to use 10000000000000000000 tokens" but if the owner is calling the approve function then wouldn't owner would be msg.sender and address(this) be the contract address of which the function is being called?
Similarly, if the owner (bob) is calling the transferFrom function then wouldn't bob's address be msg.sender and destination be address(this) musicToken.transferFrom(bob's address, destination, 1000)
The owner needs to call the approve function outside of the contract. If he calls it through the contract, msg.sender is the contract address. Imagine this:
owner -> intermediary contract -> token contract.
What the token contract sees as msg.sender is not the owner's address (that's tx.origin) but instead the intermediary contract address. You can read more here.