{ code: -32003, message: "insufficient funds for gas * price + value: have 0 want 53901949584960" }

{ code: -32003, message: “insufficient funds for gas * price + value: have 0 want 53901949584960” }

Hello developers!
I’m getting this error while trying to transfer an ERC-20 token through the ICP chain fusion concept.

this is frontend code for authentication from metamask

  const TransferToken = async () => {
   const canisterEthAddress = "0x260A5568d2002B8F601Fe1001BD2D93A212F087b";
    console.log("Canister ETH address:", canisterEthAddress);

    const provider = new ethers.providers.JsonRpcProvider(
      "https://eth-sepolia.g.alchemy.com/v2/userAPIKey"
    );
    const nonce = await provider.getTransactionCount(canisterEthAddress);
    const feeData: any = await provider.getFeeData();
    const chainId: any = (await provider.getNetwork()).chainId;

    const tokenABI = [
      "function transfer(address to,uint256 amount) returns (bool)",
    ];
    const token = new ethers.Contract(
      "0xDFdA108391A1EDa23CB0f6546e9F9386E4227994",
      tokenABI,
      provider
    );

    const burnAddress = "0x259B2BdaD6228bdC5Eb48c7A8c244f5F798113Dd";
    const amount = ethers.utils.parseUnits("1", 18);
    const txRequest = await token.populateTransaction.transfer(
      burnAddress,
      amount
    );
    console.log("Max Fee Per Gas:", feeData.maxFeePerGas.toNumber());
    console.log(
      "Max Priority Fee Per Gas:",
      feeData.maxPriorityFeePerGas.toNumber()
    );

    const gasLimit = await provider.estimateGas({
      from: canisterEthAddress,
      to: txRequest.to,
      data: txRequest.data,
      value: 0,
    });

    console.log("gasLimit : ", gasLimit.toNumber());

    const tx = {
      type: 2,
      chainId,
      nonce,
      to: txRequest.to,
      data: txRequest.data,
      value: 0,
      maxFeePerGas: feeData.maxFeePerGas,
      maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
      gasLimit,
    };

    const unsignedTx = ethers.utils.serializeTransaction(tx);
    const txHash = ethers.utils.keccak256(unsignedTx);

    const ic = icblast({ ic: true });
    const backendActor = await ic("vrqyr-saaaa-aaaan-qzn4q-cai");
    const sig = await backendActor.sign_with_ecdsa({
      key_id: { name: "insecure_test_key_1", curve: { secp256k1: null } },
      derivation_path: [],
      message_hash: Array.from(ethers.utils.arrayify(txHash)),
    });
    const signature = new Uint8Array(sig.signature);
    const r = ethers.utils.hexlify(signature.slice(0, 32));
    const s = ethers.utils.hexlify(signature.slice(32, 64));
    const v = 27 + (sig.recovery_id ?? 0);
    const rawTx = ethers.utils.serializeTransaction(tx, { v, r, s });
    console.log("rawTx:", rawTx);
    const txHashRes = await actor.send_raw_transaction(rawTx);
    console.log("Broadcast success:", txHashRes);
  };

backend code

#[update]
pub async fn send_raw_transaction(rawSignedTransactionHex: String) -> Result<String, String> {
    let RpcServices: RpcServices = RpcServices::Custom {
        chainId: ChainId::from(1u64),
        services: vec![RpcApi {
            url: "https://eth-sepolia.g.alchemy.com/v2/userAPIKEy"
                .to_string(),
            headers: None,
        }],
    };

    let cycles = 2_000_000_000_000;
    let canister_id =
        Principal::from_text("7hfb6-caaaa-aaaar-qadga-cai").expect("principal should be valid");
    let RpcConfig: Option<()> = None;
    let args = (RpcServices, RpcConfig, rawSignedTransactionHex);

    let result: (MultiSendRawTransactionResult,) =
        call_with_payment128(canister_id, "eth_sendRawTransaction", args, cycles)
            .await
            .expect("Failed to call eth_sendRawTransaction");

    match result.0 {
        MultiSendRawTransactionResult::Consistent(SendRawTransactionResult::Ok(status)) => {
            match status {
                SendRawTransactionStatus::Ok(Some(tx_hash)) => Ok(tx_hash),
                SendRawTransactionStatus::Ok(None) => {
                    Err("Transaction succeeded but tx_hash missing".to_string())
                }
                SendRawTransactionStatus::NonceTooLow => Err("Nonce too low".to_string()),
                SendRawTransactionStatus::NonceTooHigh => Err("Nonce too high".to_string()),
                SendRawTransactionStatus::InsufficientFunds => {
                    Err("Insufficient funds".to_string())
                }
            }
        }
        MultiSendRawTransactionResult::Consistent(SendRawTransactionResult::Err(e)) => {
            Err(format!("SendRawTransaction failed: {:?}", e))
        }
        MultiSendRawTransactionResult::Inconsistent(_) => {
            Err("Transaction is inconsistent".to_string())
        }
    }
}

Error

“SendRawTransaction failed: JsonRpcError(JsonRpcError { code: -32003, message: “insufficient funds for gas * price + value: have 0 want 53901949584960” })”

I've tried this multiple times but still getting the same error. Can anyone help me fix this issue?

you let backendActor create the signature, but then actor is called for send_raw_transaction. my first guess would be that backendActor doesn’t have any ETH to pay for gas.

why do you have a two canister setup? if you return the signed transaction to the user frontend, why not send it to an RPC provider from there instead of proxying that through a canister?

in general it would be helpful if you could provide the a minimum example that reproduces the issue.

let backendActor is for the vrqyr-saaaa-aaaan-qzn4q-cai canister actor for getting signature through sign_with_ecdsa api so that we can send that signature to the eth_sendRawTransaction function and secound actor actor.send_raw_transaction(rawTx); is my own backend canister which have above provided rust code, where i’m calling eth_sendRawTransaction function in backend

vrqyr-saaaa-aaaan-qzn4q-cai this is the canister provided by definity or icp for getting signature

I don’t recognize this principal vrqyr-saaaa-aaaan-qzn4q-cai. But I think my initial assessment holds