Zero to One Full-Stack DApp Ethereum Development based on Foundry, NextJS, Typescript - 5 Building front-end then using it to call smart contract

Zero to One Full-Stack DApp Ethereum Development based on Foundry, NextJS, Typescript - 5 Building front-end then using it to call smart contract

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;

image.png

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_end
yarn add ethers

We will build a button that connects our wallet.

We will use metamask to connect to our website. Looks like

2022-10-22 23.20.04.gif

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_end
yarn 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!

2022-10-23 00.15.00.gif

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/

Zero to One Full-Stack DApp Ethereum Development based on Foundry, NextJS, Typescript - 5 Building front-end then using it to call smart contract

https://iiiyu.com/2022/10/17/Zero-to-One-Full-Stack-DApp-Ethereum-Development-based-on-Foundry-NextJS-Typescript-5-Building-front-end-then-using-it-to-call-smart-contract/

Author

Ewan Xiao

Posted on

October 17th 2022

Updated on

May 17th 2024

Licensed under

Comments