Search code examples
javascriptnode.jsethereumweb3js

Web3 SendSignedTransaction through Infura doesn't appear in the Etherscan transactions list


I've started this Udacity Blockchain Nanodegree Program and I started programming some blockchain applications.

From the course I started to code a simple program to send some Ether from one Metamask account to another one, both accounts are in the same testnet (Rinkeby).

This is what I am using for program so far:

  • Metamask with the 2 accounts in the Rinkeby Testnet.
  • Web3 version 1.5.1
  • ethereumjs-tx version 2.1.2
  • Infura Rinkeby Endpoint

PROBLEM

The problem is that the course is outdated and most of their code doesn't work anymore. So, I started implementing my code after 3 days of searching through the Web3 website ( link: https://web3js.readthedocs.io/en/v1.4.0/index.html ), I managed to write the code that you can see in the snippet.

The code throws no errors on my end, and when I check the number of transactions (including the pending ones), the number of transactions keeps increasing each time I run my code. But, when I check the Rinkeby Etherscan website ( link: https://rinkeby.etherscan.io/ ), the transactions are nowhere to be found in the transaction list (completed, pending, failed, outgoing and incoming transactions).

QUESTIONS

  • What is/are the problem/s with my code? How can I solve it/them?
  • How do I calculate the GasPrice and how do I determine the GasLimit? I only want to make a transaction to send X amount of Ether with no data.
  • I tried to use the same GasPrice and GasLimit as Metamask, but it throw me the error "Intrinsic gas too low". Why does it happen? Because, I had no problems using those values with Metamask, and the transaction to send some ether from one of my metamask account to the other took less than 3 minutes to completed (I sent the transaction from the Metamask Plugin).
  • Does the chain's fork has anything to do with this problem? If so, How do I check the correct fork for my two accounts in Metamask?

NOTE

I am sharing through the code the private key for the senderAccount because these 2 accounts are only for testing this particular code in the Rinkeby Testnet. I am not planning to use them as wallets.

CODE

// STEP 1: LOADING DEPENDENCIES
const Web3 = require('web3');
const web3 = new Web3('https://rinkeby.infura.io/v3/4fa53ccf01504cc69f0dcbdfdaa38acf');
const Transaction = require('ethereumjs-tx').Transaction;

async function sendTransaction() {
    // STEP 2: INSTANCIATING ADDRESSES
    const sendingAddress = '0x5Be6e93fE99374E506F4e3803e91EbDFe35D6A39';
    const receivingAddress = '0x24620ddf8474c89C0Fc0c916acBcF4029C4eB47F';

    // STEP 3: CONSTRUCTING THE TRANSACTION
    const rawTx = {
        from        :   web3.utils.toHex(sendingAddress),
        to          :   web3.utils.toHex(receivingAddress),
        value       :   web3.utils.toHex(900000000000000),
        gasPrice    :   web3.utils.toHex(1000000000),
        gasLimit    :   web3.utils.toHex(210000),
        data        :   web3.utils.toHex(''),
        nonce       :   web3.utils.toHex(await web3.eth.getTransactionCount(sendingAddress, 'pending')),
    };

    // STEP 4: GENERATING PRIVATE KEY FROM PRIVATE KEY OF ACCOUNT
    const privateKey = Buffer.from('e603c35185142cc8779c47f9c88a81a52446aaa1398286abf3340178aee11c36', 'hex');

    // STEP 5: INITIALIZATING THE TRANSACTION
    const tx = new Transaction(rawTx, { chain: 'rinkeby', hardfork: 'istanbul' });

    // STEP 6: SIGN TRANSACTION
    tx.sign(privateKey);

    // STEP 7: SERIALIZE TRANSACTION
    const serializedTx = tx.serialize();
    web3.eth.sendSignedTransaction('0x' + serializedTx.toString('hex')).on('receipt', console.log);

    // BONUS: CHECKING NUMBER OF TRANSACTIONS
    console.log(await web3.eth.getTransactionCount(sendingAddress, 'pending'));
}

sendTransaction();

Solution

  • Ok, I've found out that the code was incomplete and I needed to implement more things. Here is the code completed and 100% working.

    // THIS IS THE LEGACY FORM TO SEND TRANSACTIONS
    // Loading dependencies
    const fs = require( 'fs' ).promises;
    const Web3 = require( 'web3' );
    const HDWalletProvider = require( '@truffle/hdwallet-provider' );
    const { mnemonicGenerate } = require( '@polkadot/util-crypto' );
    const Transaction = require('ethereumjs-tx').Transaction;
    const Common = require('ethereumjs-common').default;
    
    async function main () {  
        // Infura rinkeby's url
        const infuraRinkeby = INFURA_HTTPS;
    
        // Generating bip39 mnemonic
        // const mnemonic = mnemonicGenerate();
        // save the mnemonic in a JSON file in your project directory
        // console.log(mnemonic);
    
        // Loading previously generated mnemonic
        const mnemonic = ( JSON.parse( await fs.readFile(
                           "FILE_WITH_MNEMONIC.json" ,
                           "utf8" 
                          ) ) ).mnemonic;
    
        // Generating provider
        const provider = new HDWalletProvider( mnemonic , infuraRinkeby );
        const web3 = new Web3( provider );
    
        // Declaring rinkeby testnet
        const chain = new Common( 'rinkeby' , 'istanbul' );
    
        // Getting sending and receiving addresses
        //YOU CAN CHANGE 0 TO SELECT OTHER ADDRESSES
        const sendingAddress = ( await web3.eth.getAccounts() )[0]; 
        const receivingAddress = "DESTINATION_ADDRESS";
    
        // Getting the private key for the account
        const preKey = ( provider.wallets )[ sendingAddress.toLowerCase() ]
                       .privateKey.toString( 'hex' );
        const privateKey = Buffer.from( preKey , 'hex' );
    
        // Constructing the raw transaction
        const rawTx = {
            from        :   web3.utils.toHex( sendingAddress ),
            to          :   web3.utils.toHex( receivingAddress ),
            gasPrice    :   web3.utils.toHex( web3.utils.toWei( '1' , 'gwei' ) ),
            gasLimit    :   web3.utils.toHex( 200000 ),
            value       :   web3.utils.toHex( web3.utils.toWei( '0.25' , 'ether' ) ),
            data        :   web3.utils.toHex( 'Hello World!' ),
            nonce       :   web3.utils.toHex( await web3.eth.getTransactionCount( 
                                              sendingAddress ,
                                              'pending'
                                             ) ),
        };
    
        // Creating a new transaction
        const tx = new Transaction( rawTx , { common : chain } );
    
        // Signing the transaction
        tx.sign( privateKey );
    
        // Sending transaction
        await web3.eth.sendSignedTransaction( '0x' + tx.serialize().toString( 'hex' ) )
        .on( 'receipt', function( receipt ) {
            console.log( receipt );
        })
        .on( 'error' , function( error ) {
            console.error( error );
        });   
    };
    
    main();