2

I'm attempting to initiate a transaction (transfer of ETH) from my main account to a test account on the Kovan Testnet, but I'm getting the error Returned error: Invalid chain id. from the following code:

const Web3 = require("web3");
const EthereumTx = require("ethereumjs-tx").Transaction;

const SK = process.env.PROD ? nice try ;)
const PK = process.env.PROD ? "0x5A8721b7DE69b3538a4cC61614628f7c1A6E59Fb"
  : "0x33Bcd8bf72D594B0974beFd830a29CeC55079976";
const url = process.env.PROD ? "https://kovan.infura.io/v3/2bd0c2e1f29f4ab9b47374c6b50023c5"
  : "http://127.0.0.1:8545";

const web3Provider = new Web3.providers.HttpProvider(url);
const web3 = new Web3(web3Provider);
const { toWei, numberToHex: toHex } = web3.utils;

const sendETH = async () => {
  const nonce = await web3.eth.getTransactionCount(PK);
  const tx = new EthereumTx({
    from: PK,
    to: "0x8631c939359FBb8cb336532b191ED80b20287CD1",
    value: toHex(toWei(".1")),
    gas: toHex("21000"),
    nonce,
  });
  tx.sign(Buffer.from(SK, "hex"));
  const serializedTx = tx.serialize();
  web3.eth.sendSignedTransaction("0x" + serializedTx.toString("hex"));
}
sendETH();

When I set PROD to false (testing on local network), it works fine. However I get that stubborn error every time I set the PROD to true (testing on Kovan).

2 Answers 2

2

Hey you need to do this for testing on kovan

const tx = new EthereumTx({
    from: PK,
    chainId: 42, // kovan chain id
    to: "0x8631c939359FBb8cb336532b191ED80b20287CD1",
    value: toHex(toWei(".1")),
    gas: toHex("21000"),
    nonce,
  });
8
  • Hey thanks! I'm getting an "invalid sender" error now, would you happen to know any common gotchas I might be running into? Same code, just modified to incorporate your answer. Apr 22, 2021 at 7:50
  • try the from address for "from" key, let tx be just an object instead of using EthereumTx and use this let tx = new Tx(txObject, { chain: 'kovan', // you can remove chain id from tx object hardfork: 'petersburg' }) let key = Buffer.from(process.env.PRIVATE_KEY, 'hex') tx.sign(key) let serializedTx = tx.serialize() let raw = '0x' + serializedTx.toString('hex') // Broadcast the transaction return await web3.eth.sendSignedTransaction(raw)
    – viraj
    Apr 22, 2021 at 8:04
  • I believe I followed your instructions correctly, but no dice... thanks for the help though! Apr 22, 2021 at 8:13
  • try this medium.com/blockchain-musings/….
    – viraj
    Apr 22, 2021 at 8:16
  • That article does the same process I'm doing, except it assumes require("ethereumjs-tx") to be a class where I'm assuming require("ethereumjs-tx").Transaction to be a class. I'm guessing this is just outdated procedure, since the post was from 2017. I also double checked my public key, and I have a balance of ETH on kovan, so it must be a valid address. Any other ideas? Apr 22, 2021 at 8:25
1

After some digging around in the source files of ethereumjs-tx, I found that the way to specify a chainId and hardfork is to add a second object to your EthereumTx constructor.

The chainId field takes a number (chainId) or a string (chain name), which just acts as a query to require the data necessary for that chain. This field defaults to "mainnet".

The hardfork field works similar to the chainId field, but it exclusively handles strings. The default for this field is "petersburg".

My solution was as follows:

const tx = new EthereumTx({
    from: PK,
    to: "0x8631c939359FBb8cb336532b191ED80b20287CD1",
    value: toHex(toWei(".0001")),
    gas: toHex("21000"),
    nonce,
  }, { chain: 42 });

A big thank you to viraj for giving his solution in the comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.