General Javascript Questions

Feel free to post general Javascript questions here.


Hi guys, this is my first post; I am sorry if it is not to the right box…

on node.js I already have running program using ethers.js to interact with my Metamask wallet thru mnemonic phrase. I working to transfer my code to web app using Moralis to allow user to connect with Matamask without the risk to expose user’s Mnemonic phrase…
On node.js my code to interact with wallet is like this.

var PROVIDER = await new ethers.providers.JsonRpcProvider(providerUrl);
var WALLET = ethers.Wallet.fromMnemonic(pass.trader_mnemonic);
var ACCOUNT = await WALLET.connect(PROVIDER);
var ROUTER = await new ethers.Contract( ROUTER_ADDR, abi, ACCOUNT );
// perform calls with Router obj with logics

Can I create WALLET and ROUTER object like above by connecting with Metamask thru Web app not using mnemonic phrase or private key?

You can use web3 in the browser via metamask

NodeJS runs in the server and therefore it doesn’t have access to Metamask and you have to use a mnemonic

Why do you run web3 in NodeJS?

Hi Ivan, nice to hear from you!
I am coding a bot for my self. that is why I just use nodejs for bot to run on CLI.
now I want to make a dapp for people to use. Thus I want to transfer code to Web Moralis.
I am now getting a bit confussed with the Signer vs Wallet object… Dont know how to create Router instance for Pancake swap to interact with Metamask…

Your bot will not be able to make transactions on behalf of the users if they don’t allow your bot to spend funds via the “approve” function in the ERC20 contract you want to trade.

Bot wallet you can connect to web3 in NodeJS via mnemonic.

I don’t see another way as it’s impossible to do a software that moves someone’s funds without them calling “approve” and letting your bot wallet move their funds. Read about approve function and how it works in ERC20 docs

You need to get approval for each token you trade on their behalf

I want to have Metamask to ask for user Approval once; Then bot will perform some logics, i.e wait for a good price. Then when conditions are meet, bot will make swap with DEX.
Can I do that with web3 Moralis?

Yes you can do that

You need to ask allowance for every token you want to trade

That’s how ERC20 works

Thanks Ivan,…
After a while, I came up with this code; It orders MM to make a swap on Pancakeswap, but it requires 2 times approval from user:
How do I avoid the second one ?
I want just approve the order ONCE, then have this trade go thru automatically when the bot find a good chance to swap…

      async function swapFunction() {
        const provider = new ethers.providers.Web3Provider(window.ethereum)

        const signer = provider.getSigner()

        var signerAddress = await signer.getAddress()

        const ACCOUNT = provider.getSigner(0);

        var ROUTER_ADDR = '0x05ff2b0db69458a0750badebc4f9e13add608c7f'; //pancakeswap router

        var ROUTER_CONTRACT = await new ethers.Contract(
            'function getAmountsOut(uint amountIn, address[] memory path) public view returns (uint[] memory amounts)',
            'function swapExactTokensForTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts)',

        console.log(ROUTER_CONTRACT,"<< ROUTER_CONTRACT")

        var BASE = "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c";
        var TOKEN = "0xe9e7cea3dedca5984780bafc599bd69add087d56";

        var BASE_CONTRACT = new ethers.Contract(
            'function approve(address spender, uint value) external returns (bool)',
            'function decimals() public view returns (uint8)',
            'function balanceOf(address account) external view returns (uint256)',
            'function allowance(address _owner, address spender) external view returns (uint256)'

        console.log(BASE_CONTRACT,"<< BASE_CONTRACT")
        var amountIn_weiBN = ethers.utils.parseEther("0.001");
        var gasLimit = 300000;
        var gasPrice_weiBN = ethers.utils.parseUnits(`${5}`, 'gwei');;
        var approved = false

        // ******************  Here Metamask ask to Click Confirmation 1st time. *******************
        var approved = await BASE_CONTRACT.approve( ROUTER_ADDR,
                                                'gasLimit': gasLimit,
                                                'gasPrice': gasPrice_weiBN 

        console.log(approved,"<< approved")
        var routerAmountsOutBN = await ROUTER_CONTRACT.getAmountsOut( amountIn_weiBN,
                                              [BASE, TOKEN]);
        console.log(routerAmountsOutBN,"<<< routerAmountsOutBN")
       // .... Here will come some bot logics .... 
       // How to avoid this second time Confirmation ??
       // ******************  Here Metamask ask to Click Confirmation 2nd time. *******************
        var tx = await ROUTER_CONTRACT.swapExactTokensForTokens(
                      [BASE, TOKEN],
             + 1000 * 60 * 10, //10 minutes
                        'gasLimit': gasLimit,
                        'gasPrice': gasPrice_weiBN
        console.log(tx,"<<< tx")

you can do infinite approve:

I guess you miss understood my question…
If I have the infinite amount approved, it may eliminate the First Token Approval (in the future), But not the second Swapping Approval. What I am trying to do, is to have bot take care of the trade within the allowed amount and send out the transaction whenever it wants, without further human interaction.

After approval you can use your bot wallet to trade on behalf of the user (as it has permission to use funds), study how approve works in ERC20 and you will figure it out :raised_hands:

Thanks Ivan, I know you are too busy to answer my silly questions in more details… But I ve read your answer hundreds time but could not get it…
but still hope some one could help me go thru this issue…
I approved Pancakeswap Router to use fund in Matemask wallet. How can I avoid the second approval click when app send out swap order ?

1 Like

For what i understand, this is the pancake contract right? you are approving the contract to spent tokens in the accounts name.

While this one is basically another contract right? the bot contract maybe? so that means that each contracts need approval to spent tokens on the account behalf, i mean, you already approved the pancake contract, but is the router contract approved to spent tokens??

Carlos Z

Yes, Carlos,
I am swapping on Pancakeswap.
BASE_CONTRACT is to interact with WBNB BEP20 contract to make allowance for Router to spend WBNB from ACCOUNT (which is the MM wallet)
ROUTER contract is to interact with Pancakeswap router contract, which has the SwapTokensToTokens method…
Could you suggest other workflow for this?

HI guy,
Problem solved with the help of Ivan. (thanks @ivan !)
The solution is :

  1. Approve for the Bot wallet the spend tokens from MM wallet.
  2. When time is come, use Bot wallet to move fund by “.transferFrom” method from MM wallet to Bot wallet.
  3. From Bot wallet, make swap with Pancake
  4. Transfer back new token to MM wallet.
    It works. But I most of time I still have some weird errors on swapExactTokensToTokens transaction with Pancakeswap, like “replacement transaction underpriced” or transaction is just pending (?) and never returned any receipt or error messages… I have check almost all possible reasons: gas fee is enough, BNB balance is enough, Tokens are approved and ready… I am working to solve this… But if you guys have any idea about the cause, help will be very much appreciated! Just hope that this is not caused by the Moralis server things :slight_smile:

bellow is part of the code where It stucked:

        try {
          var swapApproved = await RD_acc_BASE_CONTRACT.approve(
                      ROUTER_ADDR, routerAmountsOutBN[0], 
                      { 'gasLimit': gasLimit.toString(),
                        'gasPrice': gasPrice_weiBN
            }).then(async function(tx){
                  console.log(" approve: Transaction sent, TX: ",tx.hash);
                  receipt = await tx.wait();
                  console.log("Receipt = ",receipt)
                  return receipt;
        } catch(er) {console.log("RD_acc_BASE_CONTRACT.approve:",er)};
        alert("Waiting for Approval for Router to swap")

        // I added this after errors on NONCE TOO SMALL..
        var nonce = await provider.getTransactionCount(randomAddr,'pending')
        console.log("NONCE = ",nonce)

        try {
          var swap = await RD_acc_ROUTER_CONTRACT.swapExactTokensForTokens(
                      [BASE, TOKEN],
                      timeOutMinutes(10), //function to return + 1000*10*60
                      { 'nonce': nonce.toString(),
                        'gasLimit': swapGasLimit.toString(),
                        'gasPrice': gasPrice_weiBN
            }).then(async function(tx){
                  console.log("swapExactTokensForTokens:Transaction sent, TX: ",tx.hash);
                 // console logged out the tx hash and just hang forever at THIS POINT.....

                  receipt = await tx.wait();
                  console.log("Receipt = ",receipt)
                  return receipt;
        } catch(er) {console.log("swapExactTokensForTokens error:",er)};