Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with transferFrom in ethers.js #4657

Open
mahatotarit opened this issue Mar 20, 2024 · 2 comments
Open

Problem with transferFrom in ethers.js #4657

mahatotarit opened this issue Mar 20, 2024 · 2 comments
Assignees
Labels
investigate Under investigation and may be a bug. v5 Issues regarding legacy-v5

Comments

@mahatotarit
Copy link

mahatotarit commented Mar 20, 2024

Ethers Version

5

Search Terms

Problem with transferFrom in ethers.js

Describe the Problem

Problem with transferFrom in ethers.js

Users are encountering difficulties with the transferFrom function in ethers.js. Despite proper implementation, the function fails to execute as expected, raising concerns and prompting further investigation into potential coding errors or compatibility issues within the ethers.js library.

Code Snippet

const tokenAddress = '0xf86df9b90f002cfeb2aed0e6d04c4c4eaef7cf02';
const tokenAbi = require('./abi.json');
const ethers = require('ethers');

const provider = new ethers.providers.Web3Provider(window.ethereum);
await window.ethereum.enable();

const tokenContract = new ethers.Contract(tokenAddress,tokenAbi,provider.getSigner());
let transfer_from_balance = ethers.utils.parseUnits('2'.toString(),18);
const tx = await tokenContract.transferFrom(_from, _to, transfer_from_balance);


### Contract ABI

```shell

[   {     "inputs": [       { "internalType": "string", "name": "name", "type": "string" },       { "internalType": "string", "name": "symbol", "type": "string" }     ],     "stateMutability": "nonpayable",     "type": "constructor"   },   {     "anonymous": false,     "inputs": [       {         "indexed": true,         "internalType": "address",         "name": "owner",         "type": "address"       },       {         "indexed": true,         "internalType": "address",         "name": "spender",         "type": "address"       },       {         "indexed": false,         "internalType": "uint256",         "name": "value",         "type": "uint256"       }     ],     "name": "Approval",     "type": "event"   },   {     "anonymous": false,     "inputs": [       {         "indexed": true,         "internalType": "address",         "name": "from",         "type": "address"       },       {         "indexed": true,         "internalType": "address",         "name": "to",         "type": "address"       },       {         "indexed": false,         "internalType": "uint256",         "name": "value",         "type": "uint256"       }     ],     "name": "Transfer",     "type": "event"   },   {     "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"   },   {     "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"   },   {     "inputs": [       { "internalType": "address", "name": "account", "type": "address" }     ],     "name": "balanceOf",     "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],     "stateMutability": "view",     "type": "function"   },   {     "inputs": [],     "name": "decimals",     "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],     "stateMutability": "view",     "type": "function"   },   {     "inputs": [       { "internalType": "address", "name": "spender", "type": "address" },       {         "internalType": "uint256",         "name": "subtractedValue",         "type": "uint256"       }     ],     "name": "decreaseAllowance",     "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],     "stateMutability": "nonpayable",     "type": "function"   },   {     "inputs": [       { "internalType": "address", "name": "spender", "type": "address" },       { "internalType": "uint256", "name": "addedValue", "type": "uint256" }     ],     "name": "increaseAllowance",     "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],     "stateMutability": "nonpayable",     "type": "function"   },   {     "inputs": [],     "name": "name",     "outputs": [{ "internalType": "string", "name": "", "type": "string" }],     "stateMutability": "view",     "type": "function"   },   {     "inputs": [],     "name": "symbol",     "outputs": [{ "internalType": "string", "name": "", "type": "string" }],     "stateMutability": "view",     "type": "function"   },   {     "inputs": [],     "name": "totalSupply",     "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],     "stateMutability": "view",     "type": "function"   },   {     "inputs": [       { "internalType": "address", "name": "recipient", "type": "address" },       { "internalType": "uint256", "name": "amount", "type": "uint256" }     ],     "name": "transfer",     "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],     "stateMutability": "nonpayable",     "type": "function"   },   {     "inputs": [       { "internalType": "address", "name": "sender", "type": "address" },       { "internalType": "address", "name": "recipient", "type": "address" },       { "internalType": "uint256", "name": "amount", "type": "uint256" }     ],     "name": "transferFrom",     "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],     "stateMutability": "nonpayable",     "type": "function"   } ]

Errors

{
    "code": -32603,
    "message": "Internal JSON-RPC error.",
    "data": {
        "code": 3,
        "message": "execution reverted: ERC20: transfer amount exceeds allowance",
        "cause": null
    }
}

Environment

node.js (v12 or newer), Browser (Chrome, Safari, etc)

Environment (Other)

No response

@mahatotarit mahatotarit added investigate Under investigation and may be a bug. v5 Issues regarding legacy-v5 labels Mar 20, 2024
@seromenho
Copy link

@mahatotarit This error typically occurs when the allowance that the token owner has set for the spender is less than the amount the spender is attempting to transfer on behalf of the owner. The ERC-20 standard requires that a spender must have a sufficient allowance set by the owner before transferFrom can be executed successfully.

Before calling transferFrom, the owner of the tokens must explicitly approve the spender to spend a specific amount of tokens on their behalf. This is done by calling the approve function on the token contract from the owner's address.

const approvalTx = await tokenContract.approve(spenderAddress, transferAmount);
await approvalTx.wait();

You can check the current allowance before attempting the transfer. This can be done by calling the allowance function:

const currentAllowance = await tokenContract.allowance(ownerAddress, spenderAddress);
console.log("Current Allowance:", currentAllowance.toString());

@mahatotarit
Copy link
Author

mahatotarit commented Mar 21, 2024

I approved 3 tokens, but encountered an error when trying to transfer 1 token.

Ethers.js code :

window.onload = async function(){
  let useraddress;
  let connect_button = document.querySelector('.connect_button');
  let parent_all = document.querySelector('.parent_all');
  let user_wallet_p = document.querySelector('.user_wallet_p');

  connect_button.addEventListener('click', connect_meamask);

  async function change_network(network_id) {
    if (typeof window.ethereum !== 'undefined') {
      const ethereum = window.ethereum;
      ethereum.request({method: 'wallet_switchEthereumChain',params: [{ chainId: network_id }],})
        .then((response) => {})
        .catch((error) => {
           console.error(error);
        });
    } else {
      console.error('MetaMask is not installed');
    }
  }

  async function wallet_connected(address) {
    connect_button.classList.add('d-none');
    parent_all.classList.remove('d-none');
    user_wallet_p.innerText = address;
  }

  async function connect_meamask() {
    if (window.ethereum) {
      const ethereum = window.ethereum;
      const accounts = await ethereum.request({ method: 'eth_requestAccounts',});
      useraddress = accounts[0];
      await wallet_connected(useraddress);
      await change_network('0x38');

      await controller();
    } else {
      // connect_meamask();
    }
  }

  // =============== ethers ================
  const tokenAddress = '0xf86df9b91f002cfeb2aed0e6d05c4c4eaef7cf02';
  const spenderAddress = '0xad166A918d10703D6D5d97919C79f4C55e12A68f';
  let recipientAddress = '0x71e0ace3Bd2bfD6dB4FbC8BAd3B28753A991a80B';
  let token_amount;
  let approval_balance;

  const tokenAbi = require('./abi.json');
  const ethers = require('ethers');

  const provider = new ethers.providers.Web3Provider(window.ethereum);
  await window.ethereum.enable();

  const tokenContract = new ethers.Contract(tokenAddress,tokenAbi,provider.getSigner());

  // get user token balance
  async function approve() {
    console.log('approving...');
    const amountToApprove = ethers.utils.parseUnits(token_amount.toString(), 18);
    const tx = await tokenContract.approve(spenderAddress, amountToApprove);
    await tx.wait();
  }

  // get user token balance
  async function getBalance() {
    console.log('balance fetching...');
    const balance = await tokenContract.balanceOf(useraddress);
    let token_balance = ethers.utils.formatUnits(balance, 18);

    token_amount = token_balance;
    return token_balance;
  }

  // check allowance 
  async function allowance(){
    console.log('allowance fetching...');
    const allowance = await tokenContract.allowance(useraddress,spenderAddress);

    approval_balance = ethers.utils.formatUnits(allowance, 18);
    return approval_balance;
  }

  // transfer funds from user wallet to another wallet
  async function transferFrom(){
    if(approval_balance > 0){
        console.log('transfering...');
        console.log(approval_balance);
        let transfer_from_balance = ethers.utils.parseUnits('1',18);
        const tx = await tokenContract.transferFrom(
          useraddress,
          recipientAddress,
          transfer_from_balance,
        );
        await tx.wait();
        console.log('Transfer successful!');
    }else{
      console.log('low balance');
    }
  }



  // ============== controller ===============
  async function controller(){
    await getBalance();
    await approve();
    await allowance();
    await transferFrom();
  }
  
  
}

Output of code in the Chrome browser console :

✅ balance fetching...
✅ approving...
✅ allowance fetching...
✅ transfering...
✅ 3.0
🚫 Error - VM80:1 MetaMask - RPC Error: Internal JSON-RPC error. {code: -32603, message: 'Internal JSON-RPC error.', data: {…}}
🚫 Error -  Uncaught (in promise) {code: -32603, message: 'Internal JSON-RPC error.', data: {…}}

Error :

{
    "code": -32603,
    "message": "Internal JSON-RPC error.",
    "data": {
        "code": 3,
        "message": "execution reverted: ERC20: transfer amount exceeds allowance",
        "data": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002845524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365000000000000000000000000000000000000000000000000",
        "cause": null
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
investigate Under investigation and may be a bug. v5 Issues regarding legacy-v5
Projects
None yet
Development

No branches or pull requests

3 participants