前端如何与合约交互

概述

最近朋友考虑找个 web3 的远程工作,之前的 web3 项目黄了,就整理了下 web3 相关的代码分享出来希望可以帮助大家对合约交互有个大致的了解。

主要功能

  • OKX、MateMask、Phontom 等钱包的连接

  • EVM、Tron、Solana 等多链的合约交互

项目结构

bash 复制代码
web3-start/
├── src/
│   ├── components/           # 前端交互组件(如钱包交互、交易面板等)
│       ├── Interaction/      # 合约交互功能页面
│       ├── SelectChain/      # 选择链页面
│       ├── SelectWallet/     # 选择钱包页面
│   ├── constants/            # 各链配置、常量定义
│   ├── contracts/            # 智能合约源码
│   ├── hook/                 # 业务逻辑 hooks(如钱包连接、交易处理、余额查询等)
│   ├── lib/                  # 区块链交互libs(如 EVM 交易等)
│   ├── store/                # 状态管理(钱包、余额、用户信息等)
│   ├── types/                # TypeScript 类型声明
├── public/                   # 公共资源目录
├── .env                      # 环境变量(API Key等配置)
├── README.md                 # 项目说明文档
├── package.json              # 依赖与脚本配置

钱包交互实现详解

项目支持多种钱包(如 MetaMask、OKX、TronLink、Sui Wallet)连接与账户管理,核心逻辑主要分布在 src/hook/useConnectWallet.ts 和相关组件中。以下将以 EVM 钱包为例,详细剖析钱包连接和链上交易的实现方式。

1. 钱包连接(以 EVM/MetaMask 为例)

连接钱包主要通过调用浏览器注入的钱包(如 window.ethereum),并请求账户授权:

typescript 复制代码
const connectEvmWallet = async () => {
  try {
    const provider = getProvider();
    // 请求用户授权并连接钱包
    const { accounts } = await connectAsync({
      connector: provider,
      chainId: CHAIN[chainType.toUpperCase()].id,
    });
    await handleConnectSuccess(accounts[0]);
  } catch (error) {
    handleConnectError(error);
  }
};

对于 OKX、Tron、Sui 等钱包,也有专门的连接方法,例如:

typescript 复制代码
const connectTronWallet = async () => {
  const currentProvider = window?.tronLink;
  subscribeTronWallet();
  window?.tron.request({ method: "eth_requestAccounts" }).then((res: any) => {
    addressRef.current = currentProvider.tronWeb.defaultAddress.base58;
    handleSignMessage(
      currentProvider.tronWeb.defaultAddress.base58,
      CHAIN.TRON.brief
    );
  });
};

2. 钱包事件监听

连接钱包后,需要监听如账户切换、断开连接等事件:

typescript 复制代码
const subscribeSuiWallet = async () => {
  const provider = window.okxwallet.sui;
  provider.features["standard:events"].on("connect", () =>
    setIsConnected(true)
  );
  provider.features["standard:events"].on(
    "accountChanged",
    (publicKey: any) => {
      if (publicKey) {
        console.log(`Switched to account ${publicKey.toBase58()}`);
      }
    }
  );
  provider.features["standard:events"].on("disconnect", () => {
    // disconnect();
  });
};

余额查询与链上交互

钱包连接成功后,可获取当前账户的余额,展示在前端页面上:

typescript 复制代码
const fetchBalanceLogic = async (set: any, chain: any, address: string) => {
  set({ isLoading: true });
  let balance: any = null;

  if (isEvmChain(chain.brief)) {
    balance = await getEvmBalance(chain.brief, address);
    set({
      balance: {
        origin: balance,
        value: formatUnits(balance, chain.decimals),
      },
    });
    return;
  }

  // 其他链(如Solana、Tron)处理方式
  // ...
};

合约交互与交易流程

前端通过钱包签名发起交易,完成如转账链上操作。典型流程如下:

1. 发起交易

src/components/Interaction/index.tsx 中,用户输入金额后点击按钮即可发起交易:

tsx 复制代码
const handleTrade = async () => {
  if (!inputValue || Number(inputValue) <= 0) {
    addToast({ title: "Please enter a valid amount", color: "danger" });
    return;
  }
  // 判断余额是否足够
  if (Number(inputValue) >= 1) {
    addToast({ title: "Please enter a amount < 1", color: "danger" });
    return;
  }

  try {
    const voteTokenAmount = parseUnits(
      inputValue,
      CHAIN[chain.brief!.toUpperCase()]?.decimals ?? 18
    );
    // ...额外判断和授权逻辑
    setLoading(true);

    await handleTradeFunc({
      inputValue: Number(inputValue),
      address,
      voteToken: {
        tokenAddress: "",
        chainType: chain.brief,
        tokenDecimals: CHAIN[chain.brief!.toUpperCase()]?.decimals,
      },
      mainTokenBalance: balance.origin,
    });

    setShowTradeSuccess(true);
    setTimeout(() => setShowTradeSuccess(false), 2000);
  } catch (error: any) {
    // ...错误提示
  } finally {
    setLoading(false);
  }
};

2. EVM 链合约交互(签名 & 发送交易)

src/lib/okxEvm.ts 中,使用 viem 库和钱包签名实现交易发送:

typescript 复制代码
const publicClient = createPublicClient({ chain, transport: http() });
const { request } = await publicClient.simulateContract({
  address: params.smartContractAddress as `0x${string}`,
  abi: EvmVoteAbi,
  functionName: "placeVote",
  args: [
    [
      params.voteId,
      params.tokenAddress,
      params.tokenAmount,
      params.expireTimestamp,
      params.signature,
    ],
  ],
  value: parseUnits(params.tokenAmount, 0),
  account: params.senderAddress as `0x${string}`,
});

// 发送交易
const walletClient = createWalletClient({
  chain,
  transport: custom(window?.ethereum),
});
const result = await walletClient.writeContract(request);

源码及在线体验

github 地址: github.com/jiandandkl/...

在线 demo: web3-start-sandy.vercel.app/

相关推荐
运维开发王义杰1 天前
Cosmos:构建下一代互联网的“区块链互联网
web3·区块链
Sui_Network2 天前
Swarm Network 选择 Walrus 实现可验证 AI
人工智能·物联网·web3·区块链·量子计算
Sui_Network2 天前
Sui 在非洲增长最快的科技市场开设 SuiHub Lagos 以推动创新
大数据·人工智能·科技·游戏·web3·区块链
读创商闻2 天前
Web3+AI融合新纪元:Sollong用智能终端重塑协作计算未来
人工智能·web3
gaog2zh4 天前
0201-solidity基础-区块链-web3
web3·solidity
代码羊羊4 天前
Web3 常用前端库介绍
前端·web3
dingzd954 天前
借助它,在Web3投资赛道抢占先机
web3·互联网·facebook·tiktok·instagram·指纹浏览器·clonbrowser
Hello.Reader4 天前
Web3智能合约技术论述
web3·区块链·智能合约
清 晨5 天前
Web3 支付系统:面向企业和消费者的全面概述
web3·互联网·facebook·tiktok·instagram·指纹浏览器·clonbrowser