1

I'm kind of new to Solidity and struggling with allowances and approvals. I want my smart contract to be allowed to take ERC20 tokens (LINK in this case) from the msg.sender. I'm using Remix on Goerli, so the msg.sender would be the MetaMask wallet address. I've tried to research about this, but I'm guess that I'm the functions on the ERC20 token, not just in my smart contract.

Whenever setting approveAmount I sign the contract in MetaMask for msg.sender.

Sample.sol:

//SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.0;

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

contract SampleContract {
    IERC20 public LinkToken;
    address public LinkAddress = 0x326C977E6efc84E512bB9C30f76E30c160eD06FB;  

    constructor() {
        LinkToken = IERC20(LinkAddress); 
    }

    // MetaMask address approves that address(this) can take 123 LINK
    function approveAmount() public { 
        LinkToken.approve(address(this), 123);
    }

    // Contract will check how much LINK MetaMask address has allowed for transfer
    function getAllowance() public view returns(uint256) {
        return LinkToken.allowance(address(this), msg.sender);
    }
}

4 Answers 4

1

When a user calls your contract's approveAmount() method, your contract calls approve(...) in a LinkToken contract, in the context of a LinkToken msg.sender is your contract address rather than the user address. It is therefore impossible to accomplish your goals in that manner.

Also, 0x326C977E6efc84E512bB9C30f76E30c160eD06FB is ERC677, it has additional function called transferAndCall(address _to, uint _value, bytes _data). Consider using it as a potential alternative for you. Read more about the ERC677 here

Or you can do the same thing that every web3 usually does is send a transaction to LinkToken for approval before doing anything further. Of course this will make the user confirm at least 2 times in the metamark

0

First correct the getAllowance() function with this:

function getAllowance() public view returns(uint256) {
        return LinkToken.allowance(msg.sender, address(this));  //since we had approved 123 tokens of msg.sender to be spend by address(this).
    }

function approveAmount() should be called by LinkToken owner, or the address must have atleast 123 LinkToken balance to approve it. than simply write a function:-

function transferApprovedTokens(address receiver) public {
        LinkToken.transferFrom(msg.sender, receiver, 123);  //here msg.sender is your wallet address which has balance of LinkToken and internally in LinkToken contract msg.sender is address(this) which we had approved for tansfer.
     }

When I was playing with ERC-20 contracts I too faced this confusion.

0

This has nothing to do with Solidity but ERC20.

The sender (not your contract) has to send an approve transaction to the LINK token contract, to approve who can steal his money. You want him to approve your contract to steal his money.

When your contract calls LinkToken.approve that approves who can take your contract's money. Since your parameters are (address(this), 123) you're approving the contract to take 123 from itself. Not very useful. To approve who can take the sender's money, the sender needs to send the transaction. You can't just give yourself permission to steal his money! He needs to give the permission!

This is why so many "web3 dapps" require the user to make two transactions to do anything. The first tells the token contract that the dapp's contract can take the user's money. The second one tells the dapp's contract to take the money. There is no way to do these two things in one transaction.

2
  • But isn't the LinkToken.approve(address(this), 123); call doing this first transaction, it calls .approve on the LinkToken (IERC20(LinkAddress)? I'm solely trying to get the approval right in this contract, which doesn't seem to update with the current piece of code.
    – TRS
    Dec 14, 2022 at 10:31
  • @TRS The caller of approve is your contract, so your contract is approving itself to take 123 tokens from it. You can only give permission for someone to take your money. You can't give permission for someone to take someone else's money. The contract is making the call, so the contract can only give permission for someone to take its money.
    – user253751
    Dec 14, 2022 at 10:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.