0

I'm encountering an issue with my Solidity smart contract where the allowance values for token transfers are not changing even after I've approved them. Here's the scenario:

When I call the approveForTransferTokensForId function in my contract, I'm logging the allowance values using console.log, and all of them are showing 0. Here's the log output:

First Function call is made. msg.sender 0x406AB5033423Dcb6391Ac9eEEad73294FA82Cfbc myOwner 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db owner() 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db address(this) 0xa9d281dA3B02DF2ffc8A1955c45d801B5726661D Token is formed. 0 First approve is made. 0 Second approve is made. 0 Third approve is made. 0 Fourth approve is made. 0 Fifth approve is made. 0 Sixth approve is made.

function approveForTransferTokensForId(uint256 userId, address _tokenAddress, uint256 amount, address receiver) external onlyMainContract payable {
    // Implement token transfer logic here
    // Example: Transfer 'amount' tokens from the owner of TokenOwnerContract to 'receiver'

    // Log messages and token allowance checks
    console.log("First Function call is made.");
    console.log("msg.sender", msg.sender);
    console.log("myOwner", myOwner);
    console.log("owner()", owner());
    console.log("address(this)", address(this));
    token = IERC20Metadata(_tokenAddress);
    console.log("Token is formed.");

    // Approve token transfers
    bool _success = IERC20(token).approve(address(this), amount);
    if (_success) {
        console.log(IERC20(token).allowance(msg.sender, address(this)));
    } else {
        revert("failed to approve First approve ");
    }

    // Other approvals follow...

}

I'm confused as to why the allowance values remain at 0 even after successful approval. Is there something I'm missing or misunderstanding about how token approvals work in Solidity?

Any insights or suggestions would be greatly appreciated. Thank you!

1
  • Thanks for pointing out this,. I do not know where IRCMEtadata came from :) IT was a mistake. Anyway, I changed the code as below (I also tried without castings in approvals) still getting allowences as 0. token = IERC20(_tokenAddress); console.log("Token is formed."); bool _success = IERC20(token).approve(address(this), amount);//mevcut smart contract if (_success) { console.log(IERC20(token).allowance(msg.sender, address(receiver))); } else { revert("failed to approve First approve "); } Apr 9 at 12:20

2 Answers 2

0

You make this call in your contract

IERC20(token).approve(address(this), amount);

Will increase this allowance: allowance(your_contract_address,your_contract_address)

While you expect increasing allowance between the msg.sender and your contract_address.


Explain:

  • I assume your smart contract name is: #A
  • When you call token.approve(address(this), amount) in #A
  • It will call to token smart contract with msg.sender == #A
  • So it will increase allowance(#A, #A), you can read here
  • As your expectation, you must call it external, not inside your #A
2
  • As you can see I tried different addresses, I will delete some of the calls do not worry. I am aware of that. I just need to see raised allowence. Apr 9 at 11:16
  • You are comparing different things. IERC20(token).approve(address(this), amount); <> IERC20(token).allowance(msg.sender, address(this))
    – CT95
    Apr 10 at 1:43
0

First of all, make sure that you’re creating the token instance using the correct ERC20 interface for token operations.

Seems like IERC20Metadata is only for metadata, so the correct way of creating the instance would be:

token = IERC20(_tokenAddress); 

Also, it seems there might be an issue with how you’re calling the approve() function.

In the code you provided, you’re calling:

IERC20(token).approve(address(this), amount);

Instead, you should call:

token.approve(address(this), amount);

By calling token.approve(), it's invoking the approve() function on the actual token contract instance on behalf of the contract in which it's being called. This action sets the allowance value for your contract, provided that the owner who has approved that allowance is the contract itself. So, the effective allowance can be checked using:

console.log(token.allowance(address(this), address(this)));

Here’s the corrected code snippet:

token = IERC20(_tokenAddress);
console.log("Token is formed.");
// Approve token transfers
bool _success = token.approve(address(this), amount);
if (_success) {
    console.log(token.allowance(address(this), address(this)));
} else {
    revert("failed to approve First approve ");
}

However, ideally, granting approval to the contract to spend tokens on its own behalf is meaningless. This is because such token approvals should not be handled in this manner in the context of a typical dApp.

Instead, the approval process should involve direct action by the user, who calls the approve() function of the ERC20 token contract using their wallet. Through this process, the user grants permission for a specific amount of tokens ('n') to be spent by the contract on their behalf.

However, achieving this desired behaviour isn't possible when invoking the approve() function from within the contract itself, which is intended to spend a specific amount ('n') of ERC20 tokens on behalf of the user. This is because calling the function from within the contract would entail granting approval for the 'n' amount of tokens owned by the contract, on behalf of the contract itself.

You can achieve the calling of approve() for your ERC20 token from your wallet, resulting in the approval of the specified amount of tokens to be spent by a particular contract on your behalf, using the JS library called ethers.js.

Here's the code snippet to achieve the same:

// Importing necessary modules from ethers library
const { ethers } = require('ethers')

// Initializing a JSON RPC provider with the URL
const provider = new ethers.JsonRpcProvider("JSON_RPC_URL")

// Defining a private key for signing transactions
const privateKey = "PRIVATE_KEY" // Private Key should be of your wallet having balance of ERC20 tokens that you're going to approve

// Creating a signer using the private key and provider
const signer = new ethers.Wallet(privateKey, provider)

// Defining the address of the ERC20 token contract
const tokenAddress = "ERC20_TOKEN_ADDRESS"

// ABI (Application Binary Interface) of ERC20 approve and allowance functions
const erc20_approveAndAllowance_abi = [
    {
        // Describe the inputs and outputs of 'allowance' function
        "inputs": [
            {
                "internalType": "address",
                "name": "owner",
                "type": "address"
            },
            {
                "internalType": "address",
                "name": "spender",
                "type": "address"
            }
        ],
        "name": "allowance",
        "outputs": [
            {
                "internalType": "uint256",
                "name": "",
                "type": "uint256"
            }
        ],
        "stateMutability": "view",
        "type": "function"
    },
    {
        // Describe the inputs and outputs of 'approve' function
        "inputs": [
            {
                "internalType": "address",
                "name": "spender",
                "type": "address"
            },
            {
                "internalType": "uint256",
                "name": "amount",
                "type": "uint256"
            }
        ],
        "name": "approve",
        "outputs": [
            {
                "internalType": "bool",
                "name": "",
                "type": "bool"
            }
        ],
        "stateMutability": "nonpayable",
        "type": "function"
    }
]

// Creating a contract instance using token address and ABI, with the signer
const tokenContract = new ethers.Contract(tokenAddress, erc20_approveAndAllowance_abi, signer)

// Defining the address of the contract to approve
const contractAddress = "CONTRACT_ADDRESS"

// Defining the amount of tokens to approve (1 Ether in this case)
const amountToApprove = ethers.parseUnits("1")  // 1 Ether = 1e18 Wei (1000000000000000000)

// Retrieving current allowance before approval and logging it
tokenContract.allowance(signer.address, contractAddress).then((allowance) => {
    console.log("Allowance before approval: ", allowance.toString())
})

// Approving tokens for the contract and logging the transaction hash after it's done
tokenContract.approve(contractAddress, amountToApprove).then(async (tx) => {
    const receipt = await tx.wait() // Waiting for transaction receipt

    console.log("Tx hash of approval: ", receipt.hash) // Logging transaction hash

    // Retrieving updated allowance after approval and logging it
    tokenContract.allowance(signer.address, contractAddress).then((allowance) => {
        console.log("Allowance after approval: ", allowance.toString())
    })
})
10
  • Hi, Currently the code is like below still getting 0 values for allowences please advice ? token = IERC20(_tokenAddress); console.log("Token is formed."); bool _success = token.approve(address(this), amount);//mevcut smart contract //bool _success = IERC20(token).approve(address(this), amount);//mevcut smart contract if (_success) { console.log(IERC20(token).allowance(msg.sender, receiver)); } else { revert("failed to approve First approve "); } Apr 9 at 14:44
  • Can you create the gist of your code and share the link ? Apr 9 at 14:48
  • After your first approve, the allowance should be checked using token.allowance(address(this), address(this)). I've corrected the code snippet, and also added more details as well as the JS code to achieve the correct approve and allowance on behalf of the user/wallet. Apr 10 at 9:03
  • Hi, I checked there is only one revision of this code (created by me), are you sure that you saved your edits ? Apr 11 at 0:09

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.