Create a signed transaction on the front-end to be propagated by the back-end

Hey everyone! I’m trying to allow users to sign a transacation, which is meant to call a smart contract method, on the front-end, so Metamask would prompt the user to sign message/transaction which would be sent to the back-end in order to be propagated to the blockchain. This is what I currently have on the front-end in order to achieve this goal:

    const chainId = 3 // Ropsten
    const from = await signer.getAddress()
    const nonce = await signer.getTransactionCount()
    const contractInterface = new ethers.utils.Interface(Contract.abi)
    
    const domain = {
      name: 'Contract method call',
      version: '1',
      chainId,
    }

    const types = {
      Transaction: [
        { name: 'from', type: 'address' },
        { name: 'to', type: 'address' },
        { name: 'nonce', type: 'uint256' },
        { name: 'chainId', type: 'uint16' },
        { name: 'gas', type: 'string' },
        { name: 'gasPrice', type: 'string' },
        { name: 'gasLimit', type: 'string' },
        { name: 'data', type: 'string' },
      ],
    }

    const txObj = {
      from,
      to,
      nonce,
      chainId,
      gas: ethers.utils.hexlify(500000),
      gasPrice: ethers.utils.hexlify(gasPrice),
      gasLimit: ethers.utils.hexlify(500000),
      data: contractInterface.encodeFunctionData('methodName', [arg1, arg2]),
    }

    const rawSignature = await signer._signTypedData(domain, types, txObj)
    const signature = rawSignature.substring(2)

    const r = '0x' + signature.substring(0, 64)
    const s = '0x' + signature.substring(64, 128)
    const v = parseInt(signature.substring(128, 130), 16)

    const unsignedTx = { ...txObj }
    delete unsignedTx.from
    delete unsignedTx.gas

    const signedTx = ethers.utils.serializeTransaction(unsignedTx, { r, s, v })

The signedTx is then sent to the back-end which will eventually sendRawTransaction. Unfortunatly this approach isn’t working and I am getting insufficient funds for gas * price + value even though I have more than enough in wallet. What’s the right way to go about this?

Any help would be much appreciated.

Thank you so much for your time!

hi @Nuno, check this tutorial, it has a full working code using ethers.js and does exactly what you’re trying to accomplish: Ethereum JavaScript Libraries: web3.js vs. ethers.js (Part II) | Infura Blog | Tutorials, Case Studies, News, Feature Announcements

Hey @traian.vila,

Thank you so much for your reply! Sadly in suggested tutorial the transaction is actually sent by the front-end.

What I need to accomplish is getting the user to sign the transaction in the front-end, which would be sent to the back-end, so this last one can handle load balancing and stuff, and then send it to Infura.

Regards

Ah I see what you mean. I don’t think you can do it with Metamask because it doesn’t support signing a transaction without submitting. Maybe using meta-transactions could be a solution for you, check this thread for more info web3js - Need only sign transaction feature (not send transaction) - Ethereum Stack Exchange