Visual Builder has a lot of great built-in REST features that allow developers to fetch their data from a variety of sources and consume said data in their applications. However, what if you wanted to build an application that interacts with blockchain smart contracts? 

First things first: wallets are the primary client applications used to sign transactions on the blockchain. Although there are many wallets, I selected MetaMask; a wallet with capabilities of signing blockchain transactions on a wide variety of networks (although primarily intended for Ethereum). When paired with a special JavaScript library an application can utilize MetaMask to send & sign transactions to smart contracts. Let's go through how this is done.

In order to follow along you will need the following:

        pragma  solidity ^0.8.13;
         contract HelloWorld {
             string  public message;
            constructor(string  memory  _initMessage) {
                 message = _initMessage;
             }
             function  update(string  memory  _newMessage) public {
                 message = _newMessage;
             }}

        
 

Don't Want to Build It Yourself? No Problem!

You can download a fully working sample app `MetaMaskVBDemo` and import it into your own instance of Visual Builder. All you'll need to do is configure MetaMask, faucet some test ETH, and test away! 

Instructions:
Import into Visual Builder

Before we can begin building we need to do a couple if imports. First, we need to import our Ethers.js library. Within your application right click the resources folder and select 'Import'. Download then import this `ethers.js` file. Then we also need to download and import this `HelloWorld.json` file.

Create Frontend Components

Next create a frontend to interact with the deployed contract. My example has 2 main panels. Panel 1 shows if there is no wallet detected & contains a `Connect Wallet` button. Panel 2 contains buttons to both read & update the smart contract. The panels are configured via a `Bind If` and display according to whether or not a MetaMask account is connected to the application. There are also variables setup to store values from the form & from the contract.

Load Libraries & Write Javascript Functions

In this example there are 4 functions – 2 that interact MetaMask and 2 that interact with the smart contract. However before writing these functions, make sure to define & link to both the Ethers.js library, and the contract ABI file that were imported earlier.

    define(["resources/ethers.js",  'text!resources/contractabi.json'],  function(ethers,  abiString)

Then we set our contract address and parse the imported ABI file:

       const  contractAddress  =  "0x06A3F540004A2ba928fcba915D41fF32C084B57b";
       const  contractABI  =  JSON.parse(abiString).abi;

Now write the MetaMask functions:

  • checkIfWalletIsConnected()
    • This function utilizes MetaMask to see if a wallet is already connected with the application
PageModule.prototype.checkIfWalletIsConnected  =  async  function  ()  {
                try  {
                    const  {ethereum}  =  window;
                    if  (!ethereum)  {
                        console.log("Make sure you have metamask");
                    }  else  {
                    console.log("We have the ethereum object",  ethereum);
                    }
                    const  accounts  =  await  ethereum.request({method:  "eth_accounts"});
                    if  (accounts.length  !==  0)  {
                        const  account  =  accounts[0];
                        console.log("Found an authorized account",  account);
                        return  account;
                    }  else  {
                        console.log("No authorized account found");
                    }
                }  catch(error){
                    console.log(error);
                }};
  • connectWallet() –
    • This function tells MetaMask to connect a wallet to the application
PageModule.prototype.connectWallet = async function () { 
    try { 
      const {ethereum} = window; 
      if (!ethereum) {
         alert("Get MetaMask");
         return;
        } 
      const accounts = await ethereum.request({method: "eth_requestAccounts"}); 
      return accounts[0]; 
      } catch (error) {
      console.log(error); 
  }};

And for our Contract:

  • readContractString()
    • This function calls the contract's public `message()` function –  this is where the ethers.js library comes in when creating special provider, signer, & contract objects.
  PageModule.prototype.readContractString  =  async  function  ()  {
                try  {
                    const  {ethereum}  =  window;
                    if  (ethereum)  {
                        const  provider  =  new  ethers.providers.Web3Provider(ethereum);
                        const  signer  =  provider.getSigner();
                        const  contract  =  new  ethers.Contract(contractAddress,  contractABI,  signer);
                        let  response  =  await  contract.message();
                        return  response;
                    }
                }  catch  (error)  {
                    console.log(error);
                }
            };          
  • setContractString()
    • This function calls our contract's public `update()` function
PageModule.prototype.setContractString  =  async  function  (newString)  {
                try  {
                    const  {ethereum}  =  window;
                    if  (ethereum)  {
                            const  provider  =  new  ethers.providers.Web3Provider(ethereum);
                            const  signer  =  provider.getSigner();
                            const  contract  =  new  ethers.Contract(contractAddress,  contractABI,  signer);
                            let  response  =  await  contract.update(newString);
                            return  response;
                    }
                }  catch  (error)  {
                    console.log(error);
                }
            };    

Link Everything Together:

Now that the frontend & functions are defined, all that's left to do is tie everything together with some event listeners and action chains. For each of the buttons head over to the events tab and create a new `click` event and create a new action chain for each event. Within the action chain you will need to drag in the Call JS Function action into the chain and in the drop down select the corresponding function.

       

Make sure to assign the results of the call to the response variable. For the read function the example displays the contract string. For the set string function it returns the hash of the transaction.

     

Try It Out:

Everything is set up now you can hit the play button on the application. Test the wallet & contract. Head on over to Etherscan Rinkeby to track transactions as they occur.