Transfering ERC20 token using javascript and Metamask

260 Views Asked by At

I'm developing a app that allows to transfer crypto assets using safeTransferFrom method that will call Metamask to confirm the transaction. It works well but I have a weird issue. in order to test my app, I created a ERC20 token on Mumbai. So I try to use my app to transfer some tokens, I confirm the transaction through Metamask but the transaction is rejected. Then I try do the same transaction using Metamask interface, the transaction is successful. So I try again with my app and now it's working. I get this behavior every time I want to send a new token. Do you know why I need to use Metamask first and how to fix this behaviour ?

async function sendToken(provider, account, recipientAddress, tokenContractAddress, amountToSend) {
  // Define the ABI for the ERC-20 contract
  const erc20ABI = [
    'function transfer(address to, uint256 value)',
    'function balanceOf(address owner) view returns (uint256)',
    // Add other ERC-20 functions as needed
  ];
  // The MetaMask plugin also allows signing transactions to send ether and pay to change state within the blockchain.
  // For this, you need the account signer...
  const signer = provider.getSigner();
  // Create a contract instance for the ERC-20 token
  const tokenContract = new ethers.Contract(tokenContractAddress, erc20ABI, provider);
  // Connecting with a signer allows you to use all the methods of the contract
  const tokenContractWithSigner = tokenContract.connect(signer);
 
  // Check the sender's token balance
  const senderBalance = await tokenContract.balanceOf(account);
  if (senderBalance.gte(1)) { // Check if the sender has enough tokens
    try {
      // Send the tokens
      const tx = await tokenContractWithSigner.transfer(recipientAddress, amountToSend.toHexString(),{gasLimit: 50000});
      await tx.wait(); // Wait for the transaction to be mined
      .catch((error) => console.error(error));
      console.log(Transferred ${amountToSend} tokens to ${recipientAddress} successfully);
    } catch (error) {
      console.error('Error sending tokens:', error);
    }
  } else {
    console.error('Sender does not have enough tokens');
  }

I want my web app to be able to sent the ERC20 token without having to sent it through Metamask first

1

There are 1 best solutions below

0
On

When you try to send tokens directly from your app without having first interacted with the token through MetaMask, the allowance for spending tokens might not be set correctly.

To solve the issue you can set Allowance Before Transfer.Before making the transfer call, ensure that the sender (your app) has approved the spending of tokens by the ERC-20 contract. Use the approve method to set the allowance. This should be done once per token and per recipient address.

async function sendToken(provider, account, recipientAddress, tokenContractAddress, amountToSend) {
  const erc20ABI = [
    'function transfer(address to, uint256 value)',
    'function balanceOf(address owner) view returns (uint256)',
    'function approve(address spender, uint256 value) public virtual returns (bool)',
    'function allowance(address owner, address spender) public view virtual returns (uint256)'
    // Add other ERC-20 functions as needed
  ];
  
  const signer = provider.getSigner();
  
  const tokenContract = new ethers.Contract(tokenContractAddress, erc20ABI, provider);
  
  const tokenContractWithSigner = tokenContract.connect(signer);
  
  const senderBalance = await tokenContract.balanceOf(account);

  const allowance = await tokenContract.allowance(account, recipientAddress);

  if (senderBalance.gte(1)) { 

    try {

    if (allowance.lt(amountToSend)) {
      // Allowance is not sufficient, prompt the user to approve spending tokens
      const approvalTx = await tokenContractWithSigner.approve(recipientAddress, amountToSend.toHexString(), { gasLimit: 50000 });
      await approvalTx.wait();
    }
      
      const tx = await tokenContractWithSigner.transfer(recipientAddress, amountToSend.toHexString(),{gasLimit: 50000});
      await tx.wait();

      console.log(Transferred ${amountToSend} tokens to ${recipientAddress} successfully);

    } catch (error) {
      console.error('Error sending tokens:', error);
    }

  } else {
    console.error('Sender does not have enough tokens');
  }

This help in handling the approval process.