Dapp 前端开发小记
前端开发可谓是占据了 Dapp 开发的半壁江山,除了上篇文章讲到的 Solidity 智能合约开发,作为我们 Dapp 的逻辑和储存,前端就作为一个与 Dapp 交互的 User Interface 啦。
那么首先我也是半个专业的前端开发工程师,除去我们传统的前端开发的一些基本规范:
- i18n
- 路由守卫
- 权限
- state 管理
- model
- api 封装
- 持久化
之外呢,奶爸通过深度参与我司几个 Dapp 项目的前端开发后,也有一些自己的心得体会。
Web3.js
我们做 Dapp 主要关注两个方面,
- 钱包签名验签
- sendTransaction 和 处理 transaction 的执行结果
以太坊生态不是十分健全,钱包应用做的良莠不齐,No.1 当属 MetaMask,这里又一个非常有用的 GitHub pages:https://danfinlay.github.io/js-eth-personal-sign-examples/ ,可以在钱包中检测签名兼容性十分有用。
因为博文时效性的问题,MathWallet、TrustWallet、imToken、MetaMask Mobile 这些钱包都会有些许不同,不展开描述每个钱包的异同。
连接钱包
现在是非常注重隐私的时代,在用户首次进入您的 Dapp 应用时,可能只是想浏览基本信息,尚未决定要参与进来。这时候不能进入页面立即请求连接钱包,获取当前钱包的一些信息。
如果我们要连接钱包的话有这么几种:
- MetaMask 为主的 PC 浏览器端离线钱包
- imToken、TrustWallet 为主的移动端离线钱包
- Portis 等的线上 iframe 嵌入钱包
如果要维护这么多钱包的接入工作,对于一个小团队来说十分繁琐,所以推荐使用 Web3Modal/web3modal 的统一解决方案,十分便捷(如果贵司有对项目进行改进,一定要同步到上游做贡献哦)
免密码登录
Dapp 的前端开发里面,使用 Web3 与钱包节点交互是重中之重,那么参考 CryptoKitties 等一些知名的 Dapp 项目的交互来说:
- 首先进入 Dapp 后,会展示一些统计、说明类的信息(此时并不会要求钱包授权获取用户当前选择的钱包地址)
- 放置一个
Connect
按钮,点击后再进行window.ethereum.enable()
之类的初始化web3js
的操作。 - 然后可以进行钱包签名免密码登录。
说到 钱包签名登录,坑就多了。在签名验签这里,负责签名的前端是很好处理的,直接将参数传入签名方法即可,但是负责验签的后端就比较考验能力了(先留个坑,后面奶爸可能把部署、测试工具,及签名使用的 lib 抽取出来在 GitHub 上面发布)。
Transaction 处理
首先是由 abi 初始化合约实例,然后调用一些读、写的方法。主要还是多看 web3 的文档。
对于 区块重组 这个事情对前端来说影响不大,只要你是完全去中心化的,数据都会最终一致,前端在重组时那短暂的展示数据不一致不会造成影响。
在 transaction 执行失败时,你或许想要获取错误信息然后展示出来,看博文最后一个部分里面有个取 revert 信息的库。
Transaction 即便是链上确认后,节点的读接口也可能有几秒钟的数据延时,这里就需要在 操作前对某些业务上的数据进行快照,在链上确认后先验证数据刷新,再对页面上的数据进行更新。
Transaction 重入
因为 Transaction 从广播到链上确认需要时间,如果这期间用户关闭了页面你当如何?这里奶爸从项目中总结了一些经验:
- 把所有与链交互相关的按钮的状态(loading)集合到 state 里面
- 将 Transaction 与用户绑定,持久化到数据库中(包含 提交时间、操作名称、TransactionHash、extraData (可能用于 Transaction 确认后的节点数据刷新验证))
- 前端在网页刷新后,拉取 Transaction 列表,对有待获取结果的 Transaction 进行二次确认,将操作相关的按钮置为 loading 状态
- 取到 Transaction 最终结果后,对按钮状态进行更新
对用户 Transaction 历史的保存有两种方式,一种是保存在服务端,另一种是储存在用户的 localStorage 里面,储存在 localStorage 里面时要注意实现基于钱包地址的操作隔离逻辑。
大数运算与展示
Dapp 开发中,不论是展示还是运算,都少不了跟 BigNumber
打交道,ERC20
的代笔包括 ether
都是 18 位的。那么在我司几个项目中,最佳实践是,在前端逻辑运算、展示时,使用 BigNumber.js 这个库,然后在与链交互,将要发起 Transaction 时呢 使用 web3 使用的 bn.js 库,由 BigNumber 对象格式化为字符串,然后再转化为 BN 对象。
因为 BN 库不能进行小数运算和展示,所以结合 BigNumber.js 与 BN.js 的话既保证了展示的多样性,又不会产生精度问题,还能顺利与链交互。
一些有用的东西
- https://www.trufflesuite.com/drizzle Dapp 前端框架 · React
- https://github.com/ethjs 轻量级 Web3
- https://github.com/justinjmoses/eth-reveal 取 transaction 的 revert 信息(目前只能在主网使用)