import React, { useState } from 'react'; import { usePolkadot } from '@/contexts/PolkadotContext'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { ArrowRight, Loader2, CheckCircle, XCircle } from 'lucide-react'; import { useToast } from '@/hooks/use-toast'; interface TokenBalance { assetId: number; symbol: string; name: string; balance: string; decimals: number; usdValue: number; } interface TransferModalProps { isOpen: boolean; onClose: () => void; selectedAsset?: TokenBalance | null; } type TokenType = 'HEZ' | 'PEZ' | 'USDT' | 'BTC' | 'ETH' | 'DOT'; interface Token { symbol: TokenType; name: string; assetId?: number; decimals: number; color: string; } const TOKENS: Token[] = [ { symbol: 'HEZ', name: 'Hez Token', decimals: 12, color: 'from-green-600 to-yellow-400' }, { symbol: 'PEZ', name: 'Pez Token', assetId: 1, decimals: 12, color: 'from-blue-600 to-purple-400' }, { symbol: 'USDT', name: 'Tether USD', assetId: 2, decimals: 6, color: 'from-green-500 to-green-600' }, { symbol: 'BTC', name: 'Bitcoin', assetId: 3, decimals: 8, color: 'from-orange-500 to-yellow-500' }, { symbol: 'ETH', name: 'Ethereum', assetId: 4, decimals: 18, color: 'from-purple-500 to-blue-500' }, { symbol: 'DOT', name: 'Polkadot', assetId: 5, decimals: 10, color: 'from-pink-500 to-red-500' }, ]; export const TransferModal: React.FC = ({ isOpen, onClose, selectedAsset }) => { const { api, isApiReady, selectedAccount } = usePolkadot(); const { toast } = useToast(); const [selectedToken, setSelectedToken] = useState('HEZ'); const [recipient, setRecipient] = useState(''); const [amount, setAmount] = useState(''); const [isTransferring, setIsTransferring] = useState(false); const [txStatus, setTxStatus] = useState<'idle' | 'signing' | 'pending' | 'success' | 'error'>('idle'); const [txHash, setTxHash] = useState(''); // Use the provided selectedAsset or fall back to token selection const currentToken = selectedAsset ? { symbol: selectedAsset.symbol as TokenType, name: selectedAsset.name, assetId: selectedAsset.assetId, decimals: selectedAsset.decimals, color: selectedAsset.assetId === 0 ? 'from-green-600 to-yellow-400' : selectedAsset.assetId === 2 ? 'from-emerald-500 to-teal-500' : 'from-cyan-500 to-blue-500', } : TOKENS.find(t => t.symbol === selectedToken) || TOKENS[0]; const handleTransfer = async () => { if (!api || !isApiReady || !selectedAccount) { toast({ title: "Error", description: "Wallet not connected", variant: "destructive", }); return; } if (!recipient || !amount) { toast({ title: "Error", description: "Please fill in all fields", variant: "destructive", }); return; } setIsTransferring(true); setTxStatus('signing'); try { // Import web3FromAddress to get the injector const { web3FromAddress } = await import('@polkadot/extension-dapp'); const injector = await web3FromAddress(selectedAccount.address); // Convert amount to smallest unit const amountInSmallestUnit = BigInt(parseFloat(amount) * Math.pow(10, currentToken.decimals)); let transfer; // Create appropriate transfer transaction based on token type // wHEZ uses native token transfer (balances pallet), all others use assets pallet if (currentToken.assetId === undefined || (selectedToken === 'HEZ' && !selectedAsset)) { // Native HEZ token transfer transfer = api.tx.balances.transferKeepAlive(recipient, amountInSmallestUnit.toString()); } else { // Asset token transfer (wHEZ, PEZ, wUSDT, etc.) transfer = api.tx.assets.transfer(currentToken.assetId, recipient, amountInSmallestUnit.toString()); } setTxStatus('pending'); // Sign and send transaction const unsub = await transfer.signAndSend( selectedAccount.address, { signer: injector.signer }, ({ status, events, dispatchError }) => { if (status.isInBlock) { console.log(`Transaction included in block: ${status.asInBlock}`); setTxHash(status.asInBlock.toHex()); } if (status.isFinalized) { console.log(`Transaction finalized: ${status.asFinalized}`); // Check for errors if (dispatchError) { let errorMessage = 'Transaction failed'; if (dispatchError.isModule) { const decoded = api.registry.findMetaError(dispatchError.asModule); errorMessage = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } setTxStatus('error'); toast({ title: "Transfer Failed", description: errorMessage, variant: "destructive", }); } else { setTxStatus('success'); toast({ title: "Transfer Successful!", description: `Sent ${amount} ${currentToken.symbol} to ${recipient.slice(0, 8)}...${recipient.slice(-6)}`, }); // Reset form after 2 seconds setTimeout(() => { setRecipient(''); setAmount(''); setTxStatus('idle'); setTxHash(''); onClose(); }, 2000); } setIsTransferring(false); unsub(); } } ); } catch (error: any) { console.error('Transfer error:', error); setTxStatus('error'); setIsTransferring(false); toast({ title: "Transfer Failed", description: error.message || "An error occurred during transfer", variant: "destructive", }); } }; const handleClose = () => { if (!isTransferring) { setRecipient(''); setAmount(''); setTxStatus('idle'); setTxHash(''); setSelectedToken('HEZ'); onClose(); } }; return ( {selectedAsset ? `Send ${selectedAsset.symbol}` : 'Send Tokens'} {selectedAsset ? `Transfer ${selectedAsset.name} to another account` : 'Transfer tokens to another account'} {txStatus === 'success' ? (

Transfer Successful!

Your transaction has been finalized

{txHash && (
Transaction Hash
{txHash}
)}
) : txStatus === 'error' ? (

Transfer Failed

Please try again

) : (
{/* Token Selection - Only show if no asset is pre-selected */} {!selectedAsset && (
)}
setRecipient(e.target.value)} placeholder="5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY" className="bg-gray-800 border-gray-700 text-white mt-2" disabled={isTransferring} />
setAmount(e.target.value)} placeholder="0.0000" className="bg-gray-800 border-gray-700 text-white mt-2" disabled={isTransferring} />
Decimals: {currentToken.decimals}
{txStatus === 'signing' && (

Please sign the transaction in your Polkadot.js extension

)} {txStatus === 'pending' && (

Transaction pending... Waiting for finalization

)}
)}
); };