Ethereum Gas Programming and Estimation - use of await Moralis.enableWeb3()

I’ve just watched the latest youtube tutorial on Ethereum Gas Programming and Estimation and am looking at the logic.js code that handles the functionality for interacting with the contract and estimating gas fees:

const serverUrl = "";
const appId = "";
Moralis.start({ serverUrl, appId }); 

const storeSecretAddress = "";
const storeSecretABI = [...];


login();

async function login(){
    Moralis.Web3.enableWeb3().then(async function (){
        const chainIdHex = await Moralis.switchNetwork("0x2A");
    });
}

async function storeSecret() {
    const web3 = await Moralis.enableWeb3();
    const secretNumber = document.getElementById("secretNumber").value;
    const options = {
        contractAddress: storeSecretAddress,
        functionName: "storeSecret",
        abi: storeSecretABI,
        params: {
          _newSecret: secretNumber
        },
      };
    const receipt = await Moralis.executeFunction(options);
    window.alert("operation concluded with hash " + receipt["transactionHash"]);
};


async function estimate() {
    const web3 = await Moralis.enableWeb3();
    const secretNumber = document.getElementById("secretNumber").value;
    const storeContract = await new web3.eth.Contract(storeSecretABI,storeSecretAddress)
    const estimatedGas = await storeContract.methods.storeSecret(secretNumber).estimateGas({from:ethereum.selectedAddress})
    document.getElementById("estimatedGas").value = estimatedGas;
}

In this code, the call Moralis.enableWeb3(); occurs in three different places - within each of the three functions - login(), storeSecret(), and estimate().

My question is, why is the code written in a way that includes this call within each function?

Is it possible to set a global let web3 variable at the beginning of the script that gets populated one time during the login() function, and not again? For example:

let web3; 

login();

async function login(){
    web3 = await Moralis.Web3.enableWeb3();
    const chainIdHex = await Moralis.switchNetwork("0x2A");
}

Or, is it a regular practice to define a new Moralis.enableWeb3() instance within each function?

Further, the first three lines of the script aren’t necessary at all, correct?

const serverUrl = "";
const appId = "";
Moralis.start({ serverUrl, appId }); 

These lines would be necessary if interacting with the Moralis server. However, the script’s three functions are only using the functionality from the web3 instance provided through Moralis. So there is no server functionality required.

Running the tutorial website with these first three lines removed performs as expected.

Good observation. Actually is a matter of preference. I tend to avoid Global variables.

In this case, nonetheless, having the web3 object in memory might help with better performance. I have made the web3 instance a global in other projects. But then again, I think it is a matter of preference.

This way kind of highlights the need to have an active web3 instance, which is very obvious in the estimate() function, but is also needed in the storeSecret() where the implementation is more abstracted and the web3 instance though needed is not specifically called in the code.

You are right.

In this case, specifically, It is not necessary to have a moralis account or server. You could use the SDK functions mentioned in the project without creating a server.

I, however, in all my projects tend to leave those as a boilerplate, mostly for convenience if people later on needs to expand their daps. Having a server gives you access to a complete experience with the Moralis Web3 API, and also offers you a place readily available to collect data from users. The SDK without initializing offers a very limited experience.

In this lab for example you could have synced the events from the contract to get the gas estimations on-chain in your database. I didn’t cover that to keep the video length below 40 minutes.

Thanks for both responses, they make sense to me. I can see why you structured the code and included the account/server information.

This clears up some questions I had as someone just getting into Moralis.

One more question:

The logic.js code prompts the user to switch their MetaMask wallet to the Kovan Network when the page first loads.

What happens if the user cancels this request and doesn’t change to Kovan, or accepts, but then manually changes their network to something else right afterward?

This would result in an attempt to create a transaciton on that network, using the logic in the storeSecret() function. Which would likely error out if there isn’t the same Secret_store.sol contract on that network at the same address.

Is there any way to check that the user is connected to the requried network before a transaction is requested (ie. Moralis.executeFunction())?

Check this part:
https://docs.moralis.io/moralis-server/web3/web3#events
And research web3.eth.net.getId():
With these two pieces you can do any network management you might need. This is bit out of topic for this video, but researching the two elements above you can figure it out according to your use case.