Next.js调用zkSync外部API获取代币余额及动态传参问题
问题1:动态拼接API地址+修复异步状态bug
你当前代码里setAccounts是React异步更新方法,调用后立即执行getBalases拿到的还是更新前的Accounts值,优先改这两个点:
- 给
getBalases增加入参接收钱包地址,避免读取旧状态 - 拼接URL时直接使用传入的地址,替换硬编码内容
问题2:提取指定token余额
根据你给出的接口返回结构,id=0对应ETH代币,你可以用Array.find()方法筛选对应id的代币,拿到余额后存入状态,就可以在页面渲染。建议新增余额存储的状态,用来在页面展示。
注意事项
- 绝对不要在前端代码里暴露助记词,你当前把
MNEMONIC写在前端组件里会直接泄露资产,交易相关的逻辑建议移到后端或者改用钱包签名的方式实现 - 调用接口前先判断地址是否合法,避免无效请求
修改后的完整代码
import { useState } from "react"; import { Contract, utils, ethers } from 'ethers' import ConnectMetamaskButton from '../components/ConnectMetamaskButton'; import zkswapABI from '../../zkswap.ABI.json' import * as zksync from "zksync" export default function ConnectWallet(props) { const [Accounts, setAccounts] = useState("Connect Metamask"); // 新增余额存储状态 const [ethBalance, setEthBalance] = useState("--"); const ethersProvider = ethers.getDefaultProvider("ropsten"); // 警告:以下助记词逻辑严禁放在前端,仅保留原有逻辑供参考,建议立刻迁移到后端 var MNEMONIC = process.env.MNEMONIC; const ethWallet = ethers.Wallet.fromMnemonic(MNEMONIC).connect(ethersProvider); console.log("Accounts = ", Accounts); async function ConnectMetamask() { try { const newAccounts = await ethereum.request({ method: 'eth_requestAccounts', }) const currentAddress = newAccounts[0] setAccounts(currentAddress); // 直接把最新地址传给查询余额方法 getBalases(currentAddress); } catch (error) { console.error(error); } }; // 新增入参接收地址 async function getBalases(address) { if(!address || address === "Connect Metamask") return console.log("address = ", address); // 动态拼接URL const zkSyncUrl = `https://api.zks.app/v2/3/account/${address}/balances`; const response = await fetch(zkSyncUrl); const res = await response.json(); console.log("data = ", res); // 提取ETH余额,id=0对应ETH if(res.success) { const ethToken = res.data.balances.tokens.find(item => item.id === 0) if(ethToken) { setEthBalance(ethToken.amount) } } }; async function withdrawETH() { const syncProvider = await zksync.getDefaultProvider("ropsten"); const syncWallet = await zksync.Wallet.fromEthSigner(ethWallet, syncProvider); const withdraw = await syncWallet.withdrawFromSyncToEthereum({ ethAddress: ethWallet.address, token: "ETH", amount: ethers.utils.parseEther("0.001"), }); } async function depositETH() { let ABI = zkswapABI; let ZKSwapContract = '0x010254cd670aCbb632A1c23a26Abe570Ab2Bc467' const contract = new Contract(ZKSwapContract, ABI, ethWallet) const tx = await contract.depositETH(ethWallet.address, { value: utils.parseEther('0.1') }) return tx } // 补充event参数 async function zkSyncToZKSwap(event) { event.preventDefault(); console.log("amount = ", event.target.amount.value); withdrawETH(); depositETH(); } return ( <div> <header className="text-gray-100 bg-gray-900 body-font shadow w-full"> <div className="container mx-auto flex flex-wrap p-5 flex-col md:flex-row items-center"> <nav className="flex lg:w-2/5 flex-wrap items-center text-base md:ml-auto"> {/* 新增余额展示位置 */} <span className="mr-5">ETH余额:{ethBalance}</span> </nav> <a className="flex order-first lg:order-none lg:w-1/5 title-font font-medium items-center lg:items-center lg:justify-center mb-4 md:mb-0"> <span className="ml-3 text-xl">L2 DEX HUB</span> </a> <div className="lg:w-2/5 inline-flex lg:justify-end ml-5 lg:ml-0"> <ConnectMetamaskButton Accounts={Accounts} onClick={() => { ConnectMetamask(); }}></ConnectMetamaskButton> </div> </div> </header> <div> <section className="h-screen w-4/5 max-w-5xl mx-auto flex items-center justify-center flex-col"> <form onSubmit={zkSyncToZKSwap}> <div className="flex flex-col rounded-lg overflow-hidden sm:flex-row"> <label htmlFor="amount"></label> <input className="py-3 px-4 bg-gray-200 text-gray-800 border-gray-300 border-2 outline-none placeholder-gray-500 focus:bg-gray-100" id="amount" type="text" name="amount" placeholder="Amount" /> <button className="py-3 px-4 bg-gray-700 text-gray-100 font-semibold uppercase hover:bg-gray-600" type="submit" >Exchange</button> </div> </form> </section> </div> </div> ); };
修改说明:
- 新增
ethBalance状态存储ETH余额,在头部导航栏展示 - 修复
setAccounts异步导致的旧地址问题,直接将最新获取的地址传入getBalases方法 - 接口URL改为模板字符串动态拼接传入的钱包地址
- 新增接口返回解析逻辑,筛选id为0的ETH代币获取余额存入状态
- 修复表单提交方法未接收
event参数的问题,修复input的非标准amount属性为标准name属性
内容的提问来源于stack exchange,提问作者user16697491
相关产品推荐
相关产品推荐

