diff --git a/package.json b/package.json index 7df4016..10531db 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pezkuwi-telegram-miniapp", - "version": "1.0.166", + "version": "1.0.167", "type": "module", "description": "Pezkuwichain Telegram Mini App - Forum, Announcements, Rewards", "author": "Pezkuwichain Team", diff --git a/src/components/wallet/FundFeesModal.tsx b/src/components/wallet/FundFeesModal.tsx index e6d8c95..a579235 100644 --- a/src/components/wallet/FundFeesModal.tsx +++ b/src/components/wallet/FundFeesModal.tsx @@ -1,24 +1,14 @@ /** - * Fund Fees Modal - XCM Teleport HEZ between Relay Chain and Parachains - * Supports bidirectional teleport: Relay ↔ Asset Hub / People Chain + * Fund Fees Modal - XCM Teleport HEZ to Teyerchains + * Allows users to transfer HEZ from relay chain to Asset Hub or People chain for fees */ import { useState, useEffect } from 'react'; -import { - X, - ArrowDown, - Loader2, - CheckCircle, - AlertCircle, - Fuel, - Info, - ArrowLeftRight, -} from 'lucide-react'; +import { X, ArrowDown, Loader2, CheckCircle, AlertCircle, Fuel, Info } from 'lucide-react'; import { useWallet } from '@/contexts/WalletContext'; import { useTelegram } from '@/hooks/useTelegram'; type TargetChain = 'asset-hub' | 'people'; -type TeleportDirection = 'to-parachain' | 'to-relay'; interface ChainInfo { id: TargetChain; @@ -55,7 +45,6 @@ export function FundFeesModal({ isOpen, onClose }: Props) { const { hapticImpact, showAlert } = useTelegram(); const [targetChain, setTargetChain] = useState('asset-hub'); - const [direction, setDirection] = useState('to-parachain'); const [amount, setAmount] = useState(''); const [isTransferring, setIsTransferring] = useState(false); const [txStatus, setTxStatus] = useState<'idle' | 'signing' | 'pending' | 'success' | 'error'>( @@ -67,38 +56,6 @@ export function FundFeesModal({ isOpen, onClose }: Props) { const selectedChain = TARGET_CHAINS.find((c) => c.id === targetChain) || TARGET_CHAINS[0]; - // Get source balance based on direction - const getSourceBalance = () => { - if (direction === 'to-parachain') { - return relayBalance; - } - return targetChain === 'asset-hub' ? assetHubBalance : peopleBalance; - }; - - // Get destination balance based on direction - const getDestBalance = () => { - if (direction === 'to-parachain') { - return targetChain === 'asset-hub' ? assetHubBalance : peopleBalance; - } - return relayBalance; - }; - - // Get source chain name - const getSourceChainName = () => { - if (direction === 'to-parachain') { - return 'Relay Chain'; - } - return selectedChain.name; - }; - - // Get destination chain name - const getDestChainName = () => { - if (direction === 'to-parachain') { - return selectedChain.name; - } - return 'Relay Chain'; - }; - // Fetch balances useEffect(() => { const fetchBalances = async () => { @@ -164,8 +121,12 @@ export function FundFeesModal({ isOpen, onClose }: Props) { } }, [api, assetHubApi, peopleApi, address, isOpen]); + const getTargetBalance = () => { + return targetChain === 'asset-hub' ? assetHubBalance : peopleBalance; + }; + const handleTeleport = async () => { - if (!address || !keypair) { + if (!api || !address || !keypair) { showAlert('Cizdan girêdayî nîne'); return; } @@ -175,34 +136,19 @@ export function FundFeesModal({ isOpen, onClose }: Props) { return; } - const sourceBalance = getSourceBalance(); - if (sourceBalance === '--') { - showAlert('Zincîr girêdayî nîne'); + if (relayBalance === '--') { + showAlert('Relay Chain girêdayî nîne'); return; } const sendAmount = parseFloat(amount); - const currentBalance = parseFloat(sourceBalance); + const currentBalance = parseFloat(relayBalance); if (sendAmount > currentBalance) { showAlert('Bakiye têrê nake'); return; } - // Get the appropriate API based on direction - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let sourceApi: any; - if (direction === 'to-parachain') { - sourceApi = api; - } else { - sourceApi = targetChain === 'asset-hub' ? assetHubApi : peopleApi; - } - - if (!sourceApi) { - showAlert('API girêdayî nîne'); - return; - } - setIsTransferring(true); setTxStatus('signing'); hapticImpact('medium'); @@ -211,125 +157,103 @@ export function FundFeesModal({ isOpen, onClose }: Props) { // Convert to smallest unit (12 decimals) const amountInSmallestUnit = BigInt(Math.floor(parseFloat(amount) * 1e12)); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let dest: any; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let beneficiary: any; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let assets: any; + // Get target teyrchain ID + const targetTeyrchainId = selectedChain.teyrchainId; - // isParaTeleport: true if sending FROM teyrchain - const isParaTeleport = direction === 'to-relay'; - - if (direction === 'to-parachain') { - // Relay Chain → Teyrchain - const targetTeyrchainId = selectedChain.teyrchainId; - - dest = { - V4: { - parents: 0, - interior: { - X1: [{ Parachain: targetTeyrchainId }], - }, - }, - }; - } else { - // Teyrchain → Relay Chain - dest = { - V4: { - parents: 1, - interior: 'Here', - }, - }; - } - - beneficiary = { - V4: { + // Destination: Target teyrchain + const dest = { + V3: { parents: 0, interior: { - X1: [ - { - AccountId32: { - id: sourceApi.createType('AccountId32', address).toHex(), - network: null, - }, - }, - ], + X1: { teyrchain: targetTeyrchainId }, }, }, }; - assets = { - V4: [ + // Beneficiary: Same account on target chain + const beneficiary = { + V3: { + parents: 0, + interior: { + X1: { + accountid32: { + network: null, + id: api.createType('AccountId32', address).toHex(), + }, + }, + }, + }, + }; + + // Assets: Native token (HEZ) + const assets = { + V3: [ { + id: { + Concrete: { + parents: 0, + interior: 'Here', + }, + }, fun: { Fungible: amountInSmallestUnit.toString(), }, - id: { - parents: isParaTeleport ? 1 : 0, - interior: 'Here', - }, }, ], }; - const feeAssetItem = 0; - const weightLimit = { Unlimited: null }; + // Fee asset ID: Native HEZ token + const feeAssetId = { + V3: { + Concrete: { + parents: 0, + interior: 'Here', + }, + }, + }; - // Find XCM pallet: xcmPallet (relay) or pezkuwiXcm (teyrchains) - const XCM_PALLETS = ['xcmPallet', 'pezkuwiXcm', 'xcm']; - const palletName = XCM_PALLETS.find( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (p) => (sourceApi.tx as any)[p]?.limitedTeleportAssets - ); - if (!palletName) { - throw new Error('XCM pallet nehate dîtin'); - } + const weightLimit = 'Unlimited'; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const tx = (sourceApi.tx as any)[palletName].limitedTeleportAssets( + // Create teleport transaction + const tx = api.tx.xcmPallet.limitedTeleportAssets( dest, beneficiary, assets, - feeAssetItem, + feeAssetId, weightLimit ); setTxStatus('pending'); - const unsub = await tx.signAndSend( - keypair, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - ({ status, dispatchError }: any) => { - if (status.isFinalized) { - if (dispatchError) { - let errorMessage = 'Teleport neserketî'; + const unsub = await tx.signAndSend(keypair, ({ status, dispatchError }) => { + if (status.isFinalized) { + if (dispatchError) { + let errorMessage = 'Teleport neserketî'; - if (dispatchError.isModule) { - const decoded = sourceApi.registry.findMetaError(dispatchError.asModule); - errorMessage = `${decoded.section}.${decoded.name}`; - } - - setTxStatus('error'); - hapticImpact('heavy'); - showAlert(errorMessage); - } else { - setTxStatus('success'); - hapticImpact('medium'); - - // Reset after success - setTimeout(() => { - setAmount(''); - setTxStatus('idle'); - onClose(); - }, 2000); + if (dispatchError.isModule) { + const decoded = api.registry.findMetaError(dispatchError.asModule); + errorMessage = `${decoded.section}.${decoded.name}`; } - setIsTransferring(false); - unsub(); + setTxStatus('error'); + hapticImpact('heavy'); + showAlert(errorMessage); + } else { + setTxStatus('success'); + hapticImpact('medium'); + + // Reset after success + setTimeout(() => { + setAmount(''); + setTxStatus('idle'); + onClose(); + }, 2000); } + + setIsTransferring(false); + unsub(); } - ); + }); } catch (error) { console.error('Teleport error:', error); setTxStatus('error'); @@ -340,19 +264,13 @@ export function FundFeesModal({ isOpen, onClose }: Props) { }; const setQuickAmount = (percent: number) => { - const balance = parseFloat(getSourceBalance()); + const balance = parseFloat(relayBalance); if (balance > 0) { const quickAmount = ((balance * percent) / 100).toFixed(4); setAmount(quickAmount); } }; - const toggleDirection = () => { - setDirection((prev) => (prev === 'to-parachain' ? 'to-relay' : 'to-parachain')); - setAmount(''); - hapticImpact('light'); - }; - if (!isOpen) return null; return ( @@ -383,7 +301,7 @@ export function FundFeesModal({ isOpen, onClose }: Props) {

Serketî!

- {amount} HEZ bo {getDestChainName()} hate şandin + {amount} HEZ bo {selectedChain.name} hate şandin

) : txStatus === 'error' ? ( @@ -430,36 +348,14 @@ export function FundFeesModal({ isOpen, onClose }: Props) { - {/* Direction Toggle */} -
- -
- {/* Balance Display */}
-
- {getSourceChainName()} +
+ Relay Chain
- {getSourceBalance()} HEZ + {relayBalance} HEZ
@@ -470,26 +366,34 @@ export function FundFeesModal({ isOpen, onClose }: Props) {
- {getDestChainName()} + {selectedChain.name}
- {getDestBalance()} HEZ + {getTargetBalance()} HEZ
{/* Info Box */} -
- -

- {direction === 'to-parachain' - ? `${selectedChain.description} kêmî 0.1 HEZ tê pêşniyarkirin.` - : 'HEZ ji teyrchainê vedigere Relay Chainê.'} +

+ +

+ {selectedChain.description} kêmî 0.1 HEZ tê pêşniyarkirin.

@@ -554,7 +458,7 @@ export function FundFeesModal({ isOpen, onClose }: Props) { ) : ( <> - Bo {getDestChainName()} Bişîne + Bo {selectedChain.name} Bişîne )} diff --git a/src/version.json b/src/version.json index 558f7c7..196c5d3 100644 --- a/src/version.json +++ b/src/version.json @@ -1,5 +1,5 @@ { - "version": "1.0.166", - "buildTime": "2026-02-07T21:01:47.580Z", - "buildNumber": 1770498107581 + "version": "1.0.167", + "buildTime": "2026-02-07T21:08:36.401Z", + "buildNumber": 1770498516402 }