4

Zero to One Full-Stack DApp Ethereum Development based on Foundry, NextJS, Types...

 1 year ago
source link: 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/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

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

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.

// 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

2022-10-22 23.20.04.gif

We study the ethersjs document,

We changed our front_end/pages/index.tsx file.

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

// on ./DApp-Demo
cd front_end
yarn add typechain @typechain/ethers-v5 -D

Use TypeChain

// 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.

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

2022-10-23 00.15.00.gif

2022-10-23 00.15.00.gif

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/


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK