You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js调用zkSync外部API获取代币余额及动态传参问题

问题1:动态拼接API地址+修复异步状态bug

你当前代码里setAccounts是React异步更新方法,调用后立即执行getBalases拿到的还是更新前的Accounts值,优先改这两个点:

  1. 给getBalases增加入参接收钱包地址,避免读取旧状态
  2. 拼接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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 07:15:02