I was wondering if someone could help me out with the swap function part. I tried several different ways to get it working and I keep getting errors. Here are the two main ways I tried with 2 different errors:
I have everything else working but I keep getting errors when I try to implement the swap function for MetaMask.
I’m not worried about the wallet address showing here, It’s a test account.
This is my DEX:
I’m going to list the HTML and CSS first:
<!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">
<!-- 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>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
<!-- My CSS -->
<link rel="stylesheet" href="./DEX1.css">
<title>Moo Dex</title>
</head>
<body>
<!-- Top Title -->
<div class="container">
<div class="row">
<div class="col-12 col-md-6">
<h3 style="display: inline-block">Moo Dex</h3>
<h6 style="display: inline-block">Network: Polygon</h6>
</div>
<!-- Top Buttons -->
<div class="col-12 col-md-6 d-flex align-items-center justify-content-md-center">
<button class="btn btn-primary btn-sm" id="btn-login">MetaMask 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>
<!-- Login Label -->
<div class="login-bar" id="login-bar">
<div class="login-address-label" id="login-address-label">User Address: </div>
<div class="login-address" id="login-address"></div>
</div>
<!-- Table Header -->
<table class="table table-dark table-striped">
<thead>
<tr>
<th>#</th>
<th>Symbol</th>
<th>Amount</th>
<th>Action</th>
</tr>
</thead>
<!-- Table Token Balances -->
<tbody class="js-token-balances"></tbody>
</table>
<!-- Amount Field -->
<form action="#" method="POST" class="exchange-form">
<div class="form-row">
<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>
<br>
<!-- Swapto Dropdown List -->
<div class="form-row">
<label>
Swap to:
<select name="to-token"></select>
</label>
</div>
<br>
<!-- Quote and Cancel Buttons -->
<div class="form-row">
<button type="submit" class="js-submit btn btn-warning btn-md" disabled>Get Quote</button>
<button class="js-cancel btn btn-danger btn-md" disabled>Cancel</button>
</div>
<br>
<!-- Quote Info -->
<div class="quote-box">
<div class="quote-box-label">Quote Info:</div>
<div class="js-quote-container"></div>
</div>
</form>
</div>
<br>
<!-- Approve Quote Button -->
<div class="approve-quote-row">
<button type="submit" class="js-approve btn btn-success btn-md" id="btn-approve" disabled>Approve Quote</button>
</div>
<!-- Bootstrap 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>
<!-- My Javascript -->
<script src="./DEX1.js"></script>
</body>
</html>
.error {
color: red;
}
body {
background-color: black;
color: whitesmoke;
height: 100%;
}
.btn-sm {
margin: 2px;
padding-top: 3px;
padding-bottom: 3px;
padding-left: 10px;
padding-right: 10px;
}
.btn-md {
margin: 5px;
padding-top: 5px;
padding-bottom: 5px;
padding-left: 20px;
padding-right: 20px;
}
.login-bar {
background-color: rgb(15, 16, 16);
color: rgb(255, 255, 255);
font-weight: bold;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
padding: .75rem;
margin-top: .5rem;
margin-bottom: .5rem;
}
.login-address-label {
font-style: italic;
text-decoration: underline;
}
.js-quote-container {
background-color: rgb(40, 56, 52);
padding: 1rem;
margin-top: 1rem;
margin-left: 1rem;
margin-right: 1rem;
}
.table {
border-bottom:rgb(255, 255, 255);
}
.approve-quote-row {
padding-left: 1rem;
margin-left: 2rem;
}
This is the quote array:
Now if I use the Swap code that is on the Moralis 1inch Plugin Site Section:
This is the error I get when I click the “Approve Quote” button:
This is the JS Code I used and received the error above:
// connect to Moralis server
const serverUrl = "https://omhfs3y6i9tz.usemoralis.com:2053/server";
const appId = "yKfwpciCbpWSXwyVcw4Gq8Hxi46qL9iPo2CPwhuq";
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);
/** MetaMask Login */
// Login Function
async function login() {
let user = Moralis.User.current()
if (user) {
console.log("User Logged in", user);
console.log(user.get("ethAddress"));
document.getElementById('login-address').innerHTML = user.get('ethAddress');
getStats();
}
if (!user) {
user = await Moralis.authenticate()
.then(function (user) {
console.log("logged in user:", user);
console.log(user.get("ethAddress"));
document.getElementById('login-address').innerHTML = user.get('ethAddress');
getStats();
})
.catch(function (error) {
console.log(error);
});
}
}
// Logout Function
async function logOut() {
await Moralis.User.logOut();
document.getElementById('login-address').innerHTML = 'Logged Out';
console.log("logged out");
}
// Button Click Actions
document.getElementById("btn-login").onclick = login;
document
.getElementById("btn-buy-crypto")
.addEventListener('click', buyCrypto);
document.getElementById("btn-logout").onclick = logOut;
// BuyCrypto Function
async function buyCrypto() {
Moralis.Plugins.fiat.buy();
}
// Swap Form
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 = '';
}
//return the metamask wallet balances
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 btn-sm"
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);
}
}
/** Quote / Swap */
async function formSubmitted(event) {
event.preventDefault();
const fromAmount = Number.parseFloat( $amountInput.value );
const fromMaxValue = Number.parseFloat( $selectedToken.dataset.max );
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(),
});
console.log(quote);
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 (Wei): ${quote.estimatedGas}
</p>
`;
document.querySelector('.js-approve').removeAttribute('disabled');
} catch(e) {
document.querySelector('.js-quote-container').innerHTML = `
<p class="error">The conversion didn't succedd. </p>
`;
}
}
//activate the approve quote button upon click
document.querySelector('.js-approve').addEventListener('click', swap);
//perform the swap
async function swap() {
const receipt = await Moralis.Plugins.oneInch.swap({
chain: 'bsc', // 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(),
fromAddress: Moralis.User.current().get('ethAddress'), // Your wallet address
slippage: 1,
});
console.log(receipt);
}
//cancel the quote form
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 <= 20)
.map(token => token.symbol);
}
//get ticker data from 1inch
async function getTickerData(tickerList) {
const tokens = await Moralis.Plugins.oneInch.getSupportedTokens({
chain: 'polygon', // The blockchain you want to use (eth/bsc/polygon)
});
const tokenList = Object.values(tokens.tokens);
return tokenList.filter(token => tickerList.includes(token.symbol));
}
//return the tokens available in the dropdown list
function renderTokenDropdown(tokens) {
const options = tokens.map(token => `
<option value="${token.address}-${token.decimals}">
${token.name}
</option>
`).join('');
document.querySelector('[name=to-token]').innerHTML = options;
}
//pull the tokens from 1nch
getTop10Tokens()
.then(getTickerData)
.then(renderTokenDropdown);
But then if I include the variables, I get a different error when I click the “Approve Quote” button:
This is the code I used to receive the above error:
//perform the swap
async function swap() {
const fromDecimals = $selectedToken.dataset.decimals;
const fromTokenAddress = $selectedToken.dataset.address;
const [toTokenAddress, toDecimals] = document.querySelector('[name=to-token]').value.split('-');
const fromAmount = Number.parseFloat( $amountInput.value );
const receipt = await Moralis.Plugins.oneInch.swap({
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(),
fromAddress: Moralis.User.current().get('ethAddress'), // Your wallet address
slippage: 1,
});
console.log(receipt);
}
I also tried to use a second try catch and that didn’t work.
So I am kind of stuck and not sure what to try next…
What am I doing wrong here?
Thank you in advanced for any replies.