边学边用--使用React下的Material UI框架开发一个简单的仿MetaMask的网页版以太坊钱包(四)

Valonia ·
更新时间:2024-11-13
· 660 次阅读

一、前言

       在上一章,我们完成了钱包的底层实现及新建账号、钱包登录和导入账号这三个页面之间的关联。本章我们接着开发,完成钱包详情界面UI的拼接和钱包余额的显示。

       今天的内容比较简单,我们计划实现一个这样的界面:

) } export default DetailHeader

       上面的代码中,我们点击中间的账号会将账号地址复制到粘贴板中。它通过copy-to-clipboard这个库来实现,记住要先npm install copy-to-clipboard安装它。由于Tooltip在移动端不显示,所以在点击账号时做了一个判断,如果是移动端就显示一个消息条来提示用户地址已经复制;如果是桌面端则直接改变Tooltip的内容来提示。Tooltip在关闭时将提示内容恢复成初始内容,但是这里有一点要注意,见代码:

const closeAddressTip = (e) => { e.preventDefault() setTimeout(()=>{ setClickTip(COPY_TO_CLIPBOARD) },500) }

这里延时了500毫秒来更新tooltip的显示,这个是故意为之的。因为时序问题,不延时的话关闭提示时会先显示初始内容然后再关闭。

       这里还有一个小问题,我在代码注释里有提到,就是图标按钮在上几级容器是flex布局下背景会失真,我们通过再外包一个

来解决。具体原因没有仔细研究,有兴趣的读者下载源码后可以把外包的
拿掉来复现,看能不能找到问题的根源。

三、拼出钱包详情下方界面

       从计划图中可以看出,详情下方界面主要是一个以太坊的LOGO,然后就是用户余额和对应的ETH总价值(以美元计算)。这个价格采自etherscan的数据,每分钟更新一次,用户余额实时更新。

       运行本代码你需要事先在网络上找一张以太坊的LOGO图片,然后保存在src/components/assets/目录下,名字叫着ether.png(当然你也可以改成别的名字)。

       新建src/components/DetailBody/index.js,代码如下:

import React, {useState,useEffect} from 'react'; import {makeStyles} from '@material-ui/core/styles'; import {useGlobal} from 'contexts/GlobalProvider' import Avatar from '@material-ui/core/Avatar'; import Typography from '@material-ui/core/Typography'; import Button from '@material-ui/core/Button'; import ListItemText from '@material-ui/core/ListItemText'; import {ethers} from 'ethers' import {convertToEth} from 'utils'; import etherIcon from 'components/assets/ether.png'; const useStyles = makeStyles(theme => ({ container: { display: 'flex', flexDirection: 'column', alignItems: 'center', width:"100%" }, avatar: { border: 1, borderStyle: "solid", borderColor: "#33333333", marginTop: theme.spacing(3), width: theme.spacing(7), height: theme.spacing(7), }, balanceText:{ marginTop: theme.spacing(3), }, sendBtn:{ width:"40%", margin:theme.spacing(3), }, })); //使用etherscan来查询ETH价格 const etherscanProvider = new ethers.providers.EtherscanProvider(); //每分钟定时查询ETH价格 const INTERVAL = 60000; //只有主网络才有查询并显示ETH价格的必要 const MAINNET = 'homestead' function DetailBody() { const classes = useStyles() const {network,wallet} = useGlobal() const {address} = wallet const [balance,setBalance] = useState(0) const [ethPrice,setEthPrice] = useState(0) //更新ETH价格,每一分钟更新一次 useEffect(()=>{ if(network === MAINNET){ let stale = false function getPrice() { etherscanProvider.getEtherPrice().then( price => { if(!stale) { setEthPrice(+price) } }).catch( e => {}); } getPrice() let interval = setInterval(getPrice,INTERVAL) //进行相关清理 return () =>{ stale = true clearInterval(interval) } } },[network]) //更新ETH数量 useEffect(()=>{ setBalance(0) let provider = ethers.getDefaultProvider(network) let stale = false //监听ETH变化 provider.on(address, _balance => { if(!stale){ setBalance(convertToEth(_balance)) } }); return ()=>{ stale = true provider.removeAllListeners(address) } },[network,address]) return (
<ListItemText className={classes.balanceText} primary={ {`${balance.toFixed(4)} ETH`} } secondary = { {network === MAINNET ? `${(balance * ethPrice).toFixed(2)} USD` :  } } />
) } export default DetailBody

       从上面的代码中可以看到,在切换网络时我们首先将余额清零setBalance(0),然后再获取余额信息。这个地方可以拓展一下,就是未获取到余额之前给出提示,比如显示”正在获取中…“。这里我们就不实现了,欢迎有兴趣的读者自己去实现。

       注意,我们获取到的账户余额都是以wei为单位的BigNumber,需要进行转换成我们常用的十进制浮点数(单位为ETH),转换代码也比较简单:

import {utils} from 'ethers' export function convertToEth(_bigNumber) { let eth_string = utils.formatEther(_bigNumber) return + eth_string } 四、完成钱包详情页面的拼接

       我们把前面两个元素组合起来,再稍微加上一点内容,就可以得到我们的计划界面了。修改src\views\WalletDetail.jsx,完整代码如下:

import React from 'react'; import {makeStyles} from '@material-ui/core/styles'; import Divider from '@material-ui/core/Divider'; import DetailHeader from 'components/DetailHeader'; import DetailBody from 'components/DetailBody'; const useStyles = makeStyles(theme => ({ container: { display: 'flex', flexDirection: 'column', alignItems: 'center', margin: theme.spacing(2), }, divider:{ width:"100%", marginTop: theme.spacing(-1), } })); function WalletDetail() { const classes = useStyles(); return (
历史记录
) } export default WalletDetail

代码比较简单,这其中是一条分隔线。

五、修改工具类文件

       修改src\utils\index.js,将本次使用的工具类方法添加进去,完整的代码为:

import crypto from 'crypto' import {utils} from 'ethers' export function aesEncrypt(data,key) { let cipher = crypto.createCipher('aes192', key); let crypted = cipher.update(data, 'utf8', 'hex'); crypted += cipher.final('hex'); return crypted; } export function aesDecrypt(encrypted, key) { let decipher = crypto.createDecipher('aes192', key); let decrypted = decipher.update(encrypted, 'hex', 'utf8'); decrypted += decipher.final('utf8'); return decrypted; } export function getPasswordLength() { let length = process.env.REACT_APP_PASSWORD_LENGTH; return +length } export function shortenAddress(address, digits = 4) { return `${address.substring(0, digits + 2)}...${address.substring(42 - digits)}` } export function convertToEth(_bigNumber) { let eth_string = utils.formatEther(_bigNumber) return + eth_string } 六、运行钱包并测试

       在运行之前你需要更新了最新的代码(每一篇文章结束时都附有码云上的git仓库地址),如果没有更新的话先跳到文章结尾查看git仓库地址来更新。

       npm start来运行我们的钱包,如果提示有模块找不到,先安装好。如果你第一次使用我们的钱包,会提示你创建或者导入账号;如果已经使用过了,会出现一个如下的登录界面:
在这里插入图片描述
       输入你的密码后你就会进入钱包详情页面,它会显示该账号拥有的ETH余额和对应的总价值(单位美元)。如果我们切换到测试网,也会显示你在测试网络的测试ETH余额,但不会显示总价值(因为测试网ETH没有价值)。由于Localhost 8545需要你事先在本地运行一个ganache节点,所以目前并未实现,请不要点击。

       下面是主网界面:
在这里插入图片描述
       可以看到笔者目前主网有0.2633个ETH,这些ETH总价值43.86美金(以截图时的价格计算的)。没有ETH的小伙伴们也不要着急,有认识的朋友有ETH的,可以让他转一点过来,这样钱包里就可以看见了。没有这样的朋友或者朋友不发的也不要急,我们可以切换到测试网络进行测试,下面我给出在Kovan测试网上进行测试的方法。

七、在Kovan测试网中进行测试

       我们主要测试钱包显示ETH数量是否正确,能否自动更新。要想测试,就必须先获取测试ETH。在三大测试网中,在写这篇文章时,Ropsten测试币收不到,Rinkeby测试币获取比较麻烦,所以我先介绍Kovan测试网测试ETH的获取方法,获取的同时也一并对钱包进行测试。

将我们钱包中的网络切换到Kovan测试网,如下图:
在这里插入图片描述
       可以看到,我的这个账号在ropsten测试网上的测试ETH数量为0.9995个,和主网是不同的。

打开Kovan测试网测试ETH获取网站(也叫kovan水龙头):https://gitter.im/kovan-testnet/faucet

点击最下方的登录按钮来登录,你可能需要一个github账号。
在这里插入图片描述

在我们的钱包中点击我的账号,将账号地址复制到粘贴板中。

在刚才那个水龙头网站最下方输入框里粘贴你的地址,然后回车发送。用这种方式获取一周只能获取3个测试币。 在这里插入图片描述

送完了会有提示,如下:送了3个ETH到我的账号里,并且提示不是真的币,没有价值,只用于测试。
在这里插入图片描述

等待我们的钱包自动刷新ETH数量。
在这里插入图片描述
       可以看到,我们钱包kovan测试网下ETH数量已经自动更新了,我们收到了3个ETH。-_-

八、总结

       这次开发我们主要实现了钱包详情主界面UI的拼接和账号ETH余额及总价值的显示。这其中ETH的价格来源于etherscan,在主网状态下每一分钟更新一次;而用户余额是不分网络实时更新的。

       主界面上其它按钮功能暂未实现,我们计划在下一次开发中实现ETH的发送(转账)功能。

       本学习工程码云(gittee) 上的git仓库地址为: => https://gitee.com/TianCaoJiangLin/khwallet

       恳请大家留言指正或者提出宝贵意见、建议。


作者:天草降临



以太坊钱包 钱包 以太坊 ui框架 material React

需要 登录 后方可回复, 如果你还没有账号请 注册新账号