Building DEX: Moralis Login error

I am now following the video of “Moralis Login” of Building DEX. When I click the “Moralis Login” button, console said
“Uncaught (in promise) Error: You need to call Moralis.start with an applicationId before using Moralis.
at Object.generatePath (moralis.js:26884:13)
at Object.currentUser (moralis.js:25520:33)
at Function.value (moralis.js:24944:25)
at HTMLButtonElement.login (dex.js:7:29)”

Attached is the photo:

I have already installed MEtamask in my Chrome. WHat should I do?

Below is my code:
Javascript

// connect to Moralis server
const serverUrl = "https://j9tck2jtuezz.usemoralis.com:2053/server";
const appId = "YqqTSiKo1qxsHpSngDUrJX1l4VtsqgEXrTp7JYRM";

 // add from here down
 async function login() {
    let user = Moralis.User.current();
    if (!user) {
      user = await Moralis.authenticate();
    }
    console.log("logged in user:", user);
  }

  async function logout() {
    await Moralis.User.logOut();
    console.log("logged out");
  }

  document.getElementById("btn-login").addEventListener('click', login);
  document.getElementById("btn-logout").addEventListener('click', logout);

async function getTop10Tokens() {
    const response = await fetch('https://api.coinpaprika.com/v1/coins');
    const tokens = await response.json();
    
    return tokens
            .filter(token => token.rank >= 1 && token.rank <= 30)
            .map(token => token.symbol);
}
    
async function getTickerData(tickerList) {
    const response = await fetch('https://api.1inch.exchange/v3.0/137/tokens');
    const tokens = await response.json();
    const tokenList = Object.values(tokens.tokens);
    
    return tokenList.filter(token => tickerList.includes(token.symbol));
}

getTop10Tokens()
    .then(getTickerData)
    .then(console.log);

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Moralis DEX</title>
</head>
<body>

    <button id="btn-login">Moralis Login</button>
    <button id="btn-logout">Logout</button>
    <!-- Moralis SDK code -->
    <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="./dex.js"></script>

    <script>
      // connect to Moralis server
      const serverUrl = "https://j9tck2jtuezz.usemoralis.com:2053/server";
      const appId = "YqqTSiKo1qxsHpSngDUrJX1l4VtsqgEXrTp7JYRM";
      Moralis.start({ serverUrl, appId });
    </script>
</body>
</html>

Attached below shows there should be a small window popping up after we click “moralis login” button. But mine doesn’t show up like that and console said error.

In your js file, you have your server url and appId, but you have not started moralis.

        Moralis.start({
          serverUrl,
          appId,
        })

Carlos Z

Thanks a lot for the reply!!

I have just added that in my js file. But it still has no small window popping up to login. And now it shows a different error. It said “Uncaught SyntaxError: Unexpected token ‘<’”. I can’t find which “<” is redundant. Below is my screenshot:

Below are my codes:
js

// connect to Moralis server
const serverUrl = "https://j9tck2jtuezz.usemoralis.com:2053/server";
const appId = "YqqTSiKo1qxsHpSngDUrJX1l4VtsqgEXrTp7JYRM";
Moralis.start({ serverUrl, appId, });

Moralis
    .initPlugins()
    .then(() => console.log('Plugins have been initialized'));

const $tokenBalanceTBody = document.querySelector('.js-token-balances');
const $selectedToken = document.querySelector('.js-from-token');
const $amountInput = document.querySelector('js-from-amount');

/**Utilities */
//Converting from Wei using custom function
const tokenValue = (value, decimals) =>
    (decimals ? value / Math.pow(10, decimals) : value);

/** Login-logout and initialization*/
// add from here down
async function login() {
    let user = Moralis.User.current();
    if (!user) {
      user = await Moralis.authenticate();
    }
    console.log("logged in user:", user);
    getStats();
}


async function initSwapForm(event) {
    event.preventDefault();
    $selectedToken.innerText = event.target.dataset.symbol;
    $selectedToken.dataset.address = event.target.dataset.address;
    $selectedToken.dataset.decimals = event.target.dataset.decimals;
    $selectedToken.dataset.max = event.target.dataset.max;
    $amountInput.removeAttribute('disabled');
    $amountInput.value = '';
    document.querySelector('.js-submit').removeAttribute('disabled');
    document.querySelector('.js-cancel').removeAttribute('disabled');
    document.querySelector('.js-quote-container').innerHTML = '';
    document.querySelector('.js-amount-error').innerText = '';
}

async function getStats() {
    const balances = await Moralis.Web3API.account.getTokenBalances({chain: 'polygon'});
    console.log(balances);
    $tokenBalanceTBody.innerHTML = balances.map( (token, index) =>
        <tr>
            <td>${index + 1}</td>
            <td>${token.symbol}</td>
            <td>${tokenValue(token.balance, token.decimals)}</td>
            <td>
                <button
                    class="js-swap btn btn-success"
                    data-address="${token.token_address}"
                    data-symbol="${token.symbol}"
                    data-decimals="${token.decimals}"
                    data-max="${tokenValue(token.balance, token.decimals)}"
                >
                    Swap
                </button>
            </td>
        </tr>    
    ).join('');

    for (let $btn of $tokenBalanceTBody.querySelectorAll('.js-swap')) {
        $btn.addEventListener('click', initSwapForm);
    }

}

async function buyCrypto() {
    Moralis.Plugins.fiat.buy();
}

async function logout() {
    await Moralis.User.logOut();
    console.log("logged out");
}

document.getElementById("btn-login").addEventListener('click', login);
document
    .getElementById("btn-buy-crypto")
    .addEventListener('click', buyCrypto);
document.getElementById("btn-logout").addEventListener('click', logout);

/** Quote / Swap */
async function formSubmitted(event) {
    event.preventDefault();
    const fromAmount = Number.parseFloat( $amountInput.value );
    const fromMaxValue = Number.parseFloat( $selectedToken.dataset.max );
    debugger;
    if (Number.isNaN(fromAmount) || fromAmount > fromMaxValue) {
        //invalid input
        document.querySelector('.js-amount-error').innerText = 'Invalid amount';
        return;
    } else {
        document.querySelector('.js-amount-error').innerText = '';
    }

    // Submission of the quote request
    const fromDecimals = $selectedToken.dataset.decimals;
    const fromTokenAddress = $selectedToken.dataset.address;

    const [toTokenAddress, toDecimals] = document.querySelector('[name=to-token]').value.split('-');

    try {
        const quote = await Moralis.Plugins.oneInch.quote({
            chain: 'polygon', // The blockchain you want to use (eth/bsc/polygon)
            fromTokenAddress: fromTokenAddress, // The token you want to swap
            toTokenAddress: toTokenAddress, // The token you want to receive
            amount: Moralis.Units.Token(fromAmount, fromDecimals).toString(),
        });
        
        const toAmount = tokenValue(quote.toTokenAmount, toDecimals);
        document.querySelector('.js-quote-container').innerHTML =
            <p>
                ${fromAmount} ${quote.fromToken.Symbol} = 
                ${toAmount} ${quote.toToken.Symbol}
            </p>
            <p>
                Gas fee: ${quote.estimatedGas}
            </p>
            <button class="btn btn-success">Perform swap</button>
        ;
        
    } catch(e) {
        document.querySelector('.js-quote-container').innerHTML =
            <p class="error">The conversion didn't succeed.</p>
        ;
    }

}

async function formCanceled(event) {
    event.preventDefault();
    document.querySelector('.js-submit').setAttribute('disabled', '');
    document.querySelector('.js-cancel').setAttribute('disabled', '');
    $amountInput.value = '';
    $amountInput.setAttribute('disabled', '');
    delete $selectedToken.dataset.address;
    delete $selectedToken.dataset.decimals;
    delete $selectedToken.dataset.max;
    document.querySelector('.js-quote-container').innerHTML = '';
    document.querySelector('.js-amount-error').innerText = '';
}

document.querySelector('.js-submit').addEventListener('click', formSubmitted);
document.querySelector('.js-cancel').addEventListener('click', formCanceled);

/** To token dropdown preparation*/
async function getTop10Tokens() {
    const response = await fetch('https://api.coinpaprika.com/v1/coins');
    const tokens = await response.json();
    
    return tokens
            .filter(token => token.rank >= 1 && token.rank <= 30)
            .map(token => token.symbol);
    }
    
    async function getTickerData(tickerList) {
        const tokens = await Moralis.Plugins.oneInch.getSupportedTokens({
            chain: 'polgygon', // The blockchain you want to use (eth/bsc/polygon)
         });
        const tokenList = Object.values(tokens.tokens);
    
        return tokenList.filter(token => tickerList.includes(token.symbol));
    }

function renderTokenDropdown() {
    const options = tokens.map(token =>
        <option value="${token.address}-${token.decimals}">
            ${token.name}
        </option>
    ).join('');
    document.querySelector('[name-to-token]').innerHTML = options;
}

getTop10Tokens()
    .then(getTickerData)
    .then(renderTokenDropdown);

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Moralis DEX</title>
    <!-- CSS only -->
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-12 col-md-6">
                <h1>MoralisSwap</h1>
            </div>
            <div class="col-12 col-md-6 d-flex align-items-center justify-content-md-center">
                <button class="btn btn-success btn-sm" id="btn-login">Moralis Login</button>
                <button class="btn btn-success btn-sm" id="btn-buy-crypto">Buy Crypto</button>
                <button class="btn btn-danger btn-sm" id="btn-logout">Logout</button>    
            </div>
        </div>
    
        <table class="table table-dark table-striped">
            <thread>
                <tr>
                    <th>#</th>
                    <th>Symbol</th>
                    <th>Amount</th>
                    <th>Action</th>
                </tr>
            </thread>
            <tbody class="js-token-balances"></tbody>
        </table>
    
        <form action="#" method="POST" class="exchange-form">
            <div class="row">
                <div class="col-12 col-md-6 mb-2">
                    <label>
                        <span class="js-from-token"></span>
                        Amount:
                        <input type="text" name="from-amount" class="js-from-amount" disabled />
                    </label>
                    <div class="js-amount-error error"></div>
                </div>
                <div class="col-12 col-md-6">
                    <label>
                        Swap to:
                        <select name="to-token"></select>
                    </label>
                </div>
            </div>
            <div class="row">
                <div class="col">
                    <button type="submit" class="js-submit btn btn-success btn-sm" disabled>Get Quote</button>
                    <button class="js-cancel btn btn-warning btn-sm" disabled>Cancel</button>
                </div>
            </div>
            <div class="js-quote-container"></div>
        </form>
    </div>

   

    <!-- Moralis SDK code -->
    <script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>
    <script src="https://unpkg.com/moralis/dist/moralis.js"></script>
    <!-- JavaScript Bundle with Popper -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2" crossorigin="anonymous"></script>
    <script src="./dex.js"></script>

    <script>
      // connect to Moralis server
        const serverUrl = "https://j9tck2jtuezz.usemoralis.com:2053/server";
        const appId = "YqqTSiKo1qxsHpSngDUrJX1l4VtsqgEXrTp7JYRM";
        Moralis.start({ serverUrl, appId, });
    </script>
</body>
</html>

CSS

.error {
    color: darkred
}

body {
    background-color: black;
    color: whitesmoke;
}

.btn-sm {
    margin: 8px;
}

Also, in my JS. I don’t know why it underlines line 119-125, which has the code below:

 <p>
                ${fromAmount} ${quote.fromToken.Symbol} = 
                ${toAmount} ${quote.toToken.Symbol}
            </p>
            <p>
                Gas fee: ${quote.estimatedGas}
            </p>
            <button class="btn btn-success">Perform swap</button>

May I know why please?
Below is the photo showing the codes being underlined.

I would appreciate your help!!

Its the same issue from this answer

Carlos Z

1 Like

Thanks a lot for the reply!! I have already add the curvy quotes. But I still have some problems.

The “get quote” and “cancel” button are disabled. I have check my lines of “.removeAttribute(‘disabled’);”. But I can’t find the problem.

Also, when I click “Moralis Login”, it has no response. :weary: :weary: :weary:

Can u help me see what’re the problems please? Also, can u help me with reviewing to see if there’re any other flaws in my codes please?

I would appreciate your help!!

1 Like

I replied the other topic where you have the issue with the form submission, we can continue to fix your code in that topic :nerd_face:

Carlos Z

Thanks for the reply! I have fixed it but still no window popping out and no response when I click “Moralis Login”. :slightly_frowning_face:
Can u see what are the other problems?

Here’s my code:

// connect to Moralis server
const serverUrl = "https://j9tck2jtuezz.usemoralis.com:2053/server";
const appId = "YqqTSiKo1qxsHpSngDUrJX1l4VtsqgEXrTp7JYRM";
Moralis.start({ serverUrl, appId, });

Moralis
    .initPlugins()
    .then(() => console.log('Plugins have been initialized'));

const $tokenBalanceTBody = document.querySelector('.js-token-balances');
const $selectedToken = document.querySelector('.js-from-token');
const $amountInput = document.querySelector('js-from-amount');

/**Utilities */
//Converting from Wei using custom function
const tokenValue = (value, decimals) =>
    (decimals ? value / Math.pow(10, decimals) : value);

/** Login-logout and initialization*/
// add from here down
async function login() {
    let user = Moralis.User.current();
    if (!user) {
      user = await Moralis.authenticate();
    }
    console.log("logged in user:", user);
    getStats();
}


async function initSwapForm(event) {
    event.preventDefault();
    $selectedToken.innerText = event.target.dataset.symbol;
    $selectedToken.dataset.address = event.target.dataset.address;
    $selectedToken.dataset.decimals = event.target.dataset.decimals;
    $selectedToken.dataset.max = event.target.dataset.max;
    $amountInput.removeAttribute('disabled');
    $amountInput.value = '';
    document.querySelector('.js-submit').removeAttribute('disabled');
    document.querySelector('.js-cancel').removeAttribute('disabled');
    document.querySelector('.js-quote-container').innerHTML = '';
    document.querySelector('.js-amount-error').innerText = '';
}

async function getStats() {
    const balances = await Moralis.Web3API.account.getTokenBalances({chain: 'polygon'});
    console.log(balances);
    $tokenBalanceTBody.innerHTML = balances.map( (token, index) =>
        <tr>
            <td>${index + 1}</td>
            <td>${token.symbol}</td>
            <td>${tokenValue(token.balance, token.decimals)}</td>
            <td>
                <button
                    class="js-swap btn btn-success"
                    data-address="${token.token_address}"
                    data-symbol="${token.symbol}"
                    data-decimals="${token.decimals}"
                    data-max="${tokenValue(token.balance, token.decimals)}"
                >
                    Swap
                </button>
            </td>
        </tr>    
    ).join('');

    for (let $btn of $tokenBalanceTBody.querySelectorAll('.js-swap')) {
        $btn.addEventListener('click', initSwapForm);
    }

}

async function buyCrypto() {
    Moralis.Plugins.fiat.buy();
}

async function logout() {
    await Moralis.User.logOut();
    console.log("logged out");
}

document.getElementById("btn-login").addEventListener('click', login);
document
    .getElementById("btn-buy-crypto")
    .addEventListener('click', buyCrypto);
document.getElementById("btn-logout").addEventListener('click', logout);

/** Quote / Swap */
async function formSubmitted(event) {
    event.preventDefault();
    const fromAmount = Number.parseFloat( $amountInput.value );
    const fromMaxValue = Number.parseFloat( $selectedToken.dataset.max );
    debugger;
    if (Number.isNaN(fromAmount) || fromAmount > fromMaxValue) {
        //invalid input
        document.querySelector('.js-amount-error').innerText = 'Invalid amount';
        return;
    } else {
        document.querySelector('.js-amount-error').innerText = '';
    }

    // Submission of the quote request
    const fromDecimals = $selectedToken.dataset.decimals;
    const fromTokenAddress = $selectedToken.dataset.address;

    const [toTokenAddress, toDecimals] = document.querySelector('[name=to-token]').value.split('-');

    try {
        const quote = await Moralis.Plugins.oneInch.quote({
            chain: 'polygon', // The blockchain you want to use (eth/bsc/polygon)
            fromTokenAddress: fromTokenAddress, // The token you want to swap
            toTokenAddress: toTokenAddress, // The token you want to receive
            amount: Moralis.Units.Token(fromAmount, fromDecimals).toString(),
        });
        
        const toAmount = tokenValue(quote.toTokenAmount, toDecimals);
        document.querySelector('.js-quote-container').innerHTML = `
            <p>
                ${fromAmount} ${quote.fromToken.Symbol} = 
                ${toAmount} ${quote.toToken.Symbol}
            </p>
            <p>
                Gas fee: ${quote.estimatedGas}
            </p>
            <button class="btn btn-success">Perform swap</button>
        `;
        
    } catch(e) {
        document.querySelector('.js-quote-container').innerHTML =
            <p class="error">The conversion didn't succeed.</p>
        ;
    }

}

async function formCanceled(event) {
    event.preventDefault();
    document.querySelector('.js-submit').setAttribute('disabled', '');
    document.querySelector('.js-cancel').setAttribute('disabled', '');
    $amountInput.value = '';
    $amountInput.setAttribute('disabled', '');
    delete $selectedToken.dataset.address;
    delete $selectedToken.dataset.decimals;
    delete $selectedToken.dataset.max;
    document.querySelector('.js-quote-container').innerHTML = '';
    document.querySelector('.js-amount-error').innerText = '';
}

document.querySelector('.js-submit').addEventListener('click', formSubmitted);
document.querySelector('.js-cancel').addEventListener('click', formCanceled);

/** To token dropdown preparation*/
async function getTop10Tokens() {
    const response = await fetch('https://api.coinpaprika.com/v1/coins');
    const tokens = await response.json();
    
    return tokens
            .filter(token => token.rank >= 1 && token.rank <= 30)
            .map(token => token.symbol);
    }
    
    async function getTickerData(tickerList) {
        const tokens = await Moralis.Plugins.oneInch.getSupportedTokens({
            chain: 'polgygon', // The blockchain you want to use (eth/bsc/polygon)
         });
        const tokenList = Object.values(tokens.tokens);
    
        return tokenList.filter(token => tickerList.includes(token.symbol));
    }

function renderTokenDropdown() {
    const options = tokens.map(token =>
        <option value="${token.address}-${token.decimals}">
            ${token.name}
        </option>
    ).join('');
    document.querySelector('[name=to-token]').innerHTML = options;
}

getTop10Tokens()
    .then(getTickerData)
    .then(renderTokenDropdown);
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Moralis DEX</title>
    <!-- CSS only -->
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
    <link rel="stylesheet" href="./style.css">
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-12 col-md-6">
                <h1>MoralisSwap</h1>
            </div>
            <div class="col-12 col-md-6 d-flex align-items-center justify-content-md-center">
                <button class="btn btn-success btn-sm" id="btn-login">Moralis Login</button>
                <button class="btn btn-success btn-sm" id="btn-buy-crypto">Buy Crypto</button>
                <button class="btn btn-danger btn-sm" id="btn-logout">Logout</button>    
            </div>
        </div>
    
        <table class="table table-dark table-striped">
            <thread>
                <tr>
                    <th>#</th>
                    <th>Symbol</th>
                    <th>Amount</th>
                    <th>Action</th>
                </tr>
            </thread>
            <tbody class="js-token-balances"></tbody>
        </table>
    
        <form action="#" method="POST" class="exchange-form">
            <div class="row">
                <div class="col-12 col-md-6 mb-2">
                    <label>
                        <span class="js-from-token"></span>
                        Amount:
                        <input type="text" name="from-amount" class="js-from-amount" disabled />
                    </label>
                    <div class="js-amount-error error"></div>
                </div>
                <div class="col-12 col-md-6">
                    <label>
                        Swap to:
                        <select name="to-token"></select>
                    </label>
                </div>
            </div>
            <div class="row">
                <div class="col">
                    <button type="submit" class="js-submit btn btn-success btn-sm" disabled>Get Quote</button>
                    <button class="js-cancel btn btn-warning btn-sm" disabled>Cancel</button>
                </div>
            </div>
            <div class="js-quote-container"></div>
        </form>
    </div>

   

    <!-- Moralis SDK code -->
    <script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>
    <script src="https://unpkg.com/moralis/dist/moralis.js"></script>
    <!-- JavaScript Bundle with Popper -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2" crossorigin="anonymous"></script>
    <script src="./dex.js"></script>

    <script>
      // connect to Moralis server
        const serverUrl = "https://j9tck2jtuezz.usemoralis.com:2053/server";
        const appId = "YqqTSiKo1qxsHpSngDUrJX1l4VtsqgEXrTp7JYRM";
        Moralis.start({ serverUrl, appId, });
    </script>
</body>
</html>
.error {
    color: darkred
}

body {
    background-color: black;
    color: whitesmoke;
}

.btn-sm {
    margin: 8px;
}

It’s still saying “dex.js:49 Uncaught SyntaxError: Unexpected token ‘<’” as below

check code line 49 at dex.js, you might have an incorrect type there :eyes:

Carlos Z

My line 49 is “” as attached in my photo below. I can’t see anything wrong when matching it with your code in https://github.com/Ivan-on-Tech-Academy/js-prog-course-2021/blob/main/dex.js

Can u see what’s the problem please?

1 Like

The content of the function should be returned on curvy quotes ``

Like this:

    $tokenBalanceTBody.innerHTML = balances.map((token, index) => `
        <tr>
            <td>${index + 1}</td>
            <td>${token.symbol}</td>
            <td>${Moralis.Units.FromWei(token.balance, token.decimals)}</td>
            <td>
                <button
                    class="js-swap btn btn-success"
                    data-address="${token.token_address}"
                    data-symbol="${token.symbol}"
                    data-decimals="${token.decimals}"
                    data-max="${Moralis.Units.FromWei(token.balance, token.decimals)}"
                >
                Swap
                </button>
            </td>
        </tr>
    `).join('');

Carlos Z

1 Like

Thanks so much for the reply! I have already add the curvy quotes, and also add other curvy quotes that I had missed. Now it is showing error as below:
“Uncaught SyntaxError: Identifier ‘serverUrl’ has already been declared (at index.html:73:13)
dex.js:8 Plugins have been initialized”
“Uncaught (in promise) TypeError: Cannot convert undefined or null to object
at Function.values ()
at getTickerData (dex.js:166:34)
getTickerData @ dex.js:166
Promise.then (async)
(anonymous) @ dex.js:182”

Below are my codes:

// connect to Moralis server
const serverUrl = "https://j9tck2jtuezz.usemoralis.com:2053/server";
const appId = "YqqTSiKo1qxsHpSngDUrJX1l4VtsqgEXrTp7JYRM";
Moralis.start({ serverUrl, appId, });

Moralis
    .initPlugins()
    .then(() => console.log('Plugins have been initialized'));

const $tokenBalanceTBody = document.querySelector('.js-token-balances');
const $selectedToken = document.querySelector('.js-from-token');
const $amountInput = document.querySelector('js-from-amount');

/**Utilities */
//Converting from Wei using custom function
const tokenValue = (value, decimals) =>
    (decimals ? value / Math.pow(10, decimals) : value);

/** Login-logout and initialization*/
// add from here down
async function login() {
    let user = Moralis.User.current();
    if (!user) {
      user = await Moralis.authenticate();
    }
    console.log("logged in user:", user);
    getStats();
}


async function initSwapForm(event) {
    event.preventDefault();
    $selectedToken.innerText = event.target.dataset.symbol;
    $selectedToken.dataset.address = event.target.dataset.address;
    $selectedToken.dataset.decimals = event.target.dataset.decimals;
    $selectedToken.dataset.max = event.target.dataset.max;
    $amountInput.removeAttribute('disabled');
    $amountInput.value = '';
    document.querySelector('.js-submit').removeAttribute('disabled');
    document.querySelector('.js-cancel').removeAttribute('disabled');
    document.querySelector('.js-quote-container').innerHTML = '';
    document.querySelector('.js-amount-error').innerText = '';
}

async function getStats() {
    const balances = await Moralis.Web3API.account.getTokenBalances({chain: 'polygon'});
    console.log(balances);
    $tokenBalanceTBody.innerHTML = balances.map( (token, index) => `
        <tr>
            <td>${index + 1}</td>
            <td>${token.symbol}</td>
            <td>${tokenValue(token.balance, token.decimals)}</td>
            <td>
                <button
                    class="js-swap btn btn-success"
                    data-address="${token.token_address}"
                    data-symbol="${token.symbol}"
                    data-decimals="${token.decimals}"
                    data-max="${tokenValue(token.balance, token.decimals)}"
                >
                    Swap
                </button>
            </td>
        </tr>    
    `).join('');

    for (let $btn of $tokenBalanceTBody.querySelectorAll('.js-swap')) {
        $btn.addEventListener('click', initSwapForm);
    }

}

async function buyCrypto() {
    Moralis.Plugins.fiat.buy();
}

async function logout() {
    await Moralis.User.logOut();
    console.log("logged out");
}

document.getElementById("btn-login").addEventListener('click', login);
document
    .getElementById("btn-buy-crypto")
    .addEventListener('click', buyCrypto);
document.getElementById("btn-logout").addEventListener('click', logout);

/** Quote / Swap */
async function formSubmitted(event) {
    event.preventDefault();
    const fromAmount = Number.parseFloat( $amountInput.value );
    const fromMaxValue = Number.parseFloat( $selectedToken.dataset.max );
    debugger;
    if (Number.isNaN(fromAmount) || fromAmount > fromMaxValue) {
        //invalid input
        document.querySelector('.js-amount-error').innerText = 'Invalid amount';
        return;
    } else {
        document.querySelector('.js-amount-error').innerText = '';
    }

    // Submission of the quote request
    const fromDecimals = $selectedToken.dataset.decimals;
    const fromTokenAddress = $selectedToken.dataset.address;

    const [toTokenAddress, toDecimals] = document.querySelector('[name=to-token]').value.split('-');

    try {
        const quote = await Moralis.Plugins.oneInch.quote({
            chain: 'polygon', // The blockchain you want to use (eth/bsc/polygon)
            fromTokenAddress: fromTokenAddress, // The token you want to swap
            toTokenAddress: toTokenAddress, // The token you want to receive
            amount: Moralis.Units.Token(fromAmount, fromDecimals).toString(),
        });
        
        const toAmount = tokenValue(quote.toTokenAmount, toDecimals);
        document.querySelector('.js-quote-container').innerHTML = `
            <p>
                ${fromAmount} ${quote.fromToken.Symbol} = 
                ${toAmount} ${quote.toToken.Symbol}
            </p>
            <p>
                Gas fee: ${quote.estimatedGas}
            </p>
            <button class="btn btn-success">Perform swap</button>
        `;
        
    } catch(e) {
        document.querySelector('.js-quote-container').innerHTML = `
            <p class="error">The conversion didn't succeed.</p>
        `;
    }

}

async function formCanceled(event) {
    event.preventDefault();
    document.querySelector('.js-submit').setAttribute('disabled', '');
    document.querySelector('.js-cancel').setAttribute('disabled', '');
    $amountInput.value = '';
    $amountInput.setAttribute('disabled', '');
    delete $selectedToken.dataset.address;
    delete $selectedToken.dataset.decimals;
    delete $selectedToken.dataset.max;
    document.querySelector('.js-quote-container').innerHTML = '';
    document.querySelector('.js-amount-error').innerText = '';
}

document.querySelector('.js-submit').addEventListener('click', formSubmitted);
document.querySelector('.js-cancel').addEventListener('click', formCanceled);

/** To token dropdown preparation*/
async function getTop10Tokens() {
    const response = await fetch('https://api.coinpaprika.com/v1/coins');
    const tokens = await response.json();
    
    return tokens
            .filter(token => token.rank >= 1 && token.rank <= 30)
            .map(token => token.symbol);
    }
    
    async function getTickerData(tickerList) {
        const tokens = await Moralis.Plugins.oneInch.getSupportedTokens({
            chain: 'polgygon', // The blockchain you want to use (eth/bsc/polygon)
         });
        const tokenList = Object.values(tokens.tokens);
    
        return tokenList.filter(token => tickerList.includes(token.symbol));
    }

function renderTokenDropdown() {
    const options = tokens.map(token => `
        <option value="${token.address}-${token.decimals}">
            ${token.name}
        </option>
    `).join('');
    document.querySelector('[name=to-token]').innerHTML = options;
}

getTop10Tokens()
    .then(getTickerData)
    .then(renderTokenDropdown);
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Moralis DEX</title>
    <!-- CSS only -->
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
    <link rel="stylesheet" href="./style.css">
</head>
<body>
    <div class="container">
        <div class="row">
            <div class="col-12 col-md-6">
                <h1>MoralisSwap</h1>
            </div>
            <div class="col-12 col-md-6 d-flex align-items-center justify-content-md-center">
                <button class="btn btn-success btn-sm" id="btn-login">Moralis Login</button>
                <button class="btn btn-success btn-sm" id="btn-buy-crypto">Buy Crypto</button>
                <button class="btn btn-danger btn-sm" id="btn-logout">Logout</button>    
            </div>
        </div>
    
        <table class="table table-dark table-striped">
            <thread>
                <tr>
                    <th>#</th>
                    <th>Symbol</th>
                    <th>Amount</th>
                    <th>Action</th>
                </tr>
            </thread>
            <tbody class="js-token-balances"></tbody>
        </table>
    
        <form action="#" method="POST" class="exchange-form">
            <div class="row">
                <div class="col-12 col-md-6 mb-2">
                    <label>
                        <span class="js-from-token"></span>
                        Amount:
                        <input type="text" name="from-amount" class="js-from-amount" disabled />
                    </label>
                    <div class="js-amount-error error"></div>
                </div>
                <div class="col-12 col-md-6">
                    <label>
                        Swap to:
                        <select name="to-token"></select>
                    </label>
                </div>
            </div>
            <div class="row">
                <div class="col">
                    <button type="submit" class="js-submit btn btn-success btn-sm" disabled>Get Quote</button>
                    <button class="js-cancel btn btn-warning btn-sm" disabled>Cancel</button>
                </div>
            </div>
            <div class="js-quote-container"></div>
        </form>
    </div>

   

    <!-- Moralis SDK code -->
    <script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>
    <script src="https://unpkg.com/moralis/dist/moralis.js"></script>
    <!-- JavaScript Bundle with Popper -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2" crossorigin="anonymous"></script>
    <script src="./dex.js"></script>

    <script>
      // connect to Moralis server
        const serverUrl = "https://j9tck2jtuezz.usemoralis.com:2053/server";
        const appId = "YqqTSiKo1qxsHpSngDUrJX1l4VtsqgEXrTp7JYRM";
        Moralis.start({ serverUrl, appId, });
    </script>
</body>
</html>
.error {
    color: darkred
}

body {
    background-color: black;
    color: whitesmoke;
}

.btn-sm {
    margin: 8px;
}

May I know what are other flaws of my codes please? I would appreciate your help.

At the getTickerData function, you have misspelled the chain.

Carlos Z

1 Like

Thanks for the reply!! Finally I get the Metamask small window pop up!!