How to transfer tokens from a smart contract wallet to an EOA wallet

Viewed 1230

I'm using Next.js, web3-react, ethers.js, MetaMask and Ganache to run a local blockchain.

What I'm trying to do: when the user clicks a button on the front-end, that button opens MetaMask where some tokens (I "minted/created" these tokens) are sent from the smart contract/smart contract creator to the user upon user consent.

The problem is: when the user clicks the button, the MetaMask pop-up appears, but the sender/recipient addresses are the same.

enter image description here

What I want is for the sender address to be the same as the smart contract/smart contract creator and this transaction should be done by MetaMask.

The following code is what I've done so far:

import { ethers, Contract } from 'ethers'
import { useWeb3React } from '@web3-react/core'
import HRC20 from '../../assets/HRC20.json'

const { account: userAccountAddress, library } = useWeb3React()

const provider = new ethers.providers.Web3Provider(
  library.provider // this is the same as `window.ethereum.provider` injected by MetaMask
)
const signer = provider.getSigner()

const tokenContract = new ethers.Contract(
  '0x4feEc53a54e36C80A2F0a47454Ab285B99A1a240',
   HRC20.abi,
   provider
)

const tokenContractWithSigner = contract.connect(signer)

const tx = tokenContractWithSigner.transfer(
  userAccountAddress,
  10000000000
)

My guess is that I need to specify the sender address when creating the provider or signer or something.

3 Answers

Based on calling tokenContractWithSigner.transfer, you have 2 args

function transfer(address _to, uint _value) public returns (bool success){
        // make sure callee has enough balance
        require(balanceOf[msg.sender]>=_value);
        // ... more logic
        to=payable(_to)
        to.transfer(value);     
    }

Or:

function transfer(address _to, uint _value) public returns (bool success){
        // make sure callee has enough balance
        require(balanceOf[msg.sender]>=_value);
        // ... more logic
       to=payable(_to)
        
       (bool success,)=to.call{value:_value}("");
       require(success,"Transfer failed!");
    }

When you call this:

tokenContractWithSigner.transfer(
  userAccountAddress,
  10000000000
).send({from:getAccount})

According to the ERC20 standart, the transfer method of an ERC20 contract is used to transfer tokens from the sender of the transaction, to the address specified. Because it is the same address that is sent the transaction and is given to the transfer method, the contract thinks you want to transfer tokens from an address to the same address.

To mint new tokens you need to add a mint method to your ERC20 contract.

I did find a solution to my problem: first, I can only make a transaction using MetaMask when the sender is me. I cannot send tokens on behalf of another wallet, even if I own it.

My approach was to create an endpoint on the backend that would receive the user's wallet address; then I connect to the wallet that holds the funds (usually the wallet that deployed the token) using its private key and that wallet signs the transaction. On the front end, I listen for a Transfer event so I can notify the user when their transactions are mined/confirmed.

Reference: https://ethereum.org/en/developers/tutorials/send-token-etherjs/#send-token-method

Related