<html>
<head>
<title>Simple vanilla JS example of Web3modal usage</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Get some bootstrap default styles -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<!-- Construct a Bootstrap layout -->
<div class="container">
<div class="row">
<div class="col-md-12">
<h1>Web3modal vanilla JavaScript demo</h1>
<p>No wallet connected. Connect wallet to show accounts and their ETH balances.</p>
<div id="prepare">
<button class="btn btn-primary" id="btn-connect">
Connect wallet
</button>
</div>
<div id="connected" style="display: none">
<button class="btn btn-primary" id="btn-disconnect">
Disconnect wallet
</button>
<hr>
<div id="network">
<p>
<strong>Connected blockchain:</strong> <span id="network-name"></span>
</p>
<p>
<strong>Selected account:</strong> <span id="selected-account"></span>
</p>
</div>
<hr>
<h3>All account balances</h3>
<table class="table table-listing">
<thead>
<th>Address</th>
<th>ETH balance</th>
</thead>
<tbody id="accounts">
</tbody>
</table>
<p>Please try to switch between different accounts in your wallet if your wallet supports this functonality.</p>
</div>
</div>
</div>
</div>
<!-- We use simple <template> templating for the example -->
<div id="templates" style="display: none">
<template id="template-balance">
<tr>
<th class="address"></th>
<td class="balance"></td>
</tr>
</template>
</div>
<!--
Use unpkg CDN to load all NPM packages to vanilla Javascript - read more at http://unpkg.com
On your deployment, you properly either want to use a preprocessing tool like webpack
to include these files, or extract NPM archives and manually host the files inside.
TODO: Pin down all versions.
-->
<script src="https://unpkg.com/web3@latest/dist/web3.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/web3modal"></script>
<script type="text/javascript" src="https://unpkg.com/evm-chains/lib/index.js"></script>
<script type="text/javascript" src="https://unpkg.com/@walletconnect/web3-provider"></script>
<script type="text/javascript" src="https://unpkg.com/fortmatic@2.0.6/dist/fortmatic.js"></script>
<!-- This is our example code -->
<script type="text/javascript" src="./example.js"></script>
</body>
</html>
"use strict";
/**
* Example JavaScript code that interacts with the page and Web3 wallets
*/
// Unpkg imports
const Web3Modal = window.Web3Modal.default;
const WalletConnectProvider = window.WalletConnectProvider.default;
const EvmChains = window.EvmChains;
const Fortmatic = window.Fortmatic;
// Web3modal instance
let web3Modal
// Chosen wallet provider given by the dialog window
let provider;
// Address of the selected account
let selectedAccount;
/**
* Setup the orchestra
*/
function init() {
console.log("Initializing example");
console.log("WalletConnectProvider is", WalletConnectProvider);
console.log("Fortmatic is", Fortmatic);
// Tell Web3modal what providers we have available.
// Built-in web browser provider (only one can exist as a time)
// like MetaMask, Brave or Opera is added automatically by Web3modal
const providerOptions = {
walletconnect: {
package: WalletConnectProvider,
options: {
// Mikko's test key - don't copy as your mileage may vary
infuraId: "8043bb2cf99347b1bfadfb233c5325c0",
}
},
fortmatic: {
package: Fortmatic,
options: {
// Mikko's TESTNET api key
key: "pk_test_391E26A3B43A3350"
}
}
};
web3Modal = new Web3Modal({
cacheProvider: false, // optional
providerOptions, // required
});
}
/**
* Kick in the UI action after Web3modal dialog has chosen a provider
*/
async function fetchAccountData() {
// Get a Web3 instance for the wallet
const web3 = new Web3(provider);
console.log("Web3 instance is", web3);
// Get connected chain id from Ethereum node
const chainId = await web3.eth.getChainId();
// Load chain information over an HTTP API
const chainData = await EvmChains.getChain(chainId);
document.querySelector("#network-name").textContent = chainData.name;
// Get list of accounts of the connected wallet
const accounts = await web3.eth.getAccounts();
// MetaMask does not give you all accounts, only the selected account
console.log("Got accounts", accounts);
selectedAccount = accounts[0];
document.querySelector("#selected-account").textContent = selectedAccount;
// Get a handl
const template = document.querySelector("#template-balance");
const accountContainer = document.querySelector("#accounts");
// Purge UI elements any previously loaded accounts
accountContainer.innerHTML = '';
// Go through all accounts and get their ETH balance
const rowResolvers = accounts.map(async (address) => {
const balance = await web3.eth.getBalance(address);
// ethBalance is a BigNumber instance
// https://github.com/indutny/bn.js/
const ethBalance = web3.utils.fromWei(balance, "ether");
const humanFriendlyBalance = parseFloat(ethBalance).toFixed(4);
// Fill in the templated row and put in the document
const clone = template.content.cloneNode(true);
clone.querySelector(".address").textContent = address;
clone.querySelector(".balance").textContent = humanFriendlyBalance;
accountContainer.appendChild(clone);
});
// Because rendering account does its own RPC commucation
// with Ethereum node, we do not want to display any results
// until data for all accounts is loaded
await Promise.all(rowResolvers);
// Display fully loaded UI for wallet data
document.querySelector("#prepare").style.display = "none";
document.querySelector("#connected").style.display = "block";
}
/**
* Fetch account data for UI when
* - User switches accounts in wallet
* - User switches networks in wallet
* - User connects wallet initially
*/
async function refreshAccountData() {
// If any current data is displayed when
// the user is switching acounts in the wallet
// immediate hide this data
document.querySelector("#connected").style.display = "none";
document.querySelector("#prepare").style.display = "block";
// Disable button while UI is loading.
// fetchAccountData() will take a while as it communicates
// with Ethereum node via JSON-RPC and loads chain data
// over an API call.
document.querySelector("#btn-connect").setAttribute("disabled", "disabled")
await fetchAccountData(provider);
document.querySelector("#btn-connect").removeAttribute("disabled")
}
/**
* Connect wallet button pressed.
*/
async function onConnect() {
console.log("Opening a dialog", web3Modal);
try {
provider = await web3Modal.connect();
} catch(e) {
console.log("Could not get a wallet connection", e);
return;
}
// Subscribe to accounts change
provider.on("accountsChanged", (accounts) => {
fetchAccountData();
});
// Subscribe to chainId change
provider.on("chainChanged", (chainId) => {
fetchAccountData();
});
// Subscribe to networkId change
provider.on("networkChanged", (networkId) => {
fetchAccountData();
});
await refreshAccountData();
}
/**
* Disconnect wallet button pressed.
*/
async function onDisconnect() {
console.log("Killing the wallet connection", provider);
// TODO: Which providers have close method?
if(provider.close) {
await provider.close();
// If the cached provider is not cleared,
// WalletConnect will default to the existing session
// and does not allow to re-scan the QR code with a new wallet.
// Depending on your use case you may want or want not his behavir.
await web3Modal.clearCachedProvider();
provider = null;
}
selectedAccount = null;
// Set the UI back to the initial state
document.querySelector("#prepare").style.display = "block";
document.querySelector("#connected").style.display = "none";
}
/**
* Main entry point.
*/
window.addEventListener('load', async () => {
init();
document.querySelector("#btn-connect").addEventListener("click", onConnect);
document.querySelector("#btn-disconnect").addEventListener("click", onDisconnect);
});