2

I have multiple wallet created in my nodejs app. i can successfully send transactions from one and consolidate all funds. my problem is when a wallet only have an ERC20 token in it and doesnt have ETH to cover the gas. suppose it has 100 USDC token and i want to send those tokens to another wallet, how can i do that?

what i have tried:

  • Meta transaction: this doesnt work, at least for the USDC contract, it sends the transaction to a forwarder that i have created myself (which works on another contract of mine) but when the forwarder sends a transaction to USDC/USDT contract, it always gets rejected. i have tried to increase the gas but whatever i do it just reject (the USDC contract rejects the forwarder) transaction.
  • Sending a signed transaction by Wallet "A" (which has the ERC20 token but no ETH to pay the gas) using Wallet "B" which has ETH and would pay for the gas, but cannot figure it out, it always gets an error. This is my code to create and send the signed transaction
 const wallet = new ethers.Wallet(privateKey_signer, provider);
    const wallet2 = new ethers.Wallet(privateKey_sender, provider);
    const nonce = await provider.getTransactionCount(wallet.address);

const txObject = {
      to: usdc.address,
      nonce: ethers.utils.hexlify(nonce),
      gasLimit: ethers.utils.hexlify(gasLimit),
      gasPrice: ethers.utils.hexlify(gasPrice),
      value: ethers.utils.hexlify(0n),
      data: usdc_contract.interface.encodeFunctionData("transfer", [
        destination_address,
        amount.toString(),
      ]),
    };

    const signedTx = await wallet.signTransaction(txObject);
    const txResponse = await wallet2.sendTransaction(signedTx);

i'm using ethersjs lib and alchemy provider.

i would appreciate any pointers. thanks

3 Answers 3

3

A basic Ethereum transaction looks like this:

from – the address of the sender, that will be signing the transaction. 
recipient – the receiving address. If a contract account, the transaction will execute the contract code)
signature – the identifier of the sender. This is generated when the sender's private key signs the transaction and confirms the sender has authorized this transaction
nonce - 
value – 
data – 
gasLimit –
maxPriorityFeePerGas - 
maxFeePerGas -

Source

The gas fee is deducted from the sender account. And the signature needs to be generated using the sender's private key. Unfortunately, sender=wallet2 and signature=wallt1 simply doesn't work.

For tokens, you can use wallet2 to send a transaction on behalf of wallet1 to transfer x amount of tokens to another address. Firstly, you need to call the approve method to set the allowance limit, then call the transferFrom method. But calling the approve method costs gas too. I guess the most gas-efficient way is to transfer some eth to wallet1 and have wallet1 transfer tokens directly.

In your sample code, you are calling the transfer method, which is transferring from the msg.sender(wallet2 in this case) to the destination. If it can be successfully executed it may not work as you expect.

2
  • thanks for the answer, well yeah, correct, the best way i could think of is to just once do this approve for infinite amount, then i no longer need to send ETH to do this. checked out couple of exchanges centralized wallets and how they would transfer it, got this option, which for me i guess is the best way. you are right, i didnt know, i was under the impression if i have the signed tx, so anyone should be able to "broadcast" it, you know like BTC, but i learned my lesson, just took me a day to get it. thanks bro.
    – Mostafa
    Commented Mar 29, 2023 at 6:00
  • It's my pleasure man. Happy coding. Commented Mar 29, 2023 at 7:08
1

Unfortunately, what you tried to do in your second method is not possible. You can't use another wallet to pay for the gas of a transaction signed by a different wallet.

The first method is the good one, though. Could you share the code you try to use?

You also could try using a third-party service for gas-less transactions like Gnosis Safe, Defender or Gas Station Network.

I point here some links you may find useful:

Hope this helps!

1
  • yeah the meta transaction doesnt work since the token contract i use doesnt support meta transaction and gets the sender from msg.sender rather than _msgSender(), but could have been the best option if it could work
    – Mostafa
    Commented Mar 29, 2023 at 5:56
1

as Wuzhong said, it's not possible to send another wallets transaction, so i decided to approve my pool wallet once, by sending just enough ETH to the wallet to do the approval and then set the allowance to infinite (MaxUint256) so no longer need the Wallet B, to have ETH to do the transaction, instead i would do it from my pool (or other managerial) wallet to transfer the funds. i also saw some people suggest to use smart contracts and generating new ones each time i would generate a new wallet for a user, but not working for the business logic i'm working with.

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.