How to send an EIP-1559 raw transaction in js with Axios

In general the Javascript libraries like Ethers.js or web3.js have build in methods to sign and send a raw transaction but there might be situations where you’d want interact with the Ethereum API via plain json-rpc requests.
We’ll be using Axios to send the raw transaction but before that we’ll need to also craft the transaction object, sign it with the private key and serialize it, @ethereumjs/tx is a pretty good library that does the job.

Prerequisites:

  • instal Axios: npm i axios

  • Install @ethereumjs/tx: npm install @ethereumjs/tx

Here’s how the working code would look like (make sure to replace the Infura projectID, private key and from, to addresses placeholders):

const axios = require('axios');
const Common = require( '@ethereumjs/common' ).default;
const { FeeMarketEIP1559Transaction } = require( '@ethereumjs/tx' );

const infuraUrl = "https://ropsten.infura.io/v3/<projectID>"

const payloadProto = {
  jsonrpc: "2.0",
  method: "",
  params: [],
  id: 1
};

(async () => {
  
  const addressFrom = '0x...'
  // Exclude 0x at the beginning of the private key
  const privKey = Buffer.from('....', 'hex')
  const addressTo = '0x...'
  const valueInEther =  "0x16345785D8A0000" // 0.1 ETH = 100000000000000000 Wei
  
  // Get the address transaction count in order to specify the correct nonce
  const payloadCount = Object.assign({}, payloadProto, { method: 'eth_getTransactionCount', params: [addressFrom, "latest"]})
  var resp = await axios({
    url: infuraUrl,
    method: 'POST',
    data: payloadCount,
    headers: { 'Content-Type': 'application/json' }
  });
  const txnCount = resp.data.result
  
  // Estimate the tx gas limit
  const payloadLimit = Object.assign({}, payloadProto, { method: 'eth_estimateGas', params: [{"from": addressFrom,"to": addressTo,"value": valueInEther}]})
  resp = await axios({
    url: infuraUrl,
    method: 'POST',
    data: payloadLimit,
    headers: { 'Content-Type': 'application/json' }
  });
  const limit = resp.data.result

  // Create the EIP-1559 transaction object
  var txObject = {
    nonce: txnCount,
    gasLimit: limit,
    to: addressTo,
    value: valueInEther,
    maxFeePerGas: "0x2E90EDD000", // 200000000000 Wei
    maxPriorityFeePerGas: "0x77359400", // 2000000000 Wei
    chainId: 3,
    type: 0x2
  };

  // Sign the transaction with the private key
  var chain = new Common( { chain : 'ropsten', hardfork : 'london' } );
  const tx = FeeMarketEIP1559Transaction.fromTxData( txObject , { chain } );
  const signedTransaction = tx.sign(privKey)

  //Convert to raw transaction string
  var serializedTx = signedTransaction.serialize();
  var rawTxHex = '0x' + serializedTx.toString('hex');

  // log raw transaction data to the console in case you need it for troubleshooting
  console.log("Raw transaction data: " + rawTxHex);

  // Send the raw transaction
  const payloadTx = Object.assign({}, payloadProto, { method: 'eth_sendRawTransaction', params: [rawTxHex]})
  resp = await axios({
    url: infuraUrl,
    method: 'POST',
    data: payloadTx,
    headers: { 'Content-Type': 'application/json' }
  });
  const txhash = resp.data
  console.log(txhash)

})();
2 Likes