免费mint的发布中产生的用户体验问题。
前提概要
公司在发行白名单mint NFT的时候,作为合约开发者,把有限个白名单用户存储在合约中。在合约中通过两个struct 存储两个内容:当前mint的轮次,以及用户在的白名单信息。
struct MintWhitelist {address paymentAddress;address nftAddress;uint256 amount;uint256 price;uint256 nonce;}struct Supply {uint256 startTime;uint256 endTime;uint256 mintedAmount;uint256 totalSupply;}struct MintWhitelist { address paymentAddress; address nftAddress; uint256 amount; uint256 price; uint256 nonce; } struct Supply { uint256 startTime; uint256 endTime; uint256 mintedAmount; uint256 totalSupply; }struct MintWhitelist { address paymentAddress; address nftAddress; uint256 amount; uint256 price; uint256 nonce; } struct Supply { uint256 startTime; uint256 endTime; uint256 mintedAmount; uint256 totalSupply; }
为了能够让前端小伙伴读取数据,并能够在合约代码中知道用户的mint数量,通过mapping 存储了相应的()mint轮次信息,和(用户地址→ 轮次→用户信息)用户白名单信息。
// adress ->stage-> MintWhiteListmapping(address => mapping (string => MintWhitelist)) public mintWhitelistMap;// stage => supplymapping(string => Supply) public nftSupplyMap;// adress ->stage-> MintWhiteList mapping(address => mapping (string => MintWhitelist)) public mintWhitelistMap; // stage => supply mapping(string => Supply) public nftSupplyMap;// adress ->stage-> MintWhiteList mapping(address => mapping (string => MintWhitelist)) public mintWhitelistMap; // stage => supply mapping(string => Supply) public nftSupplyMap;
在最初的设计中,mint白名单的活动信息,以及用户能够mint的数量已经可以通过合约中方法的调用来获取。
作为一个虔诚的web3开发者,这种处理方式并无不妥。然而……
1. Web2 的产品经理
通过测试小伙伴的努力之下,我们的产品终于到产品经理那里进行验收。
1.1 此时问题
产品经理的验收过程中发现如果没有切换到对应的网络,那么此时的前端数据是无法显示的。
?
Contract developer: 这是正常的现象啊,用户没有切换网络,前段也就没有拿到对应合约发布网络的rpc节点信息。此时肯定是拿不到的啊。
前端代码和合约的交互步骤是先获得用户此时的rpc节点信息,然后通过调用合约中的nftSupplyMap和mintWhitelistMap
实现的代码示例:
// 导入Ether.js库和智能合约ABIimport { ethers } from 'ethers';import contractABI from 'path/to/contractABI.json';// 创建以太坊Provider和智能合约实例const provider = new ethers.providers.JsonRpcProvider('http://localhost:8545'); // 连接到本地节点const contractAddress = '0x123456789abcdef'; // 合约地址const contract = new ethers.Contract(contractAddress, contractABI, provider); // 创建合约实例// 调用智能合约方法contract.methodName(arg1, arg2).then((result) => {console.log(result);}).catch((error) => {console.error(error);});// 导入Ether.js库和智能合约ABI import { ethers } from 'ethers'; import contractABI from 'path/to/contractABI.json'; // 创建以太坊Provider和智能合约实例 const provider = new ethers.providers.JsonRpcProvider('http://localhost:8545'); // 连接到本地节点 const contractAddress = '0x123456789abcdef'; // 合约地址 const contract = new ethers.Contract(contractAddress, contractABI, provider); // 创建合约实例 // 调用智能合约方法 contract.methodName(arg1, arg2).then((result) => { console.log(result); }).catch((error) => { console.error(error); });// 导入Ether.js库和智能合约ABI import { ethers } from 'ethers'; import contractABI from 'path/to/contractABI.json'; // 创建以太坊Provider和智能合约实例 const provider = new ethers.providers.JsonRpcProvider('http://localhost:8545'); // 连接到本地节点 const contractAddress = '0x123456789abcdef'; // 合约地址 const contract = new ethers.Contract(contractAddress, contractABI, provider); // 创建合约实例 // 调用智能合约方法 contract.methodName(arg1, arg2).then((result) => { console.log(result); }).catch((error) => { console.error(error); });
代码中的Provider 和用户metamask连接网络有关系。如果此时用户连接的是polygon测试网,而polygon 主网,此时就会出现信息获取失败的情况。
Production Manager: 但是我想要的效果是用户不登录我们的网站,同时也不需要用户切换metamask网络。
?
Contract Developer: 好吧,显然这个是想通过后端配合来实现,而不是通过单纯的前端直接连接web3网络。
1.2 解决方案
产品侧想要用户不需要做任何操作,就能够查看白名单mint的活动信息,并且不需要切换钱包的网络,也能够查询用户个人mint信息的查询。
于是乎,我们从原来的方案一改为方案二:
2. CTO的后端愤怒
CTO: 怎么可以这么设计,这个搞的话,如果用户如果集体过来访问的话,我们后端不就直接挂了吗?
Contract Develop: (一脸茫然) 原来是后端从接收的查询活动信息和用户信息的请求,到消息的返回需要将近两秒中的时间。
如果集体的访问,确实会出现这种问题。这时候肯定有小伙伴问,为什么不通过Database进行存储用户的信息以及活动信息呢??
答案是可以的,但是如果保证用户的信息准确性,是我们比较头疼的问题,如果此时通过数据库进行存储,那么此时我们必须能够知道用户什么时候进行mint的操作了,也就是能够在用户执行mint操作后,更改用户剩余能够mint的数量。
如果用户此时是按照正常的逻辑(前端mint → 调用合约→ 交易hash回传)那么此时是没问题的。可是我们不能够保证用户操作的原子性,因为此时存在和合约的交互。
如果用户此时在合约交互中存在超时,或者突然刷新,导致合约层是成功的,但是没把交易数据进行回传,那么我们数据库存在的数据就是不对的。
这也就是我们想要通过查询合约中的数据来获取用户和活动信息的原因。
3. 最终的解决方案
虽然此次的上线的是一个很小的功能,但是确实是存在很多的问题。这是web2 到web3过程中必然存在的问题。因为区块链和传统的中心话操作存在数据延迟,速度慢等问题。
最后我们不得不为这个简单的功能,增加另外一套解决方法。
在上图中,扫快服务在用户合约交互后,但没有进行hash回传到后端时候,进行交易信息补偿。这种补偿行为会进行用户可以mint信息的校验,同时增加活动信息中已经mint的数量。
4.总结
这篇文章主要讲述了在发行免费mint(白名单)时,存储用户信息的方式导致的前端体验问题。合约中存储了用户的mint数量和白名单信息,通过mapping存储了相应的信息。然而,在产品经理验收时发现,如果没有切换到对应的网络,前端数据是无法显示的。为了解决这个问题,将方案一改为从后端配合实现,用户不需要做任何操作就能够查看白名单mint的活动信息,也不需要切换钱包的网络,也能够查询用户个人mint信息的查询。