跳到主要内容

以太坊名称服务

背景

当网络最初开始时,你可以在网络上探索信息的唯一方法是输入 IP 地址。此后,DNS 的概念被引入,帮助我们将域名与 IP 地址联系起来。

因此,当你输入 learnweb3.io 时,DNS 负责将其翻译成相应的 IP,这就是计算机最终理解的内容。

什么是 ENS?

ENS 是以太坊名称服务的缩写,它的行为与 DNS 在 web2 空间的行为非常相似。我们都知道,以太坊的地址很长,很难记住或输入。ENS 通过将这些钱包地址、哈希值等翻译成可读的域名,然后保存在以太坊区块链上,解决了这个问题。

ENS 最好的部分是不像 DNS 服务器是集中式的,ENS 在智能合约的帮助下工作,是抗审查的。因此,现在当你向某人发送你的钱包地址,看起来像 0x1234huiahi....,你实际上可以向他们发送 tom.eth,ENS 会发现 tom.eth 实际上等于你的钱包地址(0x1234huiahi....)。

此外,ENS 不仅仅是将钱包地址映射为人类可读的名字。你实际上可以附加一个个人资料图片、描述、社交媒体链接,以及任何你想附加的自定义类型的数据。

要求

是时候建立一些我们可以使用 ENS 的地方了。我们将开发一个网站,如果它有一个地址,就可以显示 ENS。

让我们开始吧 🚀

设置

首先,让我们为你的地址取得一个 ENS 名称,首先打开 https://app.ens.domains/。

确保当你打开网站时,你的 MetaMask 已经连接到 Goerli Testnet,并且它有一些 Goerli Ether。

搜索一个 ENS 域名,任何你喜欢的名字,只要它是可用的!。点击 "可用

然后点击请求注册

当进度条进入第三步时,点击 RegisterImage。

然后在进度条结束后,点击设置为主要的 ENS 域名

从下拉菜单中选择你刚刚创建的 ENS 名称。

点击保存

现在你在 Goerli 上有一个注册到你地址的 ENS。太棒了,你做到了 ❤️

网站

为了开发这个网站,我们将使用 React 和 Next Js。React 是一个用于制作网站的 javascript 框架,Next.js 是一个 React 框架,它也允许与前端一起编写后端 API 代码,所以你不需要两个独立的前端和后端服务。首先,你将需要创建一个新的 Next 应用程序。你的文件夹结构应该是这样的

- ENS
- 我的应用程序

创建项目

npx create-next-app@latest
cd my-app
npm run dev

现在去 http://localhost:3000,你的应用程序应该正在运行 🤘。

安装依赖

让我们来安装 Web3Modal 库。Web3Modal 是一个易于使用的库,帮助开发者轻松地让他们的用户用各种不同的钱包连接到你的 dApps。默认情况下,Web3Modal 库支持注入的提供者,如(Metamask、Dapper、Gnosis Safe、Frame、Web3 Browsers 等)和 WalletConnect,你也可以轻松配置该库以支持 Portis、Fortmatic、Squarelink、Torus、Authereum、D'Cent Wallet 和 Arkane。打开终端指向 atmy-app 目录,执行以下命令

npm i web3modal ethers

在你的 my-app/public 文件夹中,下载这张图片并将其重命名为 learnweb3punks.png

现在进入样式文件夹,用以下代码替换 Home.modules.css 文件的所有内容,这将为你的 dapp 添加一些样式。

.main {
min-height: 90vh;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-family: "Courier New", Courier, monospace;
}

.footer {
display: flex;
padding: 2rem 0;
border-top: 1px solid #eaeaea;
justify-content: center;
align-items: center;
}

.image {
width: 70%;
height: 50%;
margin-left: 20%;
}

.title {
font-size: 2rem;
margin: 2rem 0;
}

.description {
line-height: 1;
margin: 2rem 0;
font-size: 1.2rem;
}

.button {
border-radius: 4px;
background-color: blue;
border: none;
color: #ffffff;
font-size: 15px;
padding: 20px;
width: 200px;
cursor: pointer;
margin-bottom: 2%;
}
@media (max-width: 1000px) {
.main {
width: 100%;
flex-direction: column;
justify-content: center;
align-items: center;
}
}

修改页面

pages/index.js

import Head from "next/head";
import styles from "../styles/Home.module.css";
import Web3Modal from "web3modal";
import { ethers, providers } from "ethers";
import { useEffect, useRef, useState } from "react";

export default function Home() {
// walletConnected keep track of whether the user's wallet is connected or not
const [walletConnected, setWalletConnected] = useState(false);
// Create a reference to the Web3 Modal (used for connecting to Metamask) which persists as long as the page is open
const web3ModalRef = useRef();
// ENS
const [ens, setENS] = useState("");
// Save the address of the currently connected account
const [address, setAddress] = useState("");

/**
* Sets the ENS, if the current connected address has an associated ENS or else it sets
* the address of the connected account
*/
const setENSOrAddress = async (address, web3Provider) => {
// Lookup the ENS related to the given address
var _ens = await web3Provider.lookupAddress(address);
// If the address has an ENS set the ENS or else just set the address
if (_ens) {
setENS(_ens);
} else {
setAddress(address);
}
};

/**
* A `Provider` is needed to interact with the blockchain - reading transactions, reading balances, reading state, etc.
*
* A `Signer` is a special type of Provider used in case a `write` transaction needs to be made to the blockchain, which involves the connected account
* needing to make a digital signature to authorize the transaction being sent. Metamask exposes a Signer API to allow your website to
* request signatures from the user using Signer functions.
*/
const getProviderOrSigner = async () => {
// Connect to Metamask
// Since we store `web3Modal` as a reference, we need to access the `current` value to get access to the underlying object
const provider = await web3ModalRef.current.connect();
const web3Provider = new providers.Web3Provider(provider);

// If user is not connected to the Goerli network, let them know and throw an error
const { chainId } = await web3Provider.getNetwork();
if (chainId !== 5) {
window.alert("Change the network to Goerli");
throw new Error("Change network to Goerli");
}
const signer = web3Provider.getSigner();
// Get the address associated to the signer which is connected to MetaMask
const address = await signer.getAddress();
// Calls the function to set the ENS or Address
await setENSOrAddress(address, web3Provider);
return signer;
};

/*
connectWallet: Connects the MetaMask wallet
*/
const connectWallet = async () => {
try {
// Get the provider from web3Modal, which in our case is MetaMask
// When used for the first time, it prompts the user to connect their wallet
await getProviderOrSigner(true);
setWalletConnected(true);
} catch (err) {
console.error(err);
}
};

/*
renderButton: Returns a button based on the state of the dapp
*/
const renderButton = () => {
if (walletConnected) {
<div>Wallet connected</div>;
} else {
return (
<button onClick={connectWallet} className={styles.button}>
Connect your wallet
</button>
);
}
};

// useEffects are used to react to changes in state of the website
// The array at the end of function call represents what state changes will trigger this effect
// In this case, whenever the value of `walletConnected` changes - this effect will be called
useEffect(() => {
// if wallet is not connected, create a new instance of Web3Modal and connect the MetaMask wallet
if (!walletConnected) {
// Assign the Web3Modal class to the reference object by setting it's `current` value
// The `current` value is persisted throughout as long as this page is open
web3ModalRef.current = new Web3Modal({
network: "goerli",
providerOptions: {},
disableInjectedProvider: false,
});
connectWallet();
}
}, [walletConnected]);

return (
<div>
<Head>
<title>ENS Dapp</title>
<meta name="description" content="ENS-Dapp" />
<link rel="icon" href="/favicon.ico" />
</Head>
<div className={styles.main}>
<div>
<h1 className={styles.title}>
Welcome to LearnWeb3 Punks {ens ? ens : address}!
</h1>
<div className={styles.description}>
Its an NFT collection for LearnWeb3 Punks.
</div>
{renderButton()}
</div>
<div>
<img className={styles.image} src="./learnweb3punks.png" />
</div>
</div>

<footer className={styles.footer}>
Made with &#10084; by LearnWeb3 Punks
</footer>
</div>
);
}

部署

部署到 Vercel,略。