In the beginning, we quickly build our home page’s layout on the front-end project. We use below code to replace front_end/pages/index.tsx
file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import type { NextPage } from "next" ;import { Navbar , Footer , Button } from "flowbite-react" ;const Home : NextPage = () => { const handleConnectWallet = ( ) => {}; return ( <div className ="" > <Navbar fluid ={true} rounded ={true} > <Navbar.Brand href ="/" > <img src ="https://flowbite.com/docs/images/logo.svg" className ="mr-3 h-6 sm:h-9" alt ="Flowbite Logo" /> <span className ="self-center whitespace-nowrap text-xl font-semibold dark:text-white" > DApp Demo </span > </Navbar.Brand > <Navbar.Toggle /> <Navbar.Collapse > <Button onClick ={handleConnectWallet} > Connect Wallet</Button > </Navbar.Collapse > </Navbar > <div className ="min-w-full min-h-full" > <div className ="container flex flex-col justify-center items-center space-y-5" > </div > </div > <Footer container ={true} > <Footer.Copyright href ="#" by ="OhMyApps™" year ={new Date ().getFullYear ()} /> <Footer.LinkGroup > <Footer.Link href ="#" > About</Footer.Link > <Footer.Link href ="#" > Privacy Policy</Footer.Link > <Footer.Link href ="#" > Licensing</Footer.Link > <Footer.Link href ="#" > Contact</Footer.Link > </Footer.LinkGroup > </Footer > </div > ); }; export default Home ;
Let’s try to build the first feature with ethers.js Install ethers.js The ethers.js library is interacting with Ethereum. So we choose it.
Now, We install it.
1 2 3 // on ./DApp-Demo cd front_endyarn add ethers
We will use metamask to connect to our website. Looks like
We study the ethersjs document ,
We changed our front_end/pages/index.tsx
file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 import { useState } from 'react' import type { NextPage } from 'next' import { Navbar , Footer , Button } from 'flowbite-react' import { ethers } from 'ethers' declare let window : any const Home : NextPage = () => { const [address, setAddress] = useState<string>() const [balance, setBalance] = useState<string>() const handleConnectWallet = async ( ) => { const provider = new ethers.providers .Web3Provider (window .ethereum ) await provider.send ('eth_requestAccounts' , []) const signer = provider.getSigner () setAddress (await signer.getAddress ()) setBalance (ethers.utils .formatEther (await signer.getBalance ())) } return ( <div className ="" > <Navbar fluid ={true} rounded ={true} > <Navbar.Brand href ="/" > <img src ="https://flowbite.com/docs/images/logo.svg" className ="mr-3 h-6 sm:h-9" alt ="Flowbite Logo" /> <span className ="self-center whitespace-nowrap text-xl font-semibold dark:text-white" > DApp Demo </span > </Navbar.Brand > <Navbar.Toggle /> <Navbar.Collapse > {address ? ( <> <div > {address}</div > <div > {balance}</div > </> ) : ( <Button onClick ={handleConnectWallet} > Connect Wallet</Button > )} </Navbar.Collapse > </Navbar > <div className ="min-w-full min-h-full" > <div className ="container flex flex-col justify-center items-center space-y-5" > </div > </div > <Footer container ={true} > <Footer.Copyright href ="#" by ="OhMyApps™" year ={new Date ().getFullYear ()} /> <Footer.LinkGroup > <Footer.Link href ="#" > About</Footer.Link > <Footer.Link href ="#" > Privacy Policy</Footer.Link > <Footer.Link href ="#" > Licensing</Footer.Link > <Footer.Link href ="#" > Contact</Footer.Link > </Footer.LinkGroup > </Footer > </div> ) } export default Home
We built the first feature with ethersjs.
Now we want to call our smart contract.
Integrating the Front-End Generate Typescript code from ABI Because we use typescript, so we can’t like javascript to directly call ABI.
Recommend TypeChain library. It helps us to create typescript code from Ethereum smart contract.
Install TypeChain
1 2 3 // on ./DApp-Demo cd front_endyarn add typechain @typechain/ethers-v5 -D
Use TypeChain
1 2 3 4 // on ./DApp-Demo/front_end // Keep you already built the smart contract before. npx typechain --target ethers-v5 --out-dir generated/contract-types '../chain_end/out/Counter.sol/Counter.json' Output: Successfully generated 5 typings!
Now, we finished from the JSON ABI files to the typescript module.
Update the homepage We changed our front_end/pages/index.tsx
file. Only one important thing is COUNTER_ADDRESS
value. It muse be your smart contract deployed address.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 import type { NextPage } from 'next' import React from 'react' import { useState, useEffect } from 'react' import { ethers } from 'ethers' import { Counter __factory } from '../generated/contract-types' import { Navbar , Footer , Card , Label , TextInput , Button } from 'flowbite-react' declare let window : any const Home : NextPage = () => { const [address, setAddress] = useState<string>() const [balance, setBalance] = useState<string>() const [count, setCount] = useState<number>(0 ) const [number, setNumber] = useState<number>(0 ) const [time, setTime] = useState (Date .now ()) const COUNTER_ADDRESS = '0x4D32EEaee44e11cBD3fDE99F38f0885D0F735dE3' useEffect (() => { const interval = setInterval (() => setTime (Date .now ()), 5000 ) return () => { clearInterval (interval) } }, []) useEffect (() => { const provider = new ethers.providers .StaticJsonRpcProvider () const counter = Counter __factory.connect (COUNTER_ADDRESS , provider) if (counter) { counter.number ().then ((count ) => { setCount (count.toNumber ()) }) } }, [time]) const handleConnectWallet = async ( ) => { const provider = new ethers.providers .Web3Provider (window .ethereum ) await provider.send ('eth_requestAccounts' , []) const signer = provider.getSigner () setAddress (await signer.getAddress ()) setBalance (ethers.utils .formatEther (await signer.getBalance ())) } const handleRefresh = async ( ) => { const provider = new ethers.providers .StaticJsonRpcProvider () const counter = Counter __factory.connect (COUNTER_ADDRESS , provider) const n = await counter.number () setCount (n.toNumber ()) } const handleIncrement = async ( ) => { console .log ('increment' ) const provider = new ethers.providers .Web3Provider (window .ethereum ) const signer = await provider.getSigner () const counter = Counter __factory.connect (COUNTER_ADDRESS , signer) await counter.increment () } const handleSetNumber = async ( ) => { console .log ('set number' ) const provider = new ethers.providers .Web3Provider (window .ethereum ) const signer = await provider.getSigner () const contract = Counter __factory.connect (COUNTER_ADDRESS , signer) await contract.setNumber (number) } return ( <div className ="" > <Navbar fluid ={true} rounded ={true} > <Navbar.Brand href ="/" > <img src ="https://flowbite.com/docs/images/logo.svg" className ="mr-3 h-6 sm:h-9" alt ="Flowbite Logo" /> <span className ="self-center whitespace-nowrap text-xl font-semibold dark:text-white" > DApp Demo </span > </Navbar.Brand > <Navbar.Toggle /> <Navbar.Collapse > {address ? ( <> <div > {address}</div > <div > {balance}</div > </> ) : ( <Button onClick ={handleConnectWallet} > Connect Wallet</Button > )} </Navbar.Collapse > </Navbar > <div className ="min-w-full min-h-full" > <div className ="container flex flex-col justify-center items-center space-y-5" > <div className ="text-3xl font-bold" > Counter {count}</div > <Button color ="light" onClick ={handleRefresh} > Refresh Counter </Button > <Card > <Button onClick ={handleIncrement} > Increment Counter</Button > </Card > <Card > <div > <div className ="mb-2 block" > <Label htmlFor ="number" value ="Set Number" /> </div > <TextInput id ="number" type ="number" placeholder ="Enter number" value ={number} required ={true} onChange ={(e) => setNumber(parseInt(e.target.value))} /> </div > <Button type ="submit" onClick ={handleSetNumber} > Submit </Button > </Card > </div > </div > <Footer container ={true} > <Footer.Copyright href ="#" by ="OhMyApps™" year ={new Date ().getFullYear ()} /> <Footer.LinkGroup > <Footer.Link href ="#" > About</Footer.Link > <Footer.Link href ="#" > Privacy Policy</Footer.Link > <Footer.Link href ="#" > Licensing</Footer.Link > <Footer.Link href ="#" > Contact</Footer.Link > </Footer.LinkGroup > </Footer > </div> ) } export default Home
Complete Nice work!
P.S. This article is very subjective. If you do not feel comfortable viewing it, please close it as soon as possible. If you think my article can help you, you can subscribe to this site by using RSS .
Referrals Photo by GuerrillaBuzz Crypto PR on Unsplash
https://docs.scaffoldeth.io/scaffold-eth/toolkit/how-tos-and-troubleshooting/providers https://docs.ethers.io/v5/api/providers/ https://docs.ethers.io/v5/api/signer/