Loading...
Ethers.js is a JavaScript library that allows developers to interact with the EVM compatible blockchains.
We will use this library to interact with Polygon blockchain which provides a protocol and a framework for building and connecting Ethereum-compatible blockchain networks. Polygon technology provides developers with the tools to readily deploy a stand-alone network or a secure sidechain that can optionally leverage the security of the Ethereum network via smart contracts.
This smartbook will be about interaction with Polygon POS blockchain from client side with ethers library.
You can check this smartbook for interaction with polygon POS blockchain from nodejs (backend).
We will be using storage smart contract which will be deployed on Polygon POS blockchain and interact with it.
Our simple storage smart contract will look like this,
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Storage {
uint number;
function store(uint num) public {
number = num;
}
function retrieve() public view returns (uint){
return number;
}
}
You can get test tokens from matic's faucet.
From select token section , select MATIC Token and from select network section , select Mumbai.
Then enter your address and click on submit and confirm.
In order to interact with Polygon POS blockchain , Polygon network must be configured on Metamask.
You can refer this article to configure Metamask.
There are many methods of deployment like using truffle, Hardhat etc. but using Remix IDE is the easiest method for deployment of smart contract. You can refer this for deployment process with Remix. Make sure to switch to polygon network on metamask before selecting the injected web3 option in environment from deploy and transaction section in Remix IDE.
or
You can refer this smartbook for deployment with the truffle and this smartbook to deploy with hardhat.
> npm init
> npm install --save express
Here index.js will be our server file and index.html will be main working file.
> touch index.js
> mkdir public
> touch public/index.html
Our index.js file will be simple node server serving index.html file,
var express = require('express');
var app = require('express')();
var http = require('http').Server(app);
var path = require('path');
var port = process.env.PORT || 3000;
app.use(express.static(path.join(__dirname, './public/')));
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
});
http.listen(port, function () {
console.log('listening on *:' + port);
});
Client side code will consist of html for UI and script for interaction with blockchain.
We will first create working script and then add it in our html ui.
Address and ABI can be accessed from above deployment methods.
We will initialise some dom elements as well.
var address = "0xB16aDe9715A521469C8700B19697270549C99FB0";
var abi = [
{
"inputs": [],
"name": "retrieve",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "num",
"type": "uint256"
}
],
"name": "store",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}];
var provider, signer;
var store = document.getElementById('store');
var result_span = document.getElementById('result');
CheckMetamaskConnection function will connect to metamask from browser and initialise provider and signer.
async function CheckMetamaskConnection() {
if (window.ethereum) {
try {
provider = new ethers.providers.Web3Provider(window.ethereum);
signer = provider.getSigner();
await window.ethereum.enable();
ethereum.request({ method: 'eth_accounts'}).then((res) => {
document.getElementById('address').innerHTML = res[0];
});
return true;
} catch (error) { return false;}
} else { return false;}
}
Here as you can see getting signer is different than one from nodejs interaction method from part 1.
Read only and Write only smart contract instances need to be assinged separately like before. Signer will give write only and provider will give read only instance.
$(document).ready(async function () {
var isMetamask = await CheckMetamaskConnection();
if (isMetamask) {
myContract_write = new ethers.Contract(address, abi, signer);
myContract_read = new ethers.Contract(address, abi, provider);
}
});
Store function will use myContract_write instance and input value in store element inisitalised before. Transaction hash will be shown in result span which we have initialised before.
function store_data() {
myContract_write.store(store.value).then(function (result) {
result_span.innerHTML = `Transaction Hash : ${result.hash}`;
});
}
Retrieve function will use myContract_read instance to access retrieve function from smart contract. As retrieve function from smart contract return stored value in result parameter, it will be shown in result span.
function retrieve_data() {
myContract_read.retrieve().then(function (result) {
result_span.innerHTML = `Stored Data : ${result}`;
});
}
With this our script is complete , now we can create html for ui interaction from client side.
Our html will consist of two buttons and an input to interact with our functions created from previous script section which will trigger functions from smart contract.
In HTML following things will be important :
We will be accessing Ethers library with cdn and put it in head section.
<script src="https://cdn.ethers.io/lib/ethers-5.2.umd.min.js" type="application/javascript"></script>
Here our retrieve button will trigger a function which will access retrieve function from smart contract.
<button class="btn btn-success" onclick="retrieve_data()"> Retrieve </button>
Store function from our script will need an input value which we will take with an input element and a button to trigger that function.
<input class="form-control" id="store"><br>
<button class="btn btn-danger" onclick="store_data()"> Store </button>
Other elements in out html are for creating ui and does not affect our interaction with smart contract from client side.
So our serving html code will be as follows,
<!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>Ethers</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"
integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"
integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.min.js"
integrity="sha384-+YQ4JLhjyBLPDQt//I+STsc9iw4uQqACwlvpslubQzn4u2UU2UFM80nGisd026JF"
crossorigin="anonymous"></script>
<!-- Ethers Library CDN -->
<script src="https://cdn.ethers.io/lib/ethers-5.2.umd.min.js" type="application/javascript"></script>
</head>
<body>
<nav class="navbar navbar-light bg-light justify-content-between">
<a class="navbar-brand">Ethers Js</a>
<form class="form-inline">
<span id="address">Address</span>
</form>
</nav>
<div class="container" style="padding-top: 200px;">
<div class="row">
<div class="col-md-6 text-center">
<div
style="margin: 0px auto;width: 60%;height: 150px;background-color: rgba(194, 194, 194, 0.253);padding-top: 15%;border-radius: 10px;box-shadow: 0px 0px 5px gray;">
<button class="btn btn-success" onclick="retrieve_data()"> Retrieve </button>
</div>
</div>
<div class="col-md-6 text-center">
<div
style="margin: 0px auto;width: 60%;height: 150px;background-color: rgba(194, 194, 194, 0.253);padding-top: 5%;border-radius: 10px;box-shadow: 0px 0px 5px gray;padding-inline: 20px;">
<input class="form-control" id="store"><br>
<button class="btn btn-danger" onclick="store_data()"> Store </button>
</div>
</div>
<div class="col-md-12 text-center " style="padding-top: 80px;">
<div>
<span id="result"
style="background-color: rgba(194, 194, 194, 0.153);padding:10px;border-radius:15px"> ----
Output Here ----
</span>
</div>
</div>
</div>
</div>
</body>
<script>
var address = "0xB16aDe9715A521469C8700B19697270549C99FB0";
var abi = [
{
"inputs": [],
"name": "retrieve",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "num",
"type": "uint256"
}
],
"name": "store",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
];
var provider, signer;
var store = document.getElementById('store');
var result_span = document.getElementById('result');
async function CheckMetamaskConnection() {
if (window.ethereum) {
try {
provider = new ethers.providers.Web3Provider(window.ethereum);
signer = provider.getSigner();
await window.ethereum.enable();
ethereum.request({
method: 'eth_accounts'
}).then((res) => {
document.getElementById('address').innerHTML = res[0];
});
return true;
} catch (error) { return false;}
} else { return false; }
}
$(document).ready(async function () {
var isMetamask = await CheckMetamaskConnection();
if (isMetamask) {
myContract_write = new ethers.Contract(address, abi, signer);
myContract_read = new ethers.Contract(address, abi, provider);
}
});
function store_data() {
myContract_write.store(store.value).then(function (result) {result_span.innerHTML = `Transaction Hash : ${result.hash}`;});
}
function retrieve_data() {
myContract_read.retrieve().then(function (result) {result_span.innerHTML = `Stored Data : ${result}`;});
}
</script>
</html>