在上一章,我们完成了钱包的底层实现及新建账号、钱包登录和导入账号这三个页面之间的关联。本章我们接着开发,完成钱包详情界面UI的拼接和钱包余额的显示。
今天的内容比较简单,我们计划实现一个这样的界面:
上面的代码中,我们点击中间的账号会将账号地址复制到粘贴板中。它通过copy-to-clipboard
这个库来实现,记住要先npm install copy-to-clipboard
安装它。由于Tooltip
在移动端不显示,所以在点击账号时做了一个判断,如果是移动端就显示一个消息条来提示用户地址已经复制;如果是桌面端则直接改变Tooltip
的内容来提示。Tooltip
在关闭时将提示内容恢复成初始内容,但是这里有一点要注意,见代码:
const closeAddressTip = (e) => {
e.preventDefault()
setTimeout(()=>{
setClickTip(COPY_TO_CLIPBOARD)
},500)
}
这里延时了500毫秒来更新tooltip的显示,这个是故意为之的。因为时序问题,不延时的话关闭提示时会先显示初始内容然后再关闭。
这里还有一个小问题,我在代码注释里有提到,就是图标按钮在上几级容器是 从计划图中可以看出,详情下方界面主要是一个以太坊的LOGO,然后就是用户余额和对应的ETH总价值(以美元计算)。这个价格采自etherscan的数据,每分钟更新一次,用户余额实时更新。 运行本代码你需要事先在网络上找一张以太坊的LOGO图片,然后保存在 新建 从上面的代码中可以看到,在切换网络时我们首先将余额清零 注意,我们获取到的账户余额都是以wei为单位的BigNumber,需要进行转换成我们常用的十进制浮点数(单位为ETH),转换代码也比较简单: 我们把前面两个元素组合起来,再稍微加上一点内容,就可以得到我们的计划界面了。修改 代码比较简单,这其中 修改 在运行之前你需要更新了最新的代码(每一篇文章结束时都附有码云上的git仓库地址),如果没有更新的话先跳到文章结尾查看git仓库地址来更新。 下面是主网界面: 我们主要测试钱包显示ETH数量是否正确,能否自动更新。要想测试,就必须先获取测试ETH。在三大测试网中,在写这篇文章时,Ropsten测试币收不到,Rinkeby测试币获取比较麻烦,所以我先介绍Kovan测试网测试ETH的获取方法,获取的同时也一并对钱包进行测试。 将我们钱包中的网络切换到Kovan测试网,如下图: 打开Kovan测试网测试ETH获取网站(也叫kovan水龙头):https://gitter.im/kovan-testnet/faucet 点击最下方的登录按钮来登录,你可能需要一个github账号。 在我们的钱包中点击我的账号,将账号地址复制到粘贴板中。 在刚才那个水龙头网站最下方输入框里粘贴你的地址,然后回车发送。用这种方式获取一周只能获取3个测试币。 送完了会有提示,如下:送了3个ETH到我的账号里,并且提示不是真的币,没有价值,只用于测试。 等待我们的钱包自动刷新ETH数量。 这次开发我们主要实现了钱包详情主界面UI的拼接和账号ETH余额及总价值的显示。这其中ETH的价格来源于etherscan,在主网状态下每一分钟更新一次;而用户余额是不分网络实时更新的。 主界面上其它按钮功能暂未实现,我们计划在下一次开发中实现ETH的发送(转账)功能。 本学习工程码云(gittee) 上的git仓库地址为: => https://gitee.com/TianCaoJiangLin/khwallet 恳请大家留言指正或者提出宝贵意见、建议。flex
布局下背景会失真,我们通过再外包一个来解决。具体原因没有仔细研究,有兴趣的读者下载源码后可以把外包的
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 (
setBalance(0)
,然后再获取余额信息。这个地方可以拓展一下,就是未获取到余额之前给出提示,比如显示”正在获取中…“。这里我们就不实现了,欢迎有兴趣的读者自己去实现。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 (
是一条分隔线。
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
}
六、运行钱包并测试
npm start
来运行我们的钱包,如果提示有模块找不到,先安装好。如果你第一次使用我们的钱包,会提示你创建或者导入账号;如果已经使用过了,会出现一个如下的登录界面:
输入你的密码后你就会进入钱包详情页面,它会显示该账号拥有的ETH余额和对应的总价值(单位美元)。如果我们切换到测试网,也会显示你在测试网络的测试ETH余额,但不会显示总价值(因为测试网ETH没有价值)。由于Localhost 8545需要你事先在本地运行一个ganache节点,所以目前并未实现,请不要点击。
可以看到笔者目前主网有0.2633个ETH,这些ETH总价值43.86美金(以截图时的价格计算的)。没有ETH的小伙伴们也不要着急,有认识的朋友有ETH的,可以让他转一点过来,这样钱包里就可以看见了。没有这样的朋友或者朋友不发的也不要急,我们可以切换到测试网络进行测试,下面我给出在Kovan测试网上进行测试的方法。
可以看到,我的这个账号在ropsten测试网上的测试ETH数量为0.9995个,和主网是不同的。
可以看到,我们钱包kovan测试网下ETH数量已经自动更新了,我们收到了3个ETH。-_-
作者:天草降临