如何在zk 上构建前端dApp

发布于:2023-08-08 18:24:00

#头条创作挑战赛#

构建前端 dApp

#设置项目

我们使用VueWeb 框架作为教程前端(过程与其他框架类似)。为了专注于zksync-web3SDK,我们提供了一个预构建的模板。设置完成后,我们添加与刚刚部署的智能合约交互的代码。

克隆模板并cd放入文件夹中

git clone https://github.com/matter-labs/greeter-tutorial-starter cd greeter-tutorial-starter

启动项目

yarnyarn serve

在浏览器中导航以http://localhost:8080/查看正在运行的应用程序。

#将帐户连接到 dApp

#智能账户

启用智能账户允许您加入已经使用 zkSync***个版本的 Argent 账户抽象钱包用户。

使用此库来验证您的智能帐户兼容性。遵循本指南在新窗口中打开将 Argent 登录添加到您的 dApp。

#外部拥有账户 (EOA)

为了与基于 zkSync 构建的 dApp 进行交互,请将 MetaMask 钱包连接到 zkSync Era 测试网。

按照本指南将 Metamask 连接到 zkSync。

#将资金桥接到 L2

使用我们的门户网站在新窗口中打开将资金桥接至 zkSync。使用水龙头在新窗口中打开在您的帐户中获取一些测试 ERC20 代币。

笔记

当从主网桥接到 zkSync Era 上的智能账户(例如 Argent)时,您必须通过单击“存款到 zkSync Era 主网”上的另一个地址来指定 L2 钱包的地址。

#项目结构

在./src/App.vue文件的functions:部分中,您将看到存储应用程序的模板代码。

提供了大部分代码。您必须完成 TODO: 部分。

functions: {initializeProviderAndSigner() {// TODO: initialize provider and signer based on `window.ethereum`},async getGreeting() {// TODO: return the current greetingreturn "";},async getFee() {// TODO: return formatted feereturn "";},async getBalance() {// Return formatted balancereturn "";},async getOverrides() {if (this.selectedToken.l1Address != ETH_L1_ADDRESS) {// TODO: Return data for the paymaster}return {};},...

在<script>标签下方,有一些占位符,用于表示已部署合约的地址Greeter:GREETER_CONTRACT_ADDRESS及其 ABI 的路径:GREETER_CONTRACT_ABI。

<script>// eslint-disable-next-lineconst GREETER_CONTRACT_ADDRESS = ""; // TODO: insert the Greeter contract address here// eslint-disable-next-lineconst GREETER_CONTRACT_ABI = []; // TODO: Complete and import the ABI

#添加库

从greeter-tutorial-starter根目录安装依赖项。yarn add ethers@^5.7.2 zksync-web3<script>在下添加库导入App.vue。<script>import {} from "zksync-web3";import {} from "ethers";// eslint-disable-next-lineconst GREETER_CONTRACT_ADDRESS = ""; // TODO: insert the Greeter contract address here// eslint-disable-next-lineconst GREETER_CONTRACT_ABI = []; // TODO: Complete and import the ABI

#添加ABI和合约地址

信息

为了与部署到 zkSync 的智能合约进行交互,我们需要它的 ABI。ABI 代表应用程序二进制接口,是描述合约变量和函数、名称和类型的 json。

创建./src/abi.json文件。您可能会在存储库中找到一个,但最好使用您创建的一个。

将合同的

ABI./artifacts-zk/contracts/Greeter.sol/Greeter.json从上一节的 Hardhat 项目文件夹中的文件复制/粘贴到abi.json. 该文件应如下所示: [{"inputs": [{"internalType": "string","name": "_greeting","type": "string"}],"stateMutability": "nonpayable","type": "constructor"},{"inputs": [],"name": "greet","outputs": [{"internalType": "string","name": "","type": "string"}],"stateMutability": "view","type": "function"},{"inputs": [{"internalType": "string","name": "_greeting","type": "string"}],"name": "setGreeting","outputs": [],"stateMutability": "nonpayable","type": "function"}]

设置GREETER_CONTRACT_ABI需要ABI文件,并添加Greeter合约地址。

// eslint-disable-next-lineconst GREETER_CONTRACT_ADDRESS = "0x...";// eslint-disable-next-lineconst GREETER_CONTRACT_ABI = require("./abi.json");

#与 Web3 提供商合作

转到

initializeProviderAndSigner中的函数./src/App.vue。该函数在连接 Metamask 成功后调用。

在这个函数中我们应该:

初始化aWeb3Provider和aSigner与zkSync交互。初始化Contract对象以与Greeter我们刚刚部署的合约进行交互。

在之前的导入下导入必要的依赖项:

import { Contract, Web3Provider, Provider } from "zksync-web3";

像这样初始化提供者、签名者和合约实例:

initializeProviderAndSigner() {this.provider = new Provider(https://testnet.era.zksync.dev);// Note that we still need to get the Metamask signerthis.signer = (new Web3Provider(window.ethereum)).getSigner();this.contract = new Contract(GREETER_CONTRACT_ADDRESS,GREETER_CONTRACT_ABI,this.signer );},

#检索问候语

填写函数以从智能合约中检索问候语:

async getGreeting() {// Smart contract calls work the same way as in `ethers`return await this.contract.greet();},

该函数如下所示:

initializeProviderAndSigner() {this.provider = new Provider(https://testnet.era.zksync.dev);// Note that we still need to get the Metamask signerthis.signer = (new Web3Provider(window.ethereum)).getSigner();this.contract = new Contract(GREETER_CONTRACT_ADDRESS,GREETER_CONTRACT_ABI,this.signer );},async getGreeting() {return await this.contract.greet();},

将 Metamask 钱包连接到 zkSync Era 测试网后,您应该看到以下页面:

选择代币下拉菜单允许您选择使用哪种代币支付费用。

#检索代币余额和交易费用

检索用户余额的最简单方法是使用该Signer.getBalance函数。

将必要的依赖项添加到之前添加导入的同一位置:

// `ethers` is only used in this tutorial for its utility functionsimport { ethers } from "ethers";

实现功能:

async getBalance() {// Getting the balance for the signer in the selected tokenconst balanceInUnits = await this.signer.getBalance(this.selectedToken.l2Address);// To display the number of tokens in the human-readable format, we need to format them,// e.g. if balanceInUnits returns 500000000000000000 wei of ETH, we want to display 0.5 ETH the userreturn ethers.utils.formatUnits(balanceInUnits, this.selectedToken.decimals);},

预估费用:

async getFee() {// Getting the amount of gas (gas) needed for one transactionconst feeInGas = await this.contract.estimateGas.setGreeting(this.newGreeting);// Getting the gas price per one erg. For now, it is the same for all tokens.const gasPriceInUnits = await this.provider.getGasPrice();// To display the number of tokens in the human-readable format, we need to format them,// e.g. if feeInGas*gasPriceInUnits returns 500000000000000000 wei of ETH, we want to display 0.5 ETH the userreturn ethers.utils.formatUnits(feeInGas.mul(gasPriceInUnits), this.selectedToken.decimals);},

现在,当您选择支付费用的代币时,即可获得交易的余额和预期费用。

单击刷新重新计算费用。费用取决于我们要存储为问候语的消息的长度。

也可以单击“更改问候语”按钮,但由于我们尚未实现该功能,所以什么也不会发生。

#更新问候语

App.vue使用以下代码更新函数:

async changeGreeting() {this.txStatus = 1;try {const txHandle = await this.contract.setGreeting(this.newGreeting, await this.getOverrides());this.txStatus = 2;// Wait until the transaction is committedawait txHandle.wait();this.txStatus = 3;// Update greetingthis.greeting = await this.getGreeting();this.retreivingFee = true;this.retreivingBalance = true;// Update balance and feethis.currentBalance = await this.getBalance();this.currentFee = await this.getFee();} catch (e) {alert(JSON.stringify(e));}this.txStatus = 0;this.retreivingFee = false;this.retreivingBalance = false;},

现在您可以添加新的问候消息并通过 MetaMask 的交易将其发送到合约。您将看到前端的 Greeter 消息发生变化。

您现在拥有一个功能齐全的 Greeter-dApp!然而,它尚未利用任何 zkSync 特定的功能。

笔记

您是否看到wallet_requestPermissions错误?

刷新浏览器,或在浏览器上打开 MetaMask 扩展程序,然后单击“下一步”“取消”即可解决。

在MetaMask 文档中阅读有关wallet_requestPermissions,的更多信息在新窗口中打开。

#使用测试网 paymaster 支付费用

zkSync Era 账户抽象功能允许您集成可以完全为您支付费用的付款人,或者即时交换您的代币。

我们将使用所有 zkSync Era 测试网上提供的测试网络 paymaster 。

信息

测试网Paymaster允许用户使用任何ERC20代币支付费用,汇率为Token:ETH 1:1,即一单位代币兑换一wei ETH。

这意味着小数位数比 ETH 少的代币的交易费用会更高;例如,USDC 只有 6 位小数。这是测试网付款大师的已知行为,该行为仅用于演示目的。

主网上的付款大师

测试网付款人在新窗口中打开纯粹是为了演示此功能,不会在主网上提供。

在主网上集成您的协议时,您应该遵循您使用的付款主管的文档,或者创建您自己的协议。

当用户决定使用以太币付款时,该getOverrides函数返回一个空对象,但是当用户选择 ERC20 选项时,它应该返回付款人地址及其所需的所有信息。操作方法如下:

要从 zkSync 提供商检索测试网付款主管的地址,请添加一个新函数getOverrides:

async getOverrides() {if (this.selectedToken.l1Address != ETH_L1_ADDRESS) {const testnetPaymaster = await this.provider.getTestnetPaymasterAddress();// ..}return {};}

信息

建议在每次交互之前检索测试网付款人的地址,因为它可能会发生变化。

添加到与之前utils相同的 SDK 导入:zksync-web3

import { Contract, Web3Provider, Provider, utils } from "zksync-web3";

我们需要计算处理交易需要多少代币。由于测试网出纳员以 1:1 的比例将任何 ERC20 代币兑换为 ETH,因此金额与 wei 中的 ETH 金额相同:

async getOverrides() {if (this.selectedToken.l1Address != ETH_L1_ADDRESS) {const testnetPaymaster = await this.provider.getTestnetPaymasterAddress();const gasPrice = await this.provider.getGasPrice();// estimate gasLimit via paymasterconst paramsForFeeEstimation = utils.getPaymasterParams( testnetPaymaster,{type: "ApprovalBased",minimalAllowance: ethers.BigNumber.from("1"),token: this.selectedToken.l2Address,innerInput: new Uint8Array(),});// estimate gasLimit via paymasterconst gasLimit = await this.contract.estimateGas.setGreeting(this.newGreeting,{customData: {gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT,paymasterParams: paramsForFeeEstimation,},});const fee = gasPrice.mul(gasLimit);// ..}return {};}

现在,剩下的就是按照协议要求对 paymasterInput 进行编码并返回所需的覆盖。

复制/粘贴以下完整函数:

async getOverrides() {if (this.selectedToken.l1Address != ETH_L1_ADDRESS) {const testnetPaymaster =await this.provider.getTestnetPaymasterAddress();const gasPrice = await this.provider.getGasPrice();// estimate gasLimit via paymasterconst paramsForFeeEstimation = utils.getPaymasterParams( testnetPaymaster,{type: "ApprovalBased",minimalAllowance: ethers.BigNumber.from("1"),token: this.selectedToken.l2Address,innerInput: new Uint8Array(),});// estimate gasLimit via paymasterconst gasLimit = await this.contract.estimateGas.setGreeting(this.newGreeting,{customData: {gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT,paymasterParams: paramsForFeeEstimation,},});const fee = gasPrice.mul(gasLimit.toString());const paymasterParams = utils.getPaymasterParams(testnetPaymaster, {type: "ApprovalBased",token: this.selectedToken.l2Address,minimalAllowance: fee,// empty bytes as testnet paymaster does not use innerInputinnerInput: new Uint8Array(),});return {maxFeePerGas: gasPrice,maxPriorityFeePerGas: ethers.BigNumber.from(0), gasLimit,customData: {gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, paymasterParams,},};}return {};},

要使用 ERC20 代币列表,请更改以下行:

const allowedTokens = require("./eth.json");

到以下一项:

const allowedTokens = require("./erc20.json");

该erc20.json文件包含一些代币,例如 DAI、USDC 和 wBTC。

#完整的应用程序

现在您应该能够使用 ETH 或任何可用的代币更新问候消息。

选择一种 ERC20 代币以查看预估费用:

单击按钮Change greeting更新消息。由于paymasterParams已提供,交易将是EIP712(有关 EIP712 的更多信息,请参见此处在新窗口中打开):

单击“签名”发送交易。

交易处理完成后,页面会更新余额,并且可以查看新的问候语。

您已使用测试网 paymaster 使用 ERC20 代币支付了本次交易


免责声明:本站所有内容及图片均采集来源于网络,并无商业使用,如若侵权请联系删除。

上一篇:怎样从零开始设计一个购物平台?

下一篇:潍坊网站建设做网站公司怎么样

资讯 观察行业视觉,用专业的角度,讲出你们的心声。
MORE

I NEED TO BUILD WEBSITE

我需要建站

*请认真填写需求信息,我们会在24小时内与您取得联系。