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())
})
})