import React, { useState, useEffect } from 'react'; import { usePezkuwi } from '@/contexts/PezkuwiContext'; import { useWallet } from '@/contexts/WalletContext'; import { X, AlertCircle, Loader2, CheckCircle, Info, ArrowDownUp } from 'lucide-react'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { useToast } from '@/hooks/use-toast'; interface InitializeHezPoolModalProps { isOpen: boolean; onClose: () => void; onSuccess?: () => void; } type TransactionStatus = 'idle' | 'signing' | 'submitting' | 'success' | 'error'; type WrapMode = 'wrap' | 'unwrap'; export const InitializeHezPoolModal: React.FC = ({ isOpen, onClose, onSuccess, }) => { // Use Asset Hub API for DEX operations (tokenWrapper pallet is on Asset Hub) const { assetHubApi, isAssetHubReady } = usePezkuwi(); const { account, signer } = useWallet(); const { toast } = useToast(); const [mode, setMode] = useState('wrap'); const [amount, setAmount] = useState('10000'); const [hezBalance, setHezBalance] = useState('0'); const [whezBalance, setWhezBalance] = useState('0'); const [palletAvailable, setPalletAvailable] = useState(null); const [txStatus, setTxStatus] = useState('idle'); const [errorMessage, setErrorMessage] = useState(''); // Reset form when modal closes or mode changes useEffect(() => { if (!isOpen) { setAmount('10000'); setTxStatus('idle'); setErrorMessage(''); } }, [isOpen]); useEffect(() => { setTxStatus('idle'); setErrorMessage(''); }, [mode]); // Check if tokenWrapper pallet is available on Asset Hub useEffect(() => { const checkPallet = async () => { if (!assetHubApi || !isAssetHubReady) { setPalletAvailable(null); return; } try { // Check if tokenWrapper pallet exists on Asset Hub const hasTokenWrapper = assetHubApi.tx.tokenWrapper !== undefined && assetHubApi.tx.tokenWrapper.wrap !== undefined && assetHubApi.tx.tokenWrapper.unwrap !== undefined; setPalletAvailable(hasTokenWrapper); if (import.meta.env.DEV) { console.log('🔍 TokenWrapper pallet on Asset Hub:', hasTokenWrapper); } } catch (error) { if (import.meta.env.DEV) console.error('Failed to check pallet:', error); setPalletAvailable(false); } }; checkPallet(); }, [assetHubApi, isAssetHubReady]); // Fetch balances from Asset Hub useEffect(() => { const fetchBalances = async () => { if (!assetHubApi || !isAssetHubReady || !account) return; try { // HEZ balance (native on Asset Hub) const balance = await assetHubApi.query.system.account(account); const freeBalance = (balance as { data: { free: { toString: () => string } } }).data.free.toString(); setHezBalance(freeBalance); // wHEZ balance (asset 2 on Asset Hub - tokenWrapper creates asset 2) const whezData = await assetHubApi.query.assets.account(2, account); const whezTyped = whezData as { isSome: boolean; unwrap: () => { balance: { toString: () => string } } }; setWhezBalance(whezTyped.isSome ? whezTyped.unwrap().balance.toString() : '0'); } catch (error) { if (import.meta.env.DEV) console.error('Failed to fetch balances from Asset Hub:', error); } }; fetchBalances(); // Refetch after successful transaction if (txStatus === 'success') { const timer = setTimeout(fetchBalances, 2000); return () => clearTimeout(timer); } }, [assetHubApi, isAssetHubReady, account, txStatus]); const handleTransaction = async () => { if (!assetHubApi || !isAssetHubReady || !signer || !account) { toast({ title: 'Error', description: 'Please connect your wallet and wait for Asset Hub connection', variant: 'destructive', }); return; } if (!palletAvailable) { setErrorMessage('TokenWrapper pallet is not available on Asset Hub.'); toast({ title: 'Pallet Not Available', description: 'The TokenWrapper pallet is not deployed on Asset Hub.', variant: 'destructive', }); return; } const amountRaw = BigInt(parseFloat(amount) * 10 ** 12); if (amountRaw <= BigInt(0)) { setErrorMessage('Amount must be greater than zero'); return; } const sourceBalance = mode === 'wrap' ? hezBalance : whezBalance; if (amountRaw > BigInt(sourceBalance)) { setErrorMessage(`Insufficient ${mode === 'wrap' ? 'HEZ' : 'wHEZ'} balance`); return; } setTxStatus('signing'); setErrorMessage(''); try { const isWrap = mode === 'wrap'; if (import.meta.env.DEV) { console.log(`🔄 ${isWrap ? 'Wrapping' : 'Unwrapping'} on Asset Hub...`, { amount, amountRaw: amountRaw.toString(), }); } const tx = isWrap ? assetHubApi.tx.tokenWrapper.wrap(amountRaw.toString()) : assetHubApi.tx.tokenWrapper.unwrap(amountRaw.toString()); setTxStatus('submitting'); await tx.signAndSend( account, { signer }, ({ status, dispatchError, events }) => { if (import.meta.env.DEV) console.log('📦 Transaction status:', status.type); if (status.isInBlock) { if (import.meta.env.DEV) console.log('✅ In block:', status.asInBlock.toHex()); if (dispatchError) { let errorMsg = ''; if (dispatchError.isModule) { const decoded = assetHubApi.registry.findMetaError(dispatchError.asModule); errorMsg = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`; if (import.meta.env.DEV) console.error('❌ Module error:', errorMsg); } else { errorMsg = dispatchError.toString(); if (import.meta.env.DEV) console.error('❌ Dispatch error:', errorMsg); } setErrorMessage(errorMsg); setTxStatus('error'); toast({ title: 'Transaction Failed', description: errorMsg, variant: 'destructive', }); } else { if (import.meta.env.DEV) console.log(`✅ ${isWrap ? 'Wrap' : 'Unwrap'} successful!`); if (import.meta.env.DEV) console.log('📋 Events:', events.map(e => e.event.method).join(', ')); setTxStatus('success'); toast({ title: 'Success!', description: isWrap ? `Successfully wrapped ${amount} HEZ to wHEZ` : `Successfully unwrapped ${amount} wHEZ to HEZ`, }); onSuccess?.(); } } } ); } catch (error) { if (import.meta.env.DEV) console.error('Transaction failed:', error); setErrorMessage(error instanceof Error ? error.message : 'Transaction failed'); setTxStatus('error'); toast({ title: 'Error', description: error instanceof Error ? error.message : 'Transaction failed', variant: 'destructive', }); } }; if (!isOpen) return null; const hezBalanceDisplay = (parseFloat(hezBalance) / 10 ** 12).toLocaleString(undefined, { maximumFractionDigits: 4 }); const whezBalanceDisplay = (parseFloat(whezBalance) / 10 ** 12).toLocaleString(undefined, { maximumFractionDigits: 4 }); const sourceToken = mode === 'wrap' ? 'HEZ' : 'wHEZ'; const targetToken = mode === 'wrap' ? 'wHEZ' : 'HEZ'; const sourceBalance = mode === 'wrap' ? hezBalanceDisplay : whezBalanceDisplay; const sourceBalanceRaw = mode === 'wrap' ? hezBalance : whezBalance; return (
Token Wrapping
Admin Only - Token Wrapping
{/* Pallet Availability Warning */} {palletAvailable === false && ( TokenWrapper pallet not deployed. Please contact the development team. )} {/* Tabs for Wrap / Unwrap */} setMode(v as WrapMode)} className="w-full"> HEZ → wHEZ wHEZ → HEZ Convert native HEZ to wHEZ (wrapped). Ratio: 1:1 Convert wHEZ back to native HEZ. Ratio: 1:1 {/* Balances Display */}
Native HEZ
{hezBalanceDisplay}
Wrapped wHEZ
{whezBalanceDisplay}
{/* Amount Input */}
Available: {sourceBalance} {sourceToken}
setAmount(e.target.value)} placeholder="10000" className="w-full px-4 py-3 bg-gray-800 border border-gray-700 rounded-lg text-white text-lg" disabled={txStatus === 'signing' || txStatus === 'submitting'} />

💡 You will receive {amount} {targetToken} (1:1 ratio)

{/* Error Message */} {errorMessage && ( {errorMessage} )} {/* Success Message */} {txStatus === 'success' && ( Successfully {mode === 'wrap' ? 'wrapped' : 'unwrapped'} {amount} {sourceToken} to {targetToken}! )} {/* Action Buttons */}
); };