11import { useState , useEffect } from 'react' ;
2- import { useTonWallet } from '@tonconnect/ui-react' ;
3- import { TonClient , Address } from 'ton' ;
4- import { fromNano } from 'ton-core' ;
5- import { Buffer } from 'buffer' ;
2+ import { useTonConnectUI } from '@tonconnect/ui-react' ;
63
7- // Polyfill for browser environment
8- window . Buffer = Buffer ;
9-
10- const JETTON_MINTER_ADDRESS = 'EQA5QopV0455mb09Nz6iPL3JsX_guIGf77a6l-DtqSQh0aE-' ;
11-
12- // Create a single TonClient instance
13- const client = new TonClient ( {
14- endpoint : 'https://toncenter.com/api/v2/jsonRPC' ,
15- } ) ;
4+ // Jetton Master Contract для RUBLE
5+ const RUBLE_JETTON_MASTER = 'EQA5QopV0455mb09Nz6iPL3JsX_guIGf77a6l-DtqSQh0aE-' ;
166
177export const useWalletBalances = ( ) => {
18- const wallet = useTonWallet ( ) ;
19- const [ balanceTon , setBalanceTon ] = useState ( 0 ) ;
20- const [ balanceRuble , setBalanceRuble ] = useState ( 0 ) ;
21- const [ isLoading , setIsLoading ] = useState ( false ) ;
8+ const [ tonConnectUI ] = useTonConnectUI ( ) ;
9+ const [ balances , setBalances ] = useState ( {
10+ ton : 0 ,
11+ ruble : 0 ,
12+ loading : true ,
13+ error : null
14+ } ) ;
2215
23- useEffect ( ( ) => {
24- const fetchBalances = async ( ) => {
25- if ( ! wallet ) {
26- setBalanceTon ( 0 ) ;
27- setBalanceRuble ( 0 ) ;
28- return ;
29- }
16+ const fetchBalances = async ( ) => {
17+ if ( ! tonConnectUI . account ) {
18+ setBalances ( { ton : 0 , ruble : 0 , loading : false , error : null } ) ;
19+ return ;
20+ }
3021
31- setIsLoading ( true ) ;
32- try {
33- // Fetch TON balance
34- const address = Address . parse ( wallet . account . address ) ;
35- const tonBalance = await client . getBalance ( address ) ;
36- setBalanceTon ( Number ( fromNano ( tonBalance ) ) ) ;
22+ try {
23+ setBalances ( prev => ( { ...prev , loading : true , error : null } ) ) ;
3724
38- // Fetch Jetton (RUBLE) balance
39- const minterAddress = Address . parse ( JETTON_MINTER_ADDRESS ) ;
40-
41- // 1. Get user's Jetton wallet address from the minter
42- const result = await client . runMethod ( minterAddress , 'get_wallet_address' , [
43- { type : 'slice' , cell : new Address ( address . workChain , address . hash ) . toCell ( ) } ,
44- ] ) ;
45- const jettonWalletAddress = result . stack . readAddress ( ) ;
25+ const walletAddress = tonConnectUI . account . address ;
26+
27+ // Получаем баланс TON
28+ const tonBalance = await fetchTonBalance ( walletAddress ) ;
29+
30+ // Получаем баланс RUBLE (Jetton)
31+ const rubleBalance = await fetchJettonBalance ( walletAddress , RUBLE_JETTON_MASTER ) ;
4632
47- // 2. Get Jetton data from the user's Jetton wallet
48- const jettonData = await client . runMethod (
49- jettonWalletAddress ,
50- 'get_jetton_data'
51- ) ;
52-
53- const jettonBalance = jettonData . stack . readBigNumber ( ) ;
54- // Assuming the Jetton has 9 decimals, like TON
55- setBalanceRuble ( Number ( fromNano ( jettonBalance ) ) ) ;
33+ setBalances ( {
34+ ton : tonBalance ,
35+ ruble : rubleBalance ,
36+ loading : false ,
37+ error : null
38+ } ) ;
39+ } catch ( error ) {
40+ console . error ( 'Failed to fetch balances:' , error ) ;
41+ setBalances ( prev => ( {
42+ ...prev ,
43+ loading : false ,
44+ error : error . message
45+ } ) ) ;
46+ }
47+ } ;
5648
57- } catch ( error ) {
58- console . error ( 'Failed to fetch balances:' , error ) ;
59- setBalanceTon ( 0 ) ;
60- setBalanceRuble ( 0 ) ;
61- } finally {
62- setIsLoading ( false ) ;
49+ // Получение баланса TON
50+ const fetchTonBalance = async ( address ) => {
51+ try {
52+ const url = new URL ( 'https://toncenter.com/api/v2/getAddressBalance' ) ;
53+ url . searchParams . append ( 'address' , address ) ;
54+
55+ const tonResponse = await fetch ( url ) ;
56+ const tonData = await tonResponse . json ( ) ;
57+
58+ if ( tonData . ok ) {
59+ // Конвертируем из nanotons в TON (1 TON = 10^9 nanotons)
60+ return parseFloat ( tonData . result ) / 1000000000 ;
6361 }
64- } ;
62+ return 0 ;
63+ } catch ( error ) {
64+ console . error ( 'Failed to fetch TON balance:' , error ) ;
65+ return 0 ;
66+ }
67+ } ;
6568
69+ // Получение баланса Jetton
70+ const fetchJettonBalance = async ( address , jettonMaster ) => {
71+ try {
72+ // Сначала получаем адрес Jetton Wallet
73+ const walletUrl = new URL ( 'https://toncenter.com/api/v2/getJettonWalletAddress' ) ;
74+ walletUrl . searchParams . append ( 'owner_address' , address ) ;
75+ walletUrl . searchParams . append ( 'jetton_master' , jettonMaster ) ;
76+
77+ const walletResponse = await fetch ( walletUrl ) ;
78+ const walletData = await walletResponse . json ( ) ;
79+
80+ if ( ! walletData . ok || ! walletData . result ) {
81+ return 0 ;
82+ }
83+
84+ const jettonWalletAddress = walletData . result ;
85+
86+ // Теперь получаем баланс Jetton Wallet
87+ const balanceUrl = new URL ( 'https://toncenter.com/api/v2/getAddressBalance' ) ;
88+ balanceUrl . searchParams . append ( 'address' , jettonWalletAddress ) ;
89+
90+ const balanceResponse = await fetch ( balanceUrl ) ;
91+ const balanceData = await balanceResponse . json ( ) ;
92+
93+ if ( balanceData . ok && balanceData . result ) {
94+ // Конвертируем из jetton units в обычные единицы
95+ // RUBLE Jetton имеет 9 знаков после запятой
96+ return parseFloat ( balanceData . result ) / 1000000000 ;
97+ }
98+ return 0 ;
99+ } catch ( error ) {
100+ console . error ( 'Failed to fetch Jetton balance:' , error ) ;
101+ return 0 ;
102+ }
103+ } ;
104+
105+ // Обновляем балансы при изменении кошелька
106+ useEffect ( ( ) => {
66107 fetchBalances ( ) ;
67- } , [ wallet ] ) ;
108+ } , [ tonConnectUI . account ?. address ] ) ;
109+
110+ // Автоматическое обновление балансов каждые 30 секунд
111+ useEffect ( ( ) => {
112+ if ( ! tonConnectUI . account ) return ;
113+
114+ const interval = setInterval ( fetchBalances , 30000 ) ;
115+ return ( ) => clearInterval ( interval ) ;
116+ } , [ tonConnectUI . account ?. address ] ) ;
68117
69- return { balanceTon, balanceRuble, isLoading } ;
70- } ;
118+ return {
119+ ...balances ,
120+ refetch : fetchBalances
121+ } ;
122+ } ;
0 commit comments