Răsfoiți Sursa

feat: 币余额显示

lushdog@outlook.com 1 săptămână în urmă
părinte
comite
9b750d9b44

+ 54 - 0
src/app/api/my-lp/getBalanceByToken/route.ts

@@ -0,0 +1,54 @@
+import { NextRequest, NextResponse } from 'next/server'
+import { connection } from '@/lib/config'
+import { Token } from '@/lib/byreal-clmm-sdk/src/client/token'
+
+export async function GET(request: NextRequest) {
+	try {
+		const searchParams = request.nextUrl.searchParams
+		const tokenAddress = searchParams.get('tokenAddress')
+		const accountAddress = searchParams.get('accountAddress')
+
+		// 验证必需参数
+		if (!tokenAddress || !accountAddress) {
+			return NextResponse.json(
+				{
+					retCode: 400,
+					retMsg: '缺少必需参数:tokenAddress 和 accountAddress',
+				},
+				{ status: 400 }
+			)
+		}
+
+		// 创建 Token 实例并查询余额
+		const token = new Token(connection)
+		const result = await token.detectTokenTypeAndGetBalance(
+			accountAddress,
+			tokenAddress
+		)
+
+		return NextResponse.json({
+			retCode: 0,
+			retMsg: '查询成功',
+			result: {
+				data: {
+					tokenAddress,
+					accountAddress,
+					balance: Number(result.balance).toFixed(2),
+					isToken2022: result.isToken2022,
+				},
+			},
+		})
+	} catch (error) {
+		console.error('API Route Error:', error)
+		return NextResponse.json(
+			{
+				retCode: 500,
+				retMsg:
+					error instanceof Error
+						? error.message
+						: '服务器内部错误',
+			},
+			{ status: 500 }
+		)
+	}
+}

+ 64 - 1
src/app/components/DataTable.tsx

@@ -1,7 +1,7 @@
 'use client'
 
 import { TickMath } from '@/lib/byreal-clmm-sdk/src/instructions/utils/tickMath'
-import { useEffect, useState } from 'react'
+import { useEffect, useState, useRef } from 'react'
 import { Table, Select, Typography, Tag, Button, InputNumber, App } from 'antd'
 
 interface TableData {
@@ -41,7 +41,9 @@ interface PoolInfo {
 		address: string
 		symbol?: string
 		decimals?: number
+		price?: number
 		mintInfo?: {
+			address?: string
 			symbol?: string
 			decimals?: number
 		}
@@ -50,7 +52,9 @@ interface PoolInfo {
 		address: string
 		symbol?: string
 		decimals?: number
+		price?: number
 		mintInfo?: {
+			address?: string
 			symbol?: string
 			decimals?: number
 		}
@@ -74,6 +78,18 @@ function DataTableContent() {
 	const [poolOptions, setPoolOptions] = useState<PoolOption[]>([])
 	const [quickCopyAmount, setQuickCopyAmount] = useState<number>(1)
 
+	const [balance, setBalance] = useState<number>(0)
+	const [tokenName, setTokenName] = useState<string>('')
+	const userAddressRef = useRef<string>('')
+	const poolsListRef = useRef<PoolsListResponse>({
+		retCode: 0,
+		result: {
+			data: {
+				records: []
+			}
+		}
+	})
+
 	const [selectedPoolAddress, setSelectedPoolAddress] = useState<string>(
 		'FPBW9dtVRoUug2BeUKZAzaknd6iiet9jHM8RcTvwUkyC'
 	)
@@ -95,6 +111,46 @@ function DataTableContent() {
 
 	const [priceLower, setPriceLower] = useState<number>(0)
 	const [priceUpper, setPriceUpper] = useState<number>(0)
+	const [balanceUsd, setBalanceUsd] = useState<number>(0)
+
+	const fetchBalance = async (tokenAddress: string, userAddress: string, price: number) => {
+		const response = await fetch(`/api/my-lp/getBalanceByToken?tokenAddress=${tokenAddress}&accountAddress=${userAddress}`)
+		const result = await response.json()
+		setBalance(result.result.data.balance)
+		setBalanceUsd(Number((Number(result.result.data.balance) * price).toFixed(2)))
+	}
+
+	function fetchAddress() {
+		fetch('/api/my-lp/getAddress')
+			.then((res) => res.json())
+			.then((data) => {
+				userAddressRef.current = data.address
+			})
+			.catch((err) => {
+				console.error('Error fetching address:', err)
+				message.error('获取地址失败')
+			})
+	}
+
+	const getTokenBalance = async (result: PoolsListResponse, selectedPoolAddress: string) => {
+		const poolInfo = result?.result?.data?.records?.find((option) => option.poolAddress === selectedPoolAddress)
+		const symbolA = poolInfo?.mintA?.mintInfo?.symbol || ''
+		const symbolB = poolInfo?.mintB?.mintInfo?.symbol || ''
+		let label = ''
+		let address = ''
+		let price = 0
+		if (symbolA === 'USDC' || symbolA === 'USDT' || symbolA === 'SOL') {
+			address = poolInfo?.mintB?.mintInfo?.address || ''
+			label = symbolB
+			price = poolInfo?.mintB?.price || 0
+		} else {
+			address = poolInfo?.mintA?.mintInfo?.address || ''
+			label = symbolA
+			price = poolInfo?.mintA?.price || 0
+		}
+		setTokenName(label || '')
+		fetchBalance(address, userAddressRef.current, price)
+	}
 
 	// 获取 pools 列表
 	const fetchPoolsList = async () => {
@@ -115,7 +171,9 @@ function DataTableContent() {
 						value: pool.poolAddress,
 					}
 				})
+				poolsListRef.current = result
 				setPoolOptions(options)
+				getTokenBalance(result, selectedPoolAddress)
 			}
 		} catch (error) {
 			console.error('Error fetching pools list:', error)
@@ -200,6 +258,7 @@ function DataTableContent() {
 	}
 
 	const init = async () => {
+		await fetchAddress()
 		await fetchPoolsList()
 		await fetchData(1, 100)
 	}
@@ -545,7 +604,10 @@ function DataTableContent() {
 	}
 
 	const handlePoolChange = (value: string) => {
+		setBalance(0)
+		setBalanceUsd(0)
 		setSelectedPoolAddress(value)
+		getTokenBalance(poolsListRef.current, value)
 		fetchData(1, 100, value)
 	}
 
@@ -760,6 +822,7 @@ function DataTableContent() {
 						(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
 					}
 				/>
+				<span className="ml-2 mr-2 text-lg font-bold text-green-500">余额:{balance} {tokenName} (${balanceUsd})</span>
 				<Button type="primary" className="ml-2 mr-2" onClick={handleRefresh}>
 					刷新
 				</Button>