Building Defi Dashboard (Zerion Clone) in 15 Minutes

After cloning the repo and following the tutorial, I was having difficulty displaying the Binance smart chain balances eventhough it was being rendered on the server database. The only ones working seem to be the Ethereum mainet and Polygon.

Im getting the following error:

moralis.js:29030 POST https://oid22tonbqqn.moralishost.com:2053/server/functions/getTokenPrice 400 moralis.js:29030

Uncaught (in promise) {code: 141, error: ‘[object Object]’} index.html:280

type or paste code here
<html>
  <head>
    <title>Cross Chain</title>
    <script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>
    <script src="https://unpkg.com/moralis/dist/moralis.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-U1DAWAznBHeqEIlVSCgzq+c9gqGAJn5c/t99JyeKa9xxaYpSvHU5awsuZVVFIhvj" crossorigin="anonymous"></script>
    <script src="https://unpkg.com/flickity@2/dist/flickity.pkgd.min.js"></script>
    <script src = "logic.js"></script>
    <link rel="stylesheet" href="styles.css">
    <link rel="stylesheet" href="https://unpkg.com/flickity@2/dist/flickity.min.css">
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" crossorigin="anonymous">
  </head>

  <body>
    <main>
      <div class="container" style="direction: rtl; padding-top: 10px;">
      <button id="btn-login">Moralis Metamask Login</button>
      <button id="btn-logout" style="display:none">Logout</button>
      <button id="btn-refresh" style="display:none">Refresh</button>
      <div style="display:inline"id="num"></div>
      </div>
      <div class="container">
          <div class="mt-2 mb-2">
             <h1>Cross Chain Wallet Dashboard
          </div>
          <hr>
          <div style="margin-bottom: 50px;">
               <div id="resultSpace"></div>
          </div>
          <div class="container chain">
            <img src="ETH.png" class="chainLogo"/>
            <div class="chainText">Ethereum Mainnet</div>
            <div class="row">
              <div class="col" id="ethTab">
              </div>
              <div class="col nftText">
                  NFTS
                  <div class="gallery js-flickity carousell" data-flickity-options='{ "wrapAround": true }'>
                      <div><img id="0eth" src="" class="nft"></div>
                      <div><img id="1eth" src="" class="nft"></div>
                      <div><img id="2eth" src="" class="nft"></div>
                  </div>
              </div>
          </div>
        </div>
        <div class="container chain">
          <img src="MATIC.png" class="chainLogo"/>
          <div class="chainText">Polygon</div>
          <div class="row">
            <div class="col"  id="polygonTab">
            </div>
            <div class="col nftText">
              NFTS
                <div class="gallery js-flickity carousell" data-flickity-options='{ "wrapAround": true }'>
                    <div><img src="" id="0polygon" class="nft"></div>
                    <div><img src="" id="1polygon" class="nft"></div>
                    <div><img src="" id="2polygon" class="nft"></div>
                </div>
            </div>
          </div>
        </div>
          <div class="container chain">
              <img src="BNB.png" class="chainLogo"/>
              <div class="chainText">Binance Smart Chain</div>
              <div class="row">
                <div class="col" id="bscTab">
                </div>
                <div class="col nftText">
                    NFTS
                    <div class="gallery js-flickity carousell" data-flickity-options='{ "wrapAround": true }'>
                        <div><img id="0bsc" src="" class="nft"></div>
                        <div><img id="1bsc" src="" class="nft"></div>
                        <div><img id="2bsc" src="" class="nft"></div>
                    </div>
                </div>
            </div>
          </div>
          <div class="container chain">
            <img src="AVAX.png" class="chainLogo"/>
            <div class="chainText">Avalanche Mainnet</div>
            <div class="row">
                <div class="col" id="avaxTab">
                </div>
                <div class="col nftText">
                    NFTS
                    <div class="gallery js-flickity carousell" data-flickity-options='{ "wrapAround": true }'>
                        <div><img src="" class="nft"></div>
                        <div><img src="" class="nft"></div>
                        <div><img src="" class="nft"></div>
                    </div>
                </div>
            </div>
          </div>
      </div>
      

  </main>

    <script>
        /** Connect to Moralis server */
        // Moralis.initialize("Sojukv0ZkWHJEo9pqURpjyzVQRoE5oSJ4vmVU8co");
        // Moralis.serverURL = "https://oid22tonbqqn.moralishost.com:2053/server";

        // const serverUrl = "https://oid22tonbqqn.moralishost.com:2053/server";
// const appId = "Sojukv0ZkWHJEo9pqURpjyzVQRoE5oSJ4vmVU8co";
// Moralis.start({ serverUrl, appId });


Moralis.start({ serverUrl: 'https://oid22tonbqqn.moralishost.com:2053/server',
appId: 'Sojukv0ZkWHJEo9pqURpjyzVQRoE5oSJ4vmVU8co' });

var web3;
checkWeb3();


function displayMessage(messageType, message){
    

    messages = {
        "00":`<div class= "alert alert-success"> ${message} </div>`,
        "01":`<div class= "alert alert-danger"> ${message} </div>`
    }
    
    document.getElementById("resultSpace").innerHTML = messages[messageType];
}

async function checkWeb3(){
    await Moralis.enableWeb3()
    const ethereum = window.ethereum;
    if(!ethereum || !ethereum.on) {
        displayMessage("01", "This App Requires MetaMask, Please Install MetaMask");
    }
    else{
        //displayMessage("00", "Metamask is Installed");
        setWeb3Environment()
    }
}

function setWeb3Environment(){
    
    web3 = new Web3(window.ethereum);
    getNetwork();
    monitorNetwork();
}

async function getNetwork(){
    await Moralis.enableWeb3()
    chainID = await web3.eth.getChainId()
    displayMessage("00","Active network is "+ getNetworkName(chainID));
}

function getNetworkName(chainID){
    
    networks = {
        1:"Ethereum Mainnet",
        43114:"Avalanche Mainnet",
        56:"Binance Smart Chain",
        137:"Polygon"
    }
    return networks[chainID];
}



function monitorNetwork(){
  
    Moralis.onChainChanged(function(){
        getNetwork()
    })
}



async function displayTokens(chn, chnSymbol, nativeAdd, nativeDecimals,dbRef, dbRefNative, htmlRef){
    await Moralis.enableWeb3()
    const query = new Moralis.Query(dbRef)
    query.equalTo("address", Moralis.User.current().get("ethAddress"))
    query.notEqualTo("balance", "0");
    const results = await query.find();

    const queryNative = new Moralis.Query(dbRefNative)
    queryNative.equalTo("address", Moralis.User.current().get("ethAddress"))
    const resultsNative = await queryNative.first();
    let nativePrice = {};
    let prices = [];

    if(chn != "avalanche"){
    nativePrice = await Moralis.Web3API.token.getTokenPrice({chain:chn, address: nativeAdd})
    prices = await Promise.all(results.map(async (e) =>
        await Moralis.Web3API.token.getTokenPrice({chain:chn, address: e.get("token_address")})
    ));}else{
    nativePrice = {usdPrice: 1};//set avax price
    prices = [{usdPrice: 1}]; //set avalanche chain token prices
    }
    

    let nativeBal = resultsNative.get("balance") / ("1e" + nativeDecimals);
    let nativePri = nativePrice.usdPrice;
    let table = '<table class="table">';
    table += `<thead><tr><th>Token</th><th>Amount</th><th>USD Value</th></tr></thead><tbody>`;
    table = table + `<tr>`;
    //Need to add token png images to directory for this to work
    table = table + `<td><img src="${chnSymbol}.png" class="tokens"/> ${chnSymbol} </td>`;
    table = table + `<td>${Math.round(nativeBal*100)/100}</td>`;
    table = table + `<td>$ ${Math.round(nativePri*nativeBal*100)/100}</td>`;
    table += `</tr>`;
    results.forEach((e,i) => {
        let bal = e.get("balance") / ("1e" + e.get("decimals"));
        let pri = prices[i].usdPrice
        table = table + `<tr>`;
        table = table + `<td><img src="${e.get("symbol")}.png" class="tokens"/> ${e.get("symbol")} </td>`;
        table = table + `<td>${Math.round(bal*100)/100}</td>`;
        table = table + `<td>$ ${Math.round(pri*bal*100)/100}</td>`;
        table += `</tr>`;
    });
    table += "</tbody></table>";
    document.getElementById(htmlRef).innerHTML = table;
}



async function displayNFTS(chn, dbRef){
    await Moralis.enableWeb3()
    const query = new Moralis.Query(dbRef)
    query.equalTo("owner_of", Moralis.User.current().get("ethAddress"))
    const results = await query.find();
    

    let images = await Promise.all(results.map(async (e) => 
        await Moralis.Web3API.token.getTokenIdMetadata({ address: e.get("token_address"), token_id: e.get("token_id"), chain: chn })
    ));
    

    if(chn == "bsc")
        images.forEach((e,i) =>{
            document.getElementById(i+chn).src = JSON.parse(e.metadata).nft.image;
            
    });else{
        images.forEach((e,i) =>{
            document.getElementById(i+chn).src = JSON.parse(e.metadata).image;
        });
    }
    
}


        
Moralis.start({ serverUrl: 'https://oid22tonbqqn.moralishost.com:2053/server',
appId: 'Sojukv0ZkWHJEo9pqURpjyzVQRoE5oSJ4vmVU8co' });


        async function login() {
          let user = Moralis.User.current();
          if (!user) {
            user = await Moralis.Web3.authenticate()
            .then(function (user) {
                console.log("logged in user:", user.get("ethAddress"));
                document.getElementById("num").innerHTML = user.get("ethAddress")
            })
          }
          document.getElementById("btn-logout").style = "display:inline";
          document.getElementById("btn-refresh").style = "display:inline";
          document.getElementById("btn-login").style = "display:none";


          await displayTokens("eth", "ETH", "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", 18,"EthTokenBalance", "EthBalance", "ethTab");
          await displayNFTS("eth", "EthNFTOwners");

          await displayTokens("polygon", "MATIC", "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270", 18,"PolygonTokenBalance", "PolygonBalance", "polygonTab");
          await displayNFTS("polygon", "PolygonNFTOwners");

          await displayTokens("bsc", "BNB", "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", 18,"BscTokenBalance", "BscBalance", "bscTab");
          await displayNFTS("bsc", "BscNFTOwners");

          await displayTokens("avalanche", "AVAX", "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7", 18,"AvaxTokenBalance", "AvaxBalance", "avaxTab");
          

          
        }

        async function logOut() {
            await Moralis.User.logOut();
            location.reload();
        }

        document.getElementById("btn-login").onclick = login;
        document.getElementById("btn-refresh").onclick = login;
        document.getElementById("btn-logout").onclick = logOut;
    </script>
  </body>
</html>

This is an example that works for BSC:

x = await Moralis.Web3API.token.getTokenPrice({address: “0xe9e7cea3dedca5984780bafc599bd69add087d56”, chain: “bsc”})

I wasn’t able to follow all that code, maybe there is a problem with the parameters that are used for bsc chain.

I keep getting an error when I run await displayTokens("bsc", "BNB", "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", 18,"BscTokenBalance", "BscBalance", "bscTab");
It is able to fetch all the token balances on the BSC but cannot render it on the table.error

The displayTokens function is below:

async function displayTokens(chn, chnSymbol, nativeAdd, nativeDecimals,dbRef, dbRefNative, htmlRef){
    await Moralis.enableWeb3()
    const query = new Moralis.Query(dbRef)
    query.equalTo("address", Moralis.User.current().get("ethAddress"))
    query.notEqualTo("balance", "0");
    const results = await query.find(); ///listing all tokens
    console.log(results)
    

    const queryNative = new Moralis.Query(dbRefNative)
    queryNative.equalTo("address", Moralis.User.current().get("ethAddress"))
    const resultsNative = await queryNative.first();
    let nativePrice = {};
    let prices = [];
    

    if(chn != "avalanche"){
    nativePrice = await Moralis.Web3API.token.getTokenPrice({chain:chn, address: nativeAdd})
 
    prices = await Promise.all(results.map(async (e) =>
        await Moralis.Web3API.token.getTokenPrice({chain:chn, address: e.get("token_address")})
        
       ))

}else{
    nativePrice = {usdPrice: 1};//set avax price
    prices = [{usdPrice: 1}];
    
    }
    

    let nativeBal = resultsNative.get("balance") / ("1e" + nativeDecimals);
    let nativePri = nativePrice.usdPrice;
    
    let table = '<table class="table">';
    table += `<thead><tr><th>Token</th><th>Amount</th><th>USD Value</th></tr></thead><tbody>`;
    table = table + `<tr>`;
    //Need to add token png images to directory for this to work
    table = table + `<td><img src="${chnSymbol}.png" class="tokens"/> ${chnSymbol} </td>`;
    table = table + `<td>${Math.round(nativeBal*100)/100}</td>`;
    table = table + `<td>$ ${Math.round(nativePri*nativeBal*100)/100}</td>`;
    table += `</tr>`;
    results.forEach((e,i) => {
        let bal = e.get("balance") / ("1e" + e.get("decimals"));
        let pri = prices[i].usdPrice
        // console.log(bal)
        // console.log(pri)
    
        table = table + `<tr>`;
        table = table + `<td><img src="${e.get("symbol")}.png" class="tokens"/> ${e.get("symbol")} </td>`;
        table = table + `<td>${Math.round(bal*100)/100}</td>`;
        table = table + `<td>$ ${Math.round(pri*bal*100)/100}</td>`;
        table += `</tr>`;
    });
    table += "</tbody></table>";
    document.getElementById(htmlRef).innerHTML = table;
}

it looks like this request in particular doesn’t work:

x = await Moralis.Web3API.token.getTokenPrice({address: “0xa6723237b51b7863303ab04c09ac27c8f42e095a”, chain: “bsc”})

and the reason is:

{
  "message": "No pools found with enough liquidity, to calculate the price"
}

Is there any way to walkaround this issue; and how was Jay able to render BNB
it on the youtube tutorial

what address do you query for price on bsc in that dashboard?
you could also add more logging to see what parameters you send to getTokenPrice function

I found that example that doesn’t work, but I’m not sure it is related to your dashboard problem.

You are correct.
All of the requests for the other contracts work but it doesn’t work for ‘0xa6723237b51b7863303ab04c09ac27c8f42e095a’. Is there anyway I can ignore it that address in particular. I tried removing in the Moralis database but that did not solve the issue.

I’m not familiar with the code, but it should be possible to add an if to skip it at least.