chore(dex): remove the XCM configuration wizard (#59)

The founder-only wizard registered PezkuwiChain as a teyrchain on
Westend, Rococo or Polkadot (Rococo is shut down) and does nothing in
the current architecture. XCMBridgeSetupModal was not mounted anywhere.
Remove both, their xcm-wizard and xcm-bridge libraries, the DEX admin
card, their translations in all six locales, and the typecheck baseline
entries for the deleted files.
This commit is contained in:
SatoshiQaziMuhammed authored and GitHub committed 2026-10-19 20:46:13 +04:00
1 parent b778493eaa
commit ac730481d9
12 files changed
-3041

No files matched your search

-6
View File
@@ -8,10 +8,6 @@
10 ../shared/lib/validator-pool.ts TS2339
2 ../shared/lib/welati.ts TS2305
24 ../shared/lib/welati.ts TS2339
1 ../shared/lib/xcm-bridge.ts TS2353
1 ../shared/lib/xcm-bridge.ts TS2554
5 ../shared/lib/xcm-wizard.ts TS2339
1 ../shared/lib/xcm-wizard.ts TS2345
1 src/components/AddLiquidityModal.tsx TS2339
4 src/components/AddLiquidityModal.tsx TS2345
2 src/components/AddLiquidityModal.tsx TS2352
@@ -34,8 +30,6 @@
2 src/components/admin/CommissionSetupTab.tsx TS2339
14 src/components/admin/CommissionVotingTab.tsx TS2339
1 src/components/admin/CommissionVotingTab.tsx TS2345
1 src/components/admin/XCMConfigurationWizard.tsx TS2339
5 src/components/admin/XCMConfigurationWizard.tsx TS2345
14 src/components/dashboard/CommissionProposalsCard.tsx TS2339
1 src/components/delegation/DelegationManager.tsx TS2322
1 src/components/delegation/DelegationManager.tsx TS2345
-403
View File
@@ -1,403 +0,0 @@
/**
* XCM Bridge Service
*
* Handles Asset Hub USDT → wUSDT bridge configuration
* User-friendly abstraction over complex XCM operations
*
* ALFA TESTNET MODE: Mock XCM for standalone chain testing
* BETA+ MODE: Real XCM with Rococo/Westend Asset Hub
*/
import { ApiPromise, WsProvider } from '@pezkuwi/api';
import type { Signer } from '@pezkuwi/api/types';
// Detect mock mode (alfa testnet)
const IS_MOCK_MODE = typeof process !== 'undefined'
? process.env.VITE_MOCK_XCM === 'true'
: typeof import.meta !== 'undefined'
? import.meta.env?.VITE_MOCK_XCM === 'true'
: false;
// Mock XCM state management (localStorage)
const MOCK_XCM_STORAGE_KEY = 'pezkuwi_mock_xcm_configured';
function getMockXcmConfigured(): boolean {
if (typeof window === 'undefined') return false;
return localStorage.getItem(MOCK_XCM_STORAGE_KEY) === 'true';
}
function setMockXcmConfigured(configured: boolean): void {
if (typeof window === 'undefined') return;
localStorage.setItem(MOCK_XCM_STORAGE_KEY, String(configured));
}
// Westend Asset Hub endpoint (production)
export const ASSET_HUB_ENDPOINT = 'wss://westend-asset-hub-rpc.polkadot.io';
// Known Asset IDs
export const ASSET_HUB_USDT_ID = 1984; // USDT on Asset Hub
export const WUSDT_ASSET_ID = 1000; // wUSDT on PezkuwiChain (was 2, now 1000)
export const ASSET_HUB_PARACHAIN_ID = 1000;
/**
* Bridge status information
*/
export interface BridgeStatus {
isConfigured: boolean;
assetHubLocation: string | null;
usdtMapping: number | null;
assetHubConnected: boolean;
wusdtExists: boolean;
}
/**
* Asset Hub USDT metadata
*/
export interface AssetHubUsdtInfo {
id: number;
name: string;
symbol: string;
decimals: number;
supply: string;
}
/**
* Connect to Asset Hub
*/
export async function connectToAssetHub(): Promise<ApiPromise> {
if (IS_MOCK_MODE) {
console.log('[MOCK XCM] Simulating Asset Hub connection for alfa testnet');
// Return null to signal mock mode - calling code will handle gracefully
return null as any;
}
try {
const provider = new WsProvider(ASSET_HUB_ENDPOINT);
const api = await ApiPromise.create({ provider });
await api.isReady;
return api;
} catch (error) {
console.error('Failed to connect to Asset Hub:', error);
throw new Error(`Asset Hub connection failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Fetch Asset Hub USDT metadata
*/
export async function fetchAssetHubUsdtInfo(
assetHubApi?: ApiPromise
): Promise<AssetHubUsdtInfo> {
if (IS_MOCK_MODE) {
console.log('[MOCK XCM] Returning simulated Asset Hub USDT info');
return {
id: ASSET_HUB_USDT_ID,
name: 'Tether USD',
symbol: 'USDT',
decimals: 6,
supply: '1000000000000000', // 1 billion USDT (simulated)
};
}
let api = assetHubApi;
let shouldDisconnect = false;
try {
// Connect if not provided
if (!api) {
api = await connectToAssetHub();
shouldDisconnect = true;
}
// Fetch USDT metadata from Asset Hub
const metadata = await api.query.assets.metadata(ASSET_HUB_USDT_ID);
const metadataJson = metadata.toJSON() as any;
// Fetch total supply
const asset = await api.query.assets.asset(ASSET_HUB_USDT_ID);
const assetJson = asset.toJSON() as any;
return {
id: ASSET_HUB_USDT_ID,
name: metadataJson?.name || 'Unknown',
symbol: metadataJson?.symbol || 'USDT',
decimals: metadataJson?.decimals || 6,
supply: assetJson?.supply?.toString() || '0',
};
} catch (error) {
console.error('Failed to fetch Asset Hub USDT info:', error);
throw new Error(`Failed to fetch USDT info: ${error instanceof Error ? error.message : 'Unknown error'}`);
} finally {
if (shouldDisconnect && api) {
await api.disconnect();
}
}
}
/**
* Check current XCM bridge configuration status
*/
export async function checkBridgeStatus(
api: ApiPromise
): Promise<BridgeStatus> {
try {
// Check if wUSDT asset exists
const wusdtAsset = await api.query.assets.asset(WUSDT_ASSET_ID);
const wusdtExists = wusdtAsset.isSome;
// Mock mode: Simulate successful bridge setup
if (IS_MOCK_MODE) {
const isConfigured = getMockXcmConfigured();
console.log('[MOCK XCM] Returning simulated bridge status for alfa testnet (configured:', isConfigured, ')');
return {
isConfigured,
assetHubLocation: isConfigured ? `ParaId(${ASSET_HUB_PARACHAIN_ID})` : null,
usdtMapping: isConfigured ? WUSDT_ASSET_ID : null,
assetHubConnected: true, // Simulated connection success
wusdtExists,
};
}
// Try to connect to Asset Hub
let assetHubConnected = false;
try {
const assetHubApi = await connectToAssetHub();
assetHubConnected = assetHubApi.isConnected;
await assetHubApi.disconnect();
} catch {
assetHubConnected = false;
}
// TODO: Check XCM configuration
// This requires checking the runtime configuration
// For now, we'll return a basic status
const isConfigured = false; // Will be updated when XCM pallet is available
return {
isConfigured,
assetHubLocation: isConfigured ? `ParaId(${ASSET_HUB_PARACHAIN_ID})` : null,
usdtMapping: isConfigured ? WUSDT_ASSET_ID : null,
assetHubConnected,
wusdtExists,
};
} catch (error) {
console.error('Failed to check bridge status:', error);
return {
isConfigured: false,
assetHubLocation: null,
usdtMapping: null,
assetHubConnected: false,
wusdtExists: false,
};
}
}
/**
* Configure XCM bridge (requires sudo access)
*
* This sets up the ForeignAssetTransactor to map Asset Hub USDT → wUSDT
*/
export async function configureXcmBridge(
api: ApiPromise,
signer: Signer,
account: string,
onStatusUpdate?: (status: string) => void
): Promise<string> {
if (!api.tx.sudo) {
throw new Error('Sudo pallet not available');
}
// Mock mode: Simulate successful configuration
if (IS_MOCK_MODE) {
console.log('[MOCK XCM] Simulating XCM bridge configuration for alfa testnet');
onStatusUpdate?.('Preparing XCM configuration...');
await new Promise(resolve => setTimeout(resolve, 500));
onStatusUpdate?.('Simulating sudo transaction...');
await new Promise(resolve => setTimeout(resolve, 1000));
onStatusUpdate?.('Mock XCM bridge configured successfully!');
// Store mock configuration state
setMockXcmConfigured(true);
// Return mock transaction hash
return '0x' + '0'.repeat(64);
}
try {
onStatusUpdate?.('Preparing XCM configuration...');
// Create Asset Hub location
const assetHubLocation = {
parents: 1,
interior: {
X2: [
{ Parachain: ASSET_HUB_PARACHAIN_ID },
{ GeneralIndex: ASSET_HUB_USDT_ID }
]
}
};
// Note: This is a placeholder for the actual XCM configuration
// The actual implementation depends on the runtime's XCM configuration pallet
// For now, we'll document the expected transaction structure
console.log('XCM Configuration (Placeholder):', {
assetHubLocation,
wusdtAssetId: WUSDT_ASSET_ID,
note: 'Actual implementation requires XCM config pallet in runtime'
});
onStatusUpdate?.('Waiting for user signature...');
// TODO: Implement actual XCM configuration when pallet is available
// const configTx = api.tx.sudo.sudo(
// api.tx.xcmConfig.configureForeignAsset(assetHubLocation, WUSDT_ASSET_ID)
// );
// For now, return a placeholder
return 'XCM configuration transaction placeholder - requires runtime XCM config pallet';
} catch (error) {
console.error('Failed to configure XCM bridge:', error);
throw new Error(`XCM configuration failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Create wUSDT/HEZ liquidity pool
*/
export async function createWUsdtHezPool(
api: ApiPromise,
signer: Signer,
account: string,
wusdtAmount: string,
hezAmount: string,
onStatusUpdate?: (status: string) => void
): Promise<string> {
try {
onStatusUpdate?.('Creating wUSDT/HEZ pool...');
// Create pool transaction
const poolTx = api.tx.assetConversion.createPool(
{ Assets: WUSDT_ASSET_ID }, // wUSDT
'Native' // Native HEZ
);
onStatusUpdate?.('Adding initial liquidity...');
// Add liquidity transaction
const liquidityTx = api.tx.assetConversion.addLiquidity(
{ Assets: WUSDT_ASSET_ID },
'Native',
wusdtAmount,
hezAmount,
'0', // min_mint_amount
account
);
onStatusUpdate?.('Batching transactions...');
// Batch both transactions
const batchTx = api.tx.utility.batchAll([poolTx, liquidityTx]);
onStatusUpdate?.('Waiting for signature...');
// Sign and send
return new Promise((resolve, reject) => {
batchTx.signAndSend(
account,
{ signer },
({ status, dispatchError, events }) => {
if (status.isInBlock) {
if (dispatchError) {
if (dispatchError.isModule) {
const decoded = api.registry.findMetaError(dispatchError.asModule);
reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
} else {
reject(new Error(dispatchError.toString()));
}
} else {
onStatusUpdate?.('Pool created successfully!');
resolve(status.asInBlock.toHex());
}
}
}
);
});
} catch (error) {
console.error('Failed to create wUSDT/HEZ pool:', error);
throw new Error(`Pool creation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Verify wUSDT asset exists on chain
*/
export async function verifyWUsdtAsset(api: ApiPromise): Promise<boolean> {
try {
const asset = await api.query.assets.asset(WUSDT_ASSET_ID);
return asset.isSome;
} catch (error) {
console.error('Failed to verify wUSDT asset:', error);
return false;
}
}
/**
* Get wUSDT asset details
*/
export async function getWUsdtAssetDetails(api: ApiPromise) {
try {
const [asset, metadata] = await Promise.all([
api.query.assets.asset(WUSDT_ASSET_ID),
api.query.assets.metadata(WUSDT_ASSET_ID),
]);
if (!asset.isSome) {
return null;
}
const assetData = (asset.unwrap() as any).toJSON() as any;
const metadataData = metadata.toJSON() as any;
return {
supply: assetData.supply?.toString() || '0',
owner: assetData.owner,
issuer: assetData.issuer,
admin: assetData.admin,
freezer: assetData.freezer,
minBalance: assetData.minBalance?.toString() || '0',
name: metadataData.name || 'wUSDT',
symbol: metadataData.symbol || 'wUSDT',
decimals: metadataData.decimals || 6,
};
} catch (error) {
console.error('Failed to get wUSDT asset details:', error);
return null;
}
}
/**
* Format XCM location for display
*/
export function formatXcmLocation(location: any): string {
if (typeof location === 'string') return location;
try {
if (location.parents !== undefined) {
const junctions = location.interior?.X2 || location.interior?.X1 || [];
return `RelayChain → ${junctions.map((j: any) => {
if (j.Parachain) return `Para(${j.Parachain})`;
if (j.GeneralIndex) return `Asset(${j.GeneralIndex})`;
return JSON.stringify(j);
}).join(' → ')}`;
}
return JSON.stringify(location);
} catch {
return 'Invalid location';
}
}
-724
View File
@@ -1,724 +0,0 @@
/**
* XCM Configuration Wizard Backend Functions
*
* Handles parachain registration, HRMP channels, foreign asset registration,
* and XCM transfer testing for PezkuwiChain.
*/
import type { ApiPromise } from '@pezkuwi/api';
import type { InjectedAccountWithMeta } from '@pezkuwi/extension-inject/types';
// ========================================
// TYPES
// ========================================
export type RelayChain = 'westend' | 'rococo' | 'polkadot';
export interface ChainArtifacts {
genesisPath: string;
genesisSize: number;
wasmPath: string;
wasmSize: number;
}
export interface HRMPChannel {
sender: number;
receiver: number;
channelId: string;
}
export interface AssetMetadata {
name: string;
symbol: string;
decimals: number;
minBalance: string;
}
export interface ForeignAsset {
symbol: string;
location: {
parents: number;
interior: any; // XCM Location interior
};
metadata: AssetMetadata;
}
export interface RegisteredAsset {
assetId: number;
symbol: string;
}
export interface XCMTestResult {
txHash: string;
success: boolean;
balance: string;
error?: string;
}
// ========================================
// STEP 1: RESERVE PARAID
// ========================================
/**
* Reserve a ParaId on the relay chain
*
* @param api - Polkadot.js API instance (connected to relay chain)
* @param relayChain - Target relay chain (westend/rococo/polkadot)
* @param account - Account to sign the transaction
* @returns Reserved ParaId number
*/
export async function reserveParaId(
api: ApiPromise,
relayChain: RelayChain,
account: InjectedAccountWithMeta
): Promise<number> {
return new Promise(async (resolve, reject) => {
try {
const injector = await (window as any).injectedWeb3[account.meta.source]?.enable?.('PezkuwiChain');
if (!injector) {
throw new Error('Failed to get injector from wallet extension');
}
const signer = injector.signer;
// Call registrar.reserve() on relay chain
const tx = api.tx.registrar.reserve();
let unsub: () => void;
await tx.signAndSend(account.address, { signer }, ({ status, events, dispatchError }) => {
if (dispatchError) {
if (dispatchError.isModule) {
const decoded = api.registry.findMetaError(dispatchError.asModule);
reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
} else {
reject(new Error(dispatchError.toString()));
}
if (unsub) unsub();
return;
}
if (status.isInBlock) {
// Extract ParaId from events
const reservedEvent = events.find(({ event }) =>
api.events.registrar.Reserved.is(event)
);
if (reservedEvent) {
const paraId = reservedEvent.event.data[0].toNumber();
resolve(paraId);
if (unsub) unsub();
} else {
reject(new Error('ParaId reservation failed: No Reserved event found'));
if (unsub) unsub();
}
}
}).then(unsubscribe => { unsub = unsubscribe; });
} catch (error) {
reject(error);
}
});
}
// ========================================
// STEP 2: GENERATE CHAIN ARTIFACTS
// ========================================
/**
* Generate genesis state and runtime WASM for parachain
*
* Note: This is a simplified version. In production, you'd call
* your blockchain node CLI to generate these artifacts.
*
* @param chainName - Name of the parachain
* @returns Paths to generated artifacts
*/
export async function generateChainArtifacts(
chainName: string
): Promise<ChainArtifacts> {
// In a real implementation, this would:
// 1. Call: ./target/release/pezkuwi export-genesis-state --chain=<chain-spec> > genesis-head.hex
// 2. Call: ./target/release/pezkuwi export-genesis-wasm --chain=<chain-spec> > runtime.wasm
// 3. Return the file paths and sizes
// For now, we'll return placeholder paths
// The actual implementation should use Node.js child_process or a backend API
return {
genesisPath: `/tmp/pezkuwi-${chainName}-genesis.hex`,
genesisSize: 0, // Would be actual file size
wasmPath: `/tmp/pezkuwi-${chainName}-runtime.wasm`,
wasmSize: 0, // Would be actual file size
};
}
// ========================================
// STEP 3: REGISTER PARACHAIN
// ========================================
/**
* Register parachain on relay chain with genesis and WASM
*
* @param api - Polkadot.js API instance (relay chain)
* @param paraId - Reserved ParaId
* @param genesisFile - Genesis state file
* @param wasmFile - Runtime WASM file
* @param account - Account to sign transaction
* @returns Transaction hash
*/
export async function registerParachain(
api: ApiPromise,
paraId: number,
genesisFile: File,
wasmFile: File,
account: InjectedAccountWithMeta
): Promise<string> {
return new Promise(async (resolve, reject) => {
try {
const injector = await (window as any).injectedWeb3[account.meta.source]?.enable?.('PezkuwiChain');
if (!injector) {
throw new Error('Failed to get injector from wallet extension');
}
const signer = injector.signer;
// Read files as hex strings
const genesisHex = await readFileAsHex(genesisFile);
const wasmHex = await readFileAsHex(wasmFile);
// Call registrar.register() with paraId, genesis, and wasm
const tx = api.tx.registrar.register(paraId, genesisHex, wasmHex);
let unsub: () => void;
await tx.signAndSend(account.address, { signer }, ({ status, dispatchError }) => {
if (dispatchError) {
if (dispatchError.isModule) {
const decoded = api.registry.findMetaError(dispatchError.asModule);
reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
} else {
reject(new Error(dispatchError.toString()));
}
if (unsub) unsub();
return;
}
if (status.isInBlock) {
resolve(status.asInBlock.toString());
if (unsub) unsub();
}
}).then(unsubscribe => { unsub = unsubscribe; });
} catch (error) {
reject(error);
}
});
}
/**
* Helper: Read File as hex string
*/
async function readFileAsHex(file: File): Promise<string> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
const arrayBuffer = reader.result as ArrayBuffer;
const uint8Array = new Uint8Array(arrayBuffer);
const hex = '0x' + Array.from(uint8Array)
.map(b => b.toString(16).padStart(2, '0'))
.join('');
resolve(hex);
};
reader.onerror = () => reject(new Error('Failed to read file'));
reader.readAsArrayBuffer(file);
});
}
// ========================================
// STEP 4: OPEN HRMP CHANNELS
// ========================================
/**
* Open bidirectional HRMP channels with target parachains
*
* @param api - Polkadot.js API instance (relay chain)
* @param paraId - Our ParaId
* @param targetParas - List of target ParaIds (e.g., [1000] for Asset Hub)
* @param account - Account to sign transactions
* @returns Array of opened channels
*/
export async function openHRMPChannels(
api: ApiPromise,
paraId: number,
targetParas: number[],
account: InjectedAccountWithMeta
): Promise<HRMPChannel[]> {
const channels: HRMPChannel[] = [];
for (const targetParaId of targetParas) {
// Open channel: paraId → targetParaId
const outgoingChannel = await openHRMPChannel(api, paraId, targetParaId, account);
channels.push(outgoingChannel);
// Open channel: targetParaId → paraId (requires governance or target's approval)
// Note: In practice, this requires the target parachain to initiate
// For Asset Hub and system chains, this is usually done via governance
}
return channels;
}
/**
* Open a single HRMP channel
*/
async function openHRMPChannel(
api: ApiPromise,
sender: number,
receiver: number,
account: InjectedAccountWithMeta
): Promise<HRMPChannel> {
return new Promise(async (resolve, reject) => {
try {
const injector = await (window as any).injectedWeb3[account.meta.source]?.enable?.('PezkuwiChain');
if (!injector) {
throw new Error('Failed to get injector from wallet extension');
}
const signer = injector.signer;
// Call hrmp.hrmpInitOpenChannel(recipient, proposedMaxCapacity, proposedMaxMessageSize)
const maxCapacity = 1000;
const maxMessageSize = 102400; // 100 KB
const tx = api.tx.hrmp.hrmpInitOpenChannel(receiver, maxCapacity, maxMessageSize);
let unsub: () => void;
await tx.signAndSend(account.address, { signer }, ({ status, events, dispatchError }) => {
if (dispatchError) {
if (dispatchError.isModule) {
const decoded = api.registry.findMetaError(dispatchError.asModule);
reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
} else {
reject(new Error(dispatchError.toString()));
}
if (unsub) unsub();
return;
}
if (status.isInBlock) {
const channelId = status.asInBlock.toString();
resolve({ sender, receiver, channelId });
if (unsub) unsub();
}
}).then(unsubscribe => { unsub = unsubscribe; });
} catch (error) {
reject(error);
}
});
}
// ========================================
// STEP 5: REGISTER FOREIGN ASSETS
// ========================================
/**
* Register foreign assets from other chains (via XCM)
*
* @param api - Polkadot.js API instance (our parachain)
* @param assets - List of foreign assets to register
* @param account - Account to sign transactions
* @returns List of registered assets with Asset IDs
*/
export async function registerForeignAssets(
api: ApiPromise,
assets: ForeignAsset[],
account: InjectedAccountWithMeta
): Promise<RegisteredAsset[]> {
const registered: RegisteredAsset[] = [];
for (const asset of assets) {
const registeredAsset = await registerSingleAsset(api, asset, account);
registered.push(registeredAsset);
}
return registered;
}
/**
* Register a single foreign asset
*/
async function registerSingleAsset(
api: ApiPromise,
asset: ForeignAsset,
account: InjectedAccountWithMeta
): Promise<RegisteredAsset> {
return new Promise(async (resolve, reject) => {
try {
const injector = await (window as any).injectedWeb3[account.meta.source]?.enable?.('PezkuwiChain');
if (!injector) {
throw new Error('Failed to get injector from wallet extension');
}
const signer = injector.signer;
// Get next available asset ID
const nextAssetId = await getNextAssetId(api);
// Create asset with metadata
// Note: Adjust based on your pallet configuration
const createTx = api.tx.assets.create(
nextAssetId,
account.address, // Admin
asset.metadata.minBalance
);
const setMetadataTx = api.tx.assets.setMetadata(
nextAssetId,
asset.metadata.name,
asset.metadata.symbol,
asset.metadata.decimals
);
// Batch both transactions
const tx = api.tx.utility.batchAll([createTx, setMetadataTx]);
let unsub: () => void;
await tx.signAndSend(account.address, { signer }, ({ status, dispatchError }) => {
if (dispatchError) {
if (dispatchError.isModule) {
const decoded = api.registry.findMetaError(dispatchError.asModule);
reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
} else {
reject(new Error(dispatchError.toString()));
}
if (unsub) unsub();
return;
}
if (status.isInBlock) {
resolve({
assetId: nextAssetId,
symbol: asset.metadata.symbol,
});
if (unsub) unsub();
}
}).then(unsubscribe => { unsub = unsubscribe; });
} catch (error) {
reject(error);
}
});
}
/**
* Get next available Asset ID
*/
async function getNextAssetId(api: ApiPromise): Promise<number> {
// Query existing assets and find the next ID
// This is a simplified version - adjust based on your implementation
const assets = await api.query.assets.asset.entries();
if (assets.length === 0) {
return 1000; // Start from 1000 for foreign assets
}
const maxId = Math.max(...assets.map(([key]) => {
const assetId = key.args[0].toNumber();
return assetId;
}));
return maxId + 1;
}
// ========================================
// STEP 6: TEST XCM TRANSFER
// ========================================
/**
* Test XCM transfer from Asset Hub USDT to our wUSDT
*
* @param api - Polkadot.js API instance (our parachain)
* @param amount - Amount to transfer (in smallest unit)
* @param account - Account to receive the transfer
* @returns Test result with transaction hash and balance
*/
export async function testXCMTransfer(
api: ApiPromise,
amount: string,
account: InjectedAccountWithMeta
): Promise<XCMTestResult> {
try {
// This is a placeholder for XCM testing
// In reality, you'd need to:
// 1. Connect to Asset Hub
// 2. Send limitedReserveTransferAssets() to our parachain
// 3. Monitor for AssetReceived event on our side
// For now, return a mock success result
return {
txHash: '0x0000000000000000000000000000000000000000000000000000000000000000',
success: false,
balance: '0',
error: 'XCM testing requires connection to relay chain and Asset Hub',
};
} catch (error) {
return {
txHash: '',
success: false,
balance: '0',
error: error instanceof Error ? error.message : 'Unknown error',
};
}
}
// ========================================
// XCM TELEPORT: RELAY CHAIN → ASSET HUB
// ========================================
/**
* Teleport HEZ from Relay Chain to Asset Hub
* This is needed to pay fees on Asset Hub for PEZ transfers
*
* @param relayApi - Polkadot.js API instance (connected to relay chain)
* @param amount - Amount in smallest unit (e.g., 100000000000 for 0.1 HEZ with 12 decimals)
* @param account - Account to sign and receive on Asset Hub
* @param assetHubParaId - Asset Hub parachain ID (default: 1000)
* @returns Transaction hash
*/
export async function teleportToAssetHub(
relayApi: ApiPromise,
amount: string | bigint,
account: InjectedAccountWithMeta,
assetHubParaId: number = 1000
): Promise<string> {
return new Promise(async (resolve, reject) => {
try {
const injector = await (window as any).injectedWeb3[account.meta.source]?.enable?.('PezkuwiChain');
if (!injector) {
throw new Error('Failed to get injector from wallet extension');
}
const signer = injector.signer;
// Destination: Asset Hub parachain
const dest = {
V3: {
parents: 0,
interior: {
X1: { Parachain: assetHubParaId }
}
}
};
// Beneficiary: Same account on Asset Hub
const beneficiary = {
V3: {
parents: 0,
interior: {
X1: {
AccountId32: {
network: null,
id: relayApi.createType('AccountId32', account.address).toHex()
}
}
}
}
};
// Assets: Native token (HEZ)
const assets = {
V3: [{
id: {
Concrete: {
parents: 0,
interior: 'Here'
}
},
fun: {
Fungible: amount.toString()
}
}]
};
// Fee asset item (index 0 = first asset)
const feeAssetItem = 0;
// Weight limit: Unlimited
const weightLimit = 'Unlimited';
// Create teleport transaction
const tx = relayApi.tx.xcmPallet.limitedTeleportAssets(
dest,
beneficiary,
assets,
feeAssetItem,
weightLimit
);
let unsub: () => void;
await tx.signAndSend(account.address, { signer }, ({ status, events, dispatchError }) => {
if (dispatchError) {
if (dispatchError.isModule) {
const decoded = relayApi.registry.findMetaError(dispatchError.asModule);
reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
} else {
reject(new Error(dispatchError.toString()));
}
if (unsub) unsub();
return;
}
if (status.isInBlock) {
console.log(`✅ XCM Teleport included in block: ${status.asInBlock}`);
// Check for XCM events
const xcmSent = events.find(({ event }) =>
event.section === 'xcmPallet' && event.method === 'Sent'
);
if (xcmSent) {
console.log('✅ XCM message sent successfully');
}
resolve(status.asInBlock.toString());
if (unsub) unsub();
}
}).then(unsubscribe => { unsub = unsubscribe; });
} catch (error) {
reject(error);
}
});
}
/**
* Teleport HEZ from Asset Hub back to Relay Chain
*
* @param assetHubApi - Polkadot.js API instance (connected to Asset Hub)
* @param amount - Amount in smallest unit
* @param account - Account to sign and receive on relay chain
* @returns Transaction hash
*/
export async function teleportToRelayChain(
assetHubApi: ApiPromise,
amount: string | bigint,
account: InjectedAccountWithMeta
): Promise<string> {
return new Promise(async (resolve, reject) => {
try {
const injector = await (window as any).injectedWeb3[account.meta.source]?.enable?.('PezkuwiChain');
if (!injector) {
throw new Error('Failed to get injector from wallet extension');
}
const signer = injector.signer;
// Destination: Relay chain (parent)
const dest = {
V3: {
parents: 1,
interior: 'Here'
}
};
// Beneficiary: Same account on relay chain
const beneficiary = {
V3: {
parents: 0,
interior: {
X1: {
AccountId32: {
network: null,
id: assetHubApi.createType('AccountId32', account.address).toHex()
}
}
}
}
};
// Assets: Native token
const assets = {
V3: [{
id: {
Concrete: {
parents: 1,
interior: 'Here'
}
},
fun: {
Fungible: amount.toString()
}
}]
};
const feeAssetItem = 0;
const weightLimit = 'Unlimited';
const tx = assetHubApi.tx.polkadotXcm.limitedTeleportAssets(
dest,
beneficiary,
assets,
feeAssetItem,
weightLimit
);
let unsub: () => void;
await tx.signAndSend(account.address, { signer }, ({ status, dispatchError }) => {
if (dispatchError) {
if (dispatchError.isModule) {
const decoded = assetHubApi.registry.findMetaError(dispatchError.asModule);
reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`));
} else {
reject(new Error(dispatchError.toString()));
}
if (unsub) unsub();
return;
}
if (status.isInBlock) {
resolve(status.asInBlock.toString());
if (unsub) unsub();
}
}).then(unsubscribe => { unsub = unsubscribe; });
} catch (error) {
reject(error);
}
});
}
// ========================================
// UTILITY FUNCTIONS
// ========================================
/**
* Get relay chain endpoint based on network selection
*/
export function getRelayChainEndpoint(relayChain: RelayChain): string {
const endpoints = {
westend: 'wss://westend-rpc.polkadot.io',
rococo: 'wss://rococo-rpc.polkadot.io',
polkadot: 'wss://rpc.polkadot.io',
};
return endpoints[relayChain];
}
/**
* Asset Hub ParaId by relay chain
*/
export function getAssetHubParaId(relayChain: RelayChain): number {
const paraIds = {
westend: 1000, // Westend Asset Hub
rococo: 1000, // Rococo Asset Hub
polkadot: 1000, // Polkadot Asset Hub (Statemint)
};
return paraIds[relayChain];
}
@@ -1,878 +0,0 @@
/**
* XCM Configuration Wizard - Multi-Step Parachain Setup
*
* Guides admin through complete XCM integration:
* 1. Reserve ParaId
* 2. Generate Chain Artifacts (genesis + WASM)
* 3. Register Parachain
* 4. Open HRMP Channels
* 5. Register Foreign Assets
* 6. Test XCM Transfer
*/
import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { usePezkuwi } from '@/contexts/PezkuwiContext';
import { useWallet } from '@/contexts/WalletContext';
import {
X,
CheckCircle,
Circle,
Loader2,
AlertCircle,
Download,
ChevronRight,
} from 'lucide-react';
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Alert, AlertDescription } from '@/components/ui/alert';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Progress } from '@/components/ui/progress';
import { Badge } from '@/components/ui/badge';
import { useToast } from '@/hooks/use-toast';
import {
reserveParaId,
generateChainArtifacts,
registerParachain,
openHRMPChannels,
registerForeignAssets,
testXCMTransfer,
getRelayChainEndpoint,
getAssetHubParaId,
type RelayChain,
type ChainArtifacts,
type HRMPChannel,
type RegisteredAsset,
type ForeignAsset,
} from '@pezkuwi/lib/xcm-wizard';
import { ApiPromise, WsProvider } from '@pezkuwi/api';
interface XCMConfigurationWizardProps {
isOpen: boolean;
onClose: () => void;
onSuccess?: () => void;
}
interface StepStatus {
completed: boolean;
data?: unknown;
error?: string;
}
export const XCMConfigurationWizard: React.FC<XCMConfigurationWizardProps> = ({
isOpen,
onClose,
onSuccess,
}) => {
const { t } = useTranslation();
// Use Asset Hub API for asset registration (Step 5) and XCM testing (Step 6)
// Steps 1-4 connect to relay chain directly via xcm-wizard functions
const { assetHubApi, isAssetHubReady } = usePezkuwi();
const { account, signer } = useWallet();
const { toast } = useToast();
// Wizard state
const [currentStep, setCurrentStep] = useState<number>(1);
const [steps, setSteps] = useState<Record<number, StepStatus>>({
1: { completed: false },
2: { completed: false },
3: { completed: false },
4: { completed: false },
5: { completed: false },
6: { completed: false },
});
// Step 1: Reserve ParaId
const [relayChain, setRelayChain] = useState<RelayChain>('westend');
const [reservedParaId, setReservedParaId] = useState<number | null>(null);
const [reserving, setReserving] = useState(false);
// Step 2: Generate Artifacts
const [artifacts, setArtifacts] = useState<ChainArtifacts | null>(null);
const [generating, setGenerating] = useState(false);
// Step 3: Register Parachain
const [genesisFile, setGenesisFile] = useState<File | null>(null);
const [wasmFile, setWasmFile] = useState<File | null>(null);
const [registering, setRegistering] = useState(false);
const [registrationTxHash, setRegistrationTxHash] = useState<string>('');
// Step 4: HRMP Channels
const [openingChannels, setOpeningChannels] = useState(false);
const [openedChannels, setOpenedChannels] = useState<HRMPChannel[]>([]);
// Step 5: Foreign Assets
const [registeringAssets, setRegisteringAssets] = useState(false);
const [registeredAssets, setRegisteredAssets] = useState<RegisteredAsset[]>([]);
// Step 6: XCM Test
const [testing, setTesting] = useState(false);
const [testResult, setTestResult] = useState<{ success: boolean; balance: string } | null>(null);
const totalSteps = 6;
const progress = (Object.values(steps).filter(s => s.completed).length / totalSteps) * 100;
// Reset state when modal opens/closes
useEffect(() => {
if (!isOpen) {
setCurrentStep(1);
setSteps({
1: { completed: false },
2: { completed: false },
3: { completed: false },
4: { completed: false },
5: { completed: false },
6: { completed: false },
});
setReservedParaId(null);
setArtifacts(null);
setOpenedChannels([]);
setRegisteredAssets([]);
setTestResult(null);
}
}, [isOpen]);
// ========================================
// STEP 1: RESERVE PARAID
// ========================================
const handleReserveParaId = async () => {
if (!account || !signer) {
toast({
title: t('xcmWizard.walletNotConnected'),
description: t('xcmWizard.connectFirst'),
variant: 'destructive',
});
return;
}
setReserving(true);
try {
// Connect to relay chain
const endpoint = getRelayChainEndpoint(relayChain);
const provider = new WsProvider(endpoint);
const relayApi = await ApiPromise.create({ provider });
// Reserve ParaId
const paraId = await reserveParaId(relayApi, relayChain, account);
setReservedParaId(paraId);
// Mark step as completed
setSteps(prev => ({
...prev,
1: { completed: true, data: { paraId, relayChain } },
}));
toast({
title: t('xcmWizard.reserveSuccess', { paraId, chain: relayChain }),
});
// Auto-advance to next step
setCurrentStep(2);
await relayApi.disconnect();
} catch (error) {
console.error('Failed to reserve ParaId:', error);
setSteps(prev => ({
...prev,
1: { completed: false, error: error instanceof Error ? error.message : 'Unknown error' },
}));
toast({
title: t('xcmWizard.reserveFailed'),
description: error instanceof Error ? error.message : t('xcmWizard.reserveFailed'),
variant: 'destructive',
});
} finally {
setReserving(false);
}
};
// ========================================
// STEP 2: GENERATE CHAIN ARTIFACTS
// ========================================
const handleGenerateArtifacts = async () => {
if (!reservedParaId) return;
setGenerating(true);
try {
const chainName = `pezkuwichain-${relayChain}`;
const artifactData = await generateChainArtifacts(chainName);
setArtifacts(artifactData);
setSteps(prev => ({
...prev,
2: { completed: true, data: artifactData },
}));
toast({
title: t('xcmWizard.artifactsReady'),
});
setCurrentStep(3);
} catch (error) {
console.error('Failed to generate artifacts:', error);
setSteps(prev => ({
...prev,
2: { completed: false, error: error instanceof Error ? error.message : 'Unknown error' },
}));
toast({
title: t('xcmWizard.artifactsFailed'),
variant: 'destructive',
});
} finally {
setGenerating(false);
}
};
// ========================================
// STEP 3: REGISTER PARACHAIN
// ========================================
const handleRegisterParachain = async () => {
if (!reservedParaId || !genesisFile || !wasmFile || !account || !signer) {
toast({
title: t('xcmWizard.missingFiles'),
variant: 'destructive',
});
return;
}
setRegistering(true);
try {
const endpoint = getRelayChainEndpoint(relayChain);
const provider = new WsProvider(endpoint);
const relayApi = await ApiPromise.create({ provider });
const txHash = await registerParachain(relayApi, reservedParaId, genesisFile, wasmFile, account);
setRegistrationTxHash(txHash);
setSteps(prev => ({
...prev,
3: { completed: true, data: { txHash, paraId: reservedParaId } },
}));
toast({
title: t('xcmWizard.registerSuccess'),
});
setCurrentStep(4);
await relayApi.disconnect();
} catch (error) {
console.error('Failed to register parachain:', error);
setSteps(prev => ({
...prev,
3: { completed: false, error: error instanceof Error ? error.message : 'Unknown error' },
}));
toast({
title: t('xcmWizard.registerFailed'),
description: error instanceof Error ? error.message : t('xcmWizard.registerFailed'),
variant: 'destructive',
});
} finally {
setRegistering(false);
}
};
// ========================================
// STEP 4: OPEN HRMP CHANNELS
// ========================================
const handleOpenHRMPChannels = async () => {
if (!reservedParaId || !account || !signer) return;
setOpeningChannels(true);
try {
const endpoint = getRelayChainEndpoint(relayChain);
const provider = new WsProvider(endpoint);
const relayApi = await ApiPromise.create({ provider });
// Get Asset Hub ParaId
const assetHubParaId = getAssetHubParaId(relayChain);
// Open channels with Asset Hub
const channels = await openHRMPChannels(relayApi, reservedParaId, [assetHubParaId], account);
setOpenedChannels(channels);
setSteps(prev => ({
...prev,
4: { completed: true, data: { channels } },
}));
toast({
title: t('xcmWizard.hrmpSuccess', { count: channels.length }),
});
setCurrentStep(5);
await relayApi.disconnect();
} catch (error) {
console.error('Failed to open HRMP channels:', error);
setSteps(prev => ({
...prev,
4: { completed: false, error: error instanceof Error ? error.message : 'Unknown error' },
}));
toast({
title: t('xcmWizard.hrmpFailed'),
description: error instanceof Error ? error.message : t('xcmWizard.hrmpFailed'),
variant: 'destructive',
});
} finally {
setOpeningChannels(false);
}
};
// ========================================
// STEP 5: REGISTER FOREIGN ASSETS (on Asset Hub)
// ========================================
const handleRegisterAssets = async () => {
if (!assetHubApi || !isAssetHubReady || !account || !signer) {
toast({
title: t('xcmWizard.notReady'),
variant: 'destructive',
});
return;
}
setRegisteringAssets(true);
try {
// Define foreign assets to register (USDT, DOT, etc.)
const foreignAssets: ForeignAsset[] = [
{
symbol: 'USDT',
location: {
parents: 1,
interior: {
X3: [{ Parachain: 1000 }, { PalletInstance: 50 }, { GeneralIndex: 1984 }],
},
},
metadata: {
name: 'Tether USD',
symbol: 'USDT',
decimals: 6,
minBalance: '1000',
},
},
{
symbol: 'DOT',
location: {
parents: 1,
interior: { Here: null },
},
metadata: {
name: 'Polkadot',
symbol: 'DOT',
decimals: 10,
minBalance: '10000000000',
},
},
];
const registered = await registerForeignAssets(assetHubApi, foreignAssets, account);
setRegisteredAssets(registered);
setSteps(prev => ({
...prev,
5: { completed: true, data: { assets: registered } },
}));
toast({
title: t('xcmWizard.assetsSuccess', { count: registered.length }),
});
setCurrentStep(6);
} catch (error) {
console.error('Failed to register assets:', error);
setSteps(prev => ({
...prev,
5: { completed: false, error: error instanceof Error ? error.message : 'Unknown error' },
}));
toast({
title: t('xcmWizard.assetsFailed'),
description: error instanceof Error ? error.message : t('xcmWizard.assetsFailed'),
variant: 'destructive',
});
} finally {
setRegisteringAssets(false);
}
};
// ========================================
// STEP 6: TEST XCM TRANSFER (on Asset Hub)
// ========================================
const handleTestXCMTransfer = async () => {
if (!assetHubApi || !isAssetHubReady || !account || !signer) {
toast({
title: t('xcmWizard.notReady'),
variant: 'destructive',
});
return;
}
setTesting(true);
try {
const result = await testXCMTransfer(assetHubApi, '1000000', account); // 1 USDT (6 decimals)
setTestResult(result);
setSteps(prev => ({
...prev,
6: { completed: result.success, data: result },
}));
if (result.success) {
toast({
title: t('xcmWizard.testSuccess', { balance: result.balance }),
});
} else {
toast({
title: t('xcmWizard.testFailed'),
description: result.error || t('xcmWizard.testFailed'),
variant: 'destructive',
});
}
} catch (error) {
console.error('Failed to test XCM transfer:', error);
setSteps(prev => ({
...prev,
6: { completed: false, error: error instanceof Error ? error.message : 'Unknown error' },
}));
toast({
title: t('xcmWizard.testFailed'),
description: error instanceof Error ? error.message : t('xcmWizard.testFailed'),
variant: 'destructive',
});
} finally {
setTesting(false);
}
};
// ========================================
// RENDER STEP CONTENT
// ========================================
const renderStepContent = () => {
switch (currentStep) {
case 1:
return (
<div className="space-y-4">
<div className="space-y-2">
<Label>{t('xcmWizard.relayChainLabel')}</Label>
<Select value={relayChain} onValueChange={(value: RelayChain) => setRelayChain(value)}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="westend">{t('xcmWizard.westend')}</SelectItem>
<SelectItem value="rococo">{t('xcmWizard.rococo')}</SelectItem>
<SelectItem value="polkadot">{t('xcmWizard.polkadot')}</SelectItem>
</SelectContent>
</Select>
</div>
{reservedParaId && (
<Alert>
<CheckCircle className="h-4 w-4" />
<AlertDescription>
ParaId <strong>{reservedParaId}</strong> reserved on {relayChain}
</AlertDescription>
</Alert>
)}
{steps[1].error && (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertDescription>{steps[1].error}</AlertDescription>
</Alert>
)}
<Button onClick={handleReserveParaId} disabled={reserving || steps[1].completed} className="w-full">
{reserving ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
{t('xcmWizard.reserving')}
</>
) : steps[1].completed ? (
<>
<CheckCircle className="mr-2 h-4 w-4" />
{t('xcmWizard.reserved')}
</>
) : (
t('xcmWizard.reserveBtn')
)}
</Button>
</div>
);
case 2:
return (
<div className="space-y-4">
{artifacts && (
<div className="space-y-2">
<Alert>
<CheckCircle className="h-4 w-4" />
<AlertDescription>
Artifacts generated. Download files for registration.
</AlertDescription>
</Alert>
<div className="grid grid-cols-2 gap-2">
<Button variant="outline" size="sm" asChild>
<a href={artifacts.genesisPath} download>
<Download className="mr-2 h-4 w-4" />
Genesis ({artifacts.genesisSize} bytes)
</a>
</Button>
<Button variant="outline" size="sm" asChild>
<a href={artifacts.wasmPath} download>
<Download className="mr-2 h-4 w-4" />
WASM ({artifacts.wasmSize} bytes)
</a>
</Button>
</div>
</div>
)}
{steps[2].error && (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertDescription>{steps[2].error}</AlertDescription>
</Alert>
)}
<Button onClick={handleGenerateArtifacts} disabled={generating || steps[2].completed} className="w-full">
{generating ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
{t('xcmWizard.generating')}
</>
) : steps[2].completed ? (
<>
<CheckCircle className="mr-2 h-4 w-4" />
{t('xcmWizard.generated')}
</>
) : (
t('xcmWizard.generateBtn')
)}
</Button>
</div>
);
case 3:
return (
<div className="space-y-4">
<div className="space-y-2">
<Label>{t('xcmWizard.genesisLabel')}</Label>
<Input
type="file"
accept=".hex,.txt"
onChange={(e) => setGenesisFile(e.target.files?.[0] || null)}
/>
</div>
<div className="space-y-2">
<Label>{t('xcmWizard.wasmLabel')}</Label>
<Input
type="file"
accept=".wasm"
onChange={(e) => setWasmFile(e.target.files?.[0] || null)}
/>
</div>
{registrationTxHash && (
<Alert>
<CheckCircle className="h-4 w-4" />
<AlertDescription>
Registered! TX: <code className="text-xs">{registrationTxHash.slice(0, 20)}...</code>
</AlertDescription>
</Alert>
)}
{steps[3].error && (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertDescription>{steps[3].error}</AlertDescription>
</Alert>
)}
<Button
onClick={handleRegisterParachain}
disabled={!genesisFile || !wasmFile || registering || steps[3].completed}
className="w-full"
>
{registering ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
{t('xcmWizard.registering')}
</>
) : steps[3].completed ? (
<>
<CheckCircle className="mr-2 h-4 w-4" />
{t('xcmWizard.registered')}
</>
) : (
t('xcmWizard.registerBtn')
)}
</Button>
</div>
);
case 4:
return (
<div className="space-y-4">
<p className="text-sm text-muted-foreground">
Opening HRMP channels with Asset Hub (ParaId {getAssetHubParaId(relayChain)})
</p>
{openedChannels.length > 0 && (
<Alert>
<CheckCircle className="h-4 w-4" />
<AlertDescription>
Opened {openedChannels.length} channel(s):
<ul className="mt-2 space-y-1 text-xs">
{openedChannels.map((ch, idx) => (
<li key={idx}>
{ch.sender} → {ch.receiver} (ID: {ch.channelId.slice(0, 10)}...)
</li>
))}
</ul>
</AlertDescription>
</Alert>
)}
{steps[4].error && (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertDescription>{steps[4].error}</AlertDescription>
</Alert>
)}
<Button onClick={handleOpenHRMPChannels} disabled={openingChannels || steps[4].completed} className="w-full">
{openingChannels ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
{t('xcmWizard.openingHrmp')}
</>
) : steps[4].completed ? (
<>
<CheckCircle className="mr-2 h-4 w-4" />
{t('xcmWizard.channelsOpened')}
</>
) : (
t('xcmWizard.hrmpBtn')
)}
</Button>
</div>
);
case 5:
return (
<div className="space-y-4">
<p className="text-sm text-muted-foreground">
{t('xcmWizard.assetsDesc')}
</p>
{registeredAssets.length > 0 && (
<Alert>
<CheckCircle className="h-4 w-4" />
<AlertDescription>
Registered {registeredAssets.length} asset(s):
<ul className="mt-2 space-y-1 text-xs">
{registeredAssets.map((asset, idx) => (
<li key={idx}>
{asset.symbol} (Asset ID: {asset.assetId})
</li>
))}
</ul>
</AlertDescription>
</Alert>
)}
{steps[5].error && (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertDescription>{steps[5].error}</AlertDescription>
</Alert>
)}
<Button onClick={handleRegisterAssets} disabled={registeringAssets || steps[5].completed} className="w-full">
{registeringAssets ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
{t('xcmWizard.registeringAssets')}
</>
) : steps[5].completed ? (
<>
<CheckCircle className="mr-2 h-4 w-4" />
{t('xcmWizard.assetsRegistered')}
</>
) : (
t('xcmWizard.assetsBtn')
)}
</Button>
</div>
);
case 6:
return (
<div className="space-y-4">
<p className="text-sm text-muted-foreground">
{t('xcmWizard.testDesc')}
</p>
{testResult && (
<Alert variant={testResult.success ? 'default' : 'destructive'}>
{testResult.success ? <CheckCircle className="h-4 w-4" /> : <AlertCircle className="h-4 w-4" />}
<AlertDescription>
{testResult.success
? t('xcmWizard.testSuccess', { balance: testResult.balance })
: testResult.error}
</AlertDescription>
</Alert>
)}
{steps[6].error && (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertDescription>{steps[6].error}</AlertDescription>
</Alert>
)}
<Button onClick={handleTestXCMTransfer} disabled={testing || steps[6].completed} className="w-full">
{testing ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
{t('xcmWizard.testing')}
</>
) : steps[6].completed ? (
<>
<CheckCircle className="mr-2 h-4 w-4" />
{t('xcmWizard.testPassed')}
</>
) : (
t('xcmWizard.testBtn')
)}
</Button>
</div>
);
default:
return null;
}
};
// Check if all steps are completed
const allStepsCompleted = Object.values(steps).every(s => s.completed);
// Handle Finish Configuration
const handleFinishConfiguration = () => {
toast({
title: t('xcmWizard.complete'),
description: t('xcmWizard.completeDesc'),
});
if (onSuccess) {
onSuccess();
}
onClose();
};
if (!isOpen) return null;
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm">
<Card className="w-full max-w-3xl max-h-[90vh] overflow-y-auto">
<CardHeader>
<div className="flex items-center justify-between">
<div>
<CardTitle>{t('xcmWizard.title')}</CardTitle>
<CardDescription>
{t('xcmWizard.subtitle')}
</CardDescription>
</div>
<Button variant="ghost" size="icon" onClick={onClose}>
<X className="h-4 w-4" />
</Button>
</div>
<div className="mt-4">
<Progress value={progress} className="h-2" />
<p className="mt-2 text-xs text-muted-foreground text-center">
{t('xcmWizard.progress', { completed: Object.values(steps).filter(s => s.completed).length, total: totalSteps })}
</p>
</div>
</CardHeader>
<CardContent className="space-y-6">
{/* Step Navigation */}
<div className="grid grid-cols-6 gap-2">
{[1, 2, 3, 4, 5, 6].map((step) => (
<button
key={step}
onClick={() => setCurrentStep(step)}
className={`flex flex-col items-center gap-1 p-2 rounded-lg transition-colors ${
currentStep === step
? 'bg-kurdish-green text-white'
: steps[step].completed
? 'bg-green-100 text-green-700'
: 'bg-gray-100 text-gray-500'
}`}
>
{steps[step].completed ? (
<CheckCircle className="h-5 w-5" />
) : currentStep === step ? (
<Circle className="h-5 w-5 fill-current" />
) : (
<Circle className="h-5 w-5" />
)}
<span className="text-xs font-medium">{step}</span>
</button>
))}
</div>
{/* Current Step Content */}
<div className="space-y-4">
<div className="flex items-center gap-2">
<Badge variant="outline">Step {currentStep}</Badge>
<h3 className="font-semibold">
{currentStep === 1 && t('xcmWizard.stepReserve')}
{currentStep === 2 && t('xcmWizard.stepArtifacts')}
{currentStep === 3 && t('xcmWizard.stepParachain')}
{currentStep === 4 && t('xcmWizard.stepHrmp')}
{currentStep === 5 && t('xcmWizard.stepAssets')}
{currentStep === 6 && t('xcmWizard.stepTest')}
</h3>
</div>
{renderStepContent()}
</div>
{/* Navigation Buttons */}
<div className="flex items-center justify-between pt-4 border-t">
<Button
variant="outline"
onClick={() => setCurrentStep(Math.max(1, currentStep - 1))}
disabled={currentStep === 1}
>
{t('xcmWizard.previous')}
</Button>
{allStepsCompleted ? (
<Button onClick={handleFinishConfiguration} className="bg-kurdish-green hover:bg-kurdish-green-dark">
<CheckCircle className="mr-2 h-4 w-4" />
{t('xcmWizard.finish')}
</Button>
) : (
<Button
onClick={() => setCurrentStep(Math.min(totalSteps, currentStep + 1))}
disabled={currentStep === totalSteps || !steps[currentStep].completed}
>
{t('xcmWizard.next')}
<ChevronRight className="ml-2 h-4 w-4" />
</Button>
)}
</div>
</CardContent>
</Card>
</div>
);
};
-22
View File
@@ -11,7 +11,6 @@ import { InitializeHezPoolModal } from './InitializeHezPoolModal';
import { InitializeUsdtModal } from './InitializeUsdtModal';
import { MintAssetModal } from './MintAssetModal';
import { MINTABLE_ASSETS, type AssetConfig } from './mintableAssets';
import { XCMConfigurationWizard } from '@/components/admin/XCMConfigurationWizard';
import { ArrowRightLeft, Droplet, Settings } from 'lucide-react';
import { isFounderWallet } from '@pezkuwi/utils/auth';
@@ -26,7 +25,6 @@ export const DEXDashboard: React.FC = () => {
const [showCreatePoolModal, setShowCreatePoolModal] = useState(false);
const [showInitializeHezPoolModal, setShowInitializeHezPoolModal] = useState(false);
const [showInitializeUsdtModal, setShowInitializeUsdtModal] = useState(false);
const [showXcmBridgeModal, setShowXcmBridgeModal] = useState(false);
// Generic mint modal state
const [mintModalAsset, setMintModalAsset] = useState<AssetConfig | null>(null);
@@ -41,7 +39,6 @@ export const DEXDashboard: React.FC = () => {
setShowCreatePoolModal(false);
setShowInitializeHezPoolModal(false);
setShowInitializeUsdtModal(false);
setShowXcmBridgeModal(false);
setMintModalAsset(null);
};
@@ -171,19 +168,6 @@ export const DEXDashboard: React.FC = () => {
</div>
</div>
<div className="p-6 bg-gray-900 border border-purple-900/30 rounded-lg">
<h3 className="text-xl font-bold text-white mb-2">{t('dex.admin.xcmWizard')}</h3>
<p className="text-gray-400 mb-6">
{t('dex.admin.xcmWizardDesc')}
</p>
<button
onClick={() => setShowXcmBridgeModal(true)}
className="w-full px-6 py-3 bg-purple-600 hover:bg-purple-700 text-white rounded-lg transition-colors font-medium"
>
{t('dex.admin.openXcmWizard')}
</button>
</div>
<div className="p-6 bg-gray-900 border border-gray-800 rounded-lg">
<h3 className="text-xl font-bold text-white mb-2">{t('dex.admin.poolManagement')}</h3>
<p className="text-gray-400 mb-6">
@@ -229,12 +213,6 @@ export const DEXDashboard: React.FC = () => {
onSuccess={handleSuccess}
/>
<XCMConfigurationWizard
isOpen={showXcmBridgeModal}
onClose={handleModalClose}
onSuccess={handleSuccess}
/>
{/* Generic Mint Asset Modal */}
{mintModalAsset && (
<MintAssetModal
@@ -1,444 +0,0 @@
// Force reload for mock XCM update
import React, { useState, useEffect, useCallback } from 'react';
import { usePezkuwi } from '@/contexts/PezkuwiContext';
import { useWallet } from '@/contexts/WalletContext';
import { X, AlertCircle, Loader2, CheckCircle, Info, ExternalLink, Zap } 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 { Alert, AlertDescription } from '@/components/ui/alert';
import { useToast } from '@/hooks/use-toast';
import { useTranslation } from 'react-i18next';
import { parseTokenInput } from '@pezkuwi/utils/dex';
import {
checkBridgeStatus,
fetchAssetHubUsdtInfo,
configureXcmBridge,
createWUsdtHezPool,
ASSET_HUB_USDT_ID,
WUSDT_ASSET_ID,
ASSET_HUB_ENDPOINT,
type BridgeStatus,
type AssetHubUsdtInfo,
} from '@pezkuwi/lib/xcm-bridge';
interface XCMBridgeSetupModalProps {
isOpen: boolean;
onClose: () => void;
onSuccess?: () => void;
}
type SetupStep = 'idle' | 'checking' | 'fetching' | 'configuring' | 'pool-creation' | 'success' | 'error';
export const XCMBridgeSetupModal: React.FC<XCMBridgeSetupModalProps> = ({
isOpen,
onClose,
onSuccess,
}) => {
// Use Asset Hub API for DEX operations
const { assetHubApi, isAssetHubReady } = usePezkuwi();
const { account, signer } = useWallet();
const { toast } = useToast();
const { t } = useTranslation();
// State
const [step, setStep] = useState<SetupStep>('idle');
const [bridgeStatus, setBridgeStatus] = useState<BridgeStatus | null>(null);
const [assetHubInfo, setAssetHubInfo] = useState<AssetHubUsdtInfo | null>(null);
const [statusMessage, setStatusMessage] = useState<string>('');
const [errorMessage, setErrorMessage] = useState<string>('');
const [showPoolCreation, setShowPoolCreation] = useState(false);
const [wusdtAmount, setWusdtAmount] = useState('1000');
const [hezAmount, setHezAmount] = useState('10');
/**
* Perform initial status check
*/
const performInitialCheck = useCallback(async () => {
if (!assetHubApi || !isAssetHubReady) return;
setStep('checking');
setStatusMessage(t('xcmBridge.checkingStatus'));
setErrorMessage('');
try {
// Check current bridge status
const status = await checkBridgeStatus(assetHubApi);
setBridgeStatus(status);
// Fetch Asset Hub USDT info
setStatusMessage(t('xcmBridge.fetchingInfo'));
const info = await fetchAssetHubUsdtInfo();
setAssetHubInfo(info);
setStatusMessage(t('xcmBridge.statusComplete'));
setStep('idle');
} catch (error) {
console.error('Initial check failed:', error);
setErrorMessage(error instanceof Error ? error.message : 'Status check failed');
setStep('error');
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [assetHubApi, isAssetHubReady]);
// Reset when modal opens/closes
useEffect(() => {
if (!isOpen) {
setStep('idle');
setStatusMessage('');
setErrorMessage('');
setShowPoolCreation(false);
} else {
// Auto-check status when opened
if (assetHubApi && isAssetHubReady && account) {
performInitialCheck();
}
}
}, [isOpen, assetHubApi, isAssetHubReady, account, performInitialCheck]);
/**
* Configure XCM bridge
*/
const handleConfigureBridge = async () => {
if (!assetHubApi || !isAssetHubReady || !signer || !account) {
toast({
title: t('common.error'),
description: t('common.connectWalletAlert'),
variant: 'destructive',
});
return;
}
setStep('configuring');
setErrorMessage('');
try {
await configureXcmBridge(
assetHubApi,
signer,
account,
(status) => setStatusMessage(status)
);
toast({
title: t('common.success'),
description: t('xcmBridge.bridgeConfigured'),
});
// Refresh status
await performInitialCheck();
setStep('success');
setStatusMessage(t('xcmBridge.configComplete'));
} catch (error) {
console.error('Bridge configuration failed:', error);
setErrorMessage(error instanceof Error ? error.message : 'Configuration failed');
setStep('error');
toast({
title: t('xcmBridge.configFailed'),
description: error instanceof Error ? error.message : t('common.error'),
variant: 'destructive',
});
}
};
/**
* Create wUSDT/HEZ pool
*/
const handleCreatePool = async () => {
if (!assetHubApi || !isAssetHubReady || !signer || !account) {
toast({
title: t('common.error'),
description: t('common.connectWalletAlert'),
variant: 'destructive',
});
return;
}
setStep('pool-creation');
setErrorMessage('');
try {
// Convert amounts to raw values (6 decimals for wUSDT, 12 for HEZ)
const wusdtRaw = parseTokenInput(wusdtAmount, 6);
const hezRaw = parseTokenInput(hezAmount, 12);
await createWUsdtHezPool(
assetHubApi,
signer,
account,
wusdtRaw,
hezRaw,
(status) => setStatusMessage(status)
);
toast({
title: t('common.success'),
description: t('xcmBridge.poolCreated'),
});
setStep('success');
setStatusMessage(t('xcmBridge.poolComplete'));
setTimeout(() => {
onSuccess?.();
onClose();
}, 2000);
} catch (error) {
console.error('Pool creation failed:', error);
setErrorMessage(error instanceof Error ? error.message : 'Pool creation failed');
setStep('error');
toast({
title: t('xcmBridge.poolFailed'),
description: error instanceof Error ? error.message : t('common.error'),
variant: 'destructive',
});
}
};
if (!isOpen) return null;
const isLoading = step === 'checking' || step === 'fetching' || step === 'configuring' || step === 'pool-creation';
return (
<div className="fixed inset-0 bg-black/60 backdrop-blur-sm flex items-center justify-center z-50 p-4">
<Card className="bg-gray-900 border-gray-800 max-w-2xl w-full max-h-[90vh] overflow-y-auto">
<CardHeader className="border-b border-gray-800">
<div className="flex items-center justify-between">
<CardTitle className="text-xl font-bold text-white">
{t('xcmBridge.title')}
</CardTitle>
<button
onClick={onClose}
className="text-gray-400 hover:text-white transition-colors"
disabled={isLoading}
>
<X className="w-5 h-5" />
</button>
</div>
<Badge className="bg-purple-600/20 text-purple-400 border-purple-600/30 w-fit mt-2">
{t('xcmBridge.adminOnly')}
</Badge>
</CardHeader>
<CardContent className="space-y-6 pt-6">
{/* Info Banner */}
<Alert className="bg-purple-500/10 border-purple-500/30">
<Zap className="h-4 w-4 text-purple-400" />
<AlertDescription className="text-purple-300 text-sm">
{t('xcmBridge.info')}
</AlertDescription>
</Alert>
{/* Current Status */}
{bridgeStatus && (
<div className="p-4 bg-gray-800/50 rounded-lg border border-gray-700 space-y-3">
<div className="text-sm font-semibold text-gray-300 mb-2">{t('xcmBridge.currentStatus')}</div>
<div className="flex items-center justify-between">
<span className="text-sm text-gray-400">{t('xcmBridge.assetHubConnection')}</span>
<div className="flex items-center gap-2">
{bridgeStatus.assetHubConnected ? (
<CheckCircle className="w-4 h-4 text-green-400" />
) : (
<AlertCircle className="w-4 h-4 text-yellow-400" />
)}
<span className={bridgeStatus.assetHubConnected ? 'text-green-400' : 'text-yellow-400'}>
{bridgeStatus.assetHubConnected ? t('xcmBridge.connected') : t('xcmBridge.checking')}
</span>
</div>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-gray-400">{t('xcmBridge.wusdtAssetExists')}</span>
<div className="flex items-center gap-2">
{bridgeStatus.wusdtExists ? (
<CheckCircle className="w-4 h-4 text-green-400" />
) : (
<AlertCircle className="w-4 h-4 text-red-400" />
)}
<span className={bridgeStatus.wusdtExists ? 'text-green-400' : 'text-red-400'}>
{bridgeStatus.wusdtExists ? t('xcmBridge.yesId') : t('xcmBridge.notFound')}
</span>
</div>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-gray-400">{t('xcmBridge.xcmConfigured')}</span>
<div className="flex items-center gap-2">
{bridgeStatus.isConfigured ? (
<CheckCircle className="w-4 h-4 text-green-400" />
) : (
<AlertCircle className="w-4 h-4 text-yellow-400" />
)}
<span className={bridgeStatus.isConfigured ? 'text-green-400' : 'text-yellow-400'}>
{bridgeStatus.isConfigured ? t('xcmBridge.configured') : t('xcmBridge.notConfigured')}
</span>
</div>
</div>
</div>
)}
{/* Asset Hub USDT Info */}
{assetHubInfo && (
<div className="p-4 bg-gray-800/50 rounded-lg border border-gray-700 space-y-2">
<div className="text-sm font-semibold text-gray-300 mb-2">{t('xcmBridge.assetHubInfo')}</div>
<div className="grid grid-cols-2 gap-2 text-sm">
<span className="text-gray-400">Asset ID:</span>
<span className="text-white font-mono">{assetHubInfo.id}</span>
<span className="text-gray-400">Symbol:</span>
<span className="text-white">{assetHubInfo.symbol}</span>
<span className="text-gray-400">Decimals:</span>
<span className="text-white">{assetHubInfo.decimals}</span>
<span className="text-gray-400">Total Supply:</span>
<span className="text-white">{(parseFloat(assetHubInfo.supply) / 10 ** 6).toLocaleString()} USDT</span>
</div>
<a
href="https://westend-assethub.subscan.io/"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1 text-xs text-purple-400 hover:text-purple-300 transition-colors mt-2"
>
View on Subscan <ExternalLink className="w-3 h-3" />
</a>
</div>
)}
{/* Configuration Details */}
<div className="p-4 bg-gray-800/50 rounded-lg border border-gray-700 space-y-2">
<div className="text-sm font-semibold text-gray-300 mb-2">{t('xcmBridge.configDetails')}</div>
<div className="text-xs space-y-1 text-gray-400 font-mono">
<div>Asset Hub Endpoint: {ASSET_HUB_ENDPOINT}</div>
<div>Asset Hub USDT ID: {ASSET_HUB_USDT_ID}</div>
<div>PezkuwiChain wUSDT ID: {WUSDT_ASSET_ID}</div>
<div>Parachain ID: 1000 (Asset Hub)</div>
</div>
</div>
{/* Status Message */}
{statusMessage && (
<Alert className="bg-blue-500/10 border-blue-500/30">
<Info className="h-4 w-4 text-blue-400" />
<AlertDescription className="text-blue-300 text-sm">
{statusMessage}
</AlertDescription>
</Alert>
)}
{/* Error Message */}
{errorMessage && (
<Alert className="bg-red-500/10 border-red-500/30">
<AlertCircle className="h-4 w-4 text-red-400" />
<AlertDescription className="text-red-300 text-sm">
{errorMessage}
</AlertDescription>
</Alert>
)}
{/* Success Message */}
{step === 'success' && (
<Alert className="bg-green-500/10 border-green-500/30">
<CheckCircle className="h-4 w-4 text-green-400" />
<AlertDescription className="text-green-300 text-sm">
{statusMessage}
</AlertDescription>
</Alert>
)}
{/* Pool Creation Section (Optional) */}
{showPoolCreation && (
<div className="p-4 bg-gray-800/50 rounded-lg border border-gray-700 space-y-4">
<div className="text-sm font-semibold text-gray-300">{t('xcmBridge.createPoolSection')}</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="text-xs text-gray-400">{t('xcmBridge.wusdtAmount')}</label>
<input
type="number"
value={wusdtAmount}
onChange={(e) => setWusdtAmount(e.target.value)}
className="w-full px-3 py-2 bg-gray-800 border border-gray-700 rounded text-white text-sm"
placeholder="1000"
/>
</div>
<div>
<label className="text-xs text-gray-400">{t('xcmBridge.hezAmount')}</label>
<input
type="number"
value={hezAmount}
onChange={(e) => setHezAmount(e.target.value)}
className="w-full px-3 py-2 bg-gray-800 border border-gray-700 rounded text-white text-sm"
placeholder="10"
/>
</div>
</div>
</div>
)}
{/* Action Buttons */}
<div className="flex gap-3 pt-4">
<Button
onClick={onClose}
variant="outline"
className="flex-1 border-gray-700 hover:bg-gray-800"
disabled={isLoading}
>
{t('xcmBridge.close')}
</Button>
{!bridgeStatus?.isConfigured && (
<Button
onClick={handleConfigureBridge}
className="flex-1 bg-purple-600 hover:bg-purple-700"
disabled={isLoading || !bridgeStatus?.assetHubConnected}
>
{step === 'configuring' ? (
<>
<Loader2 className="w-4 h-4 animate-spin mr-2" />
{t('xcmBridge.configuring')}
</>
) : (
t('xcmBridge.configureBridge')
)}
</Button>
)}
{bridgeStatus?.isConfigured && !showPoolCreation && (
<Button
onClick={() => setShowPoolCreation(true)}
className="flex-1 bg-green-600 hover:bg-green-700"
>
{t('xcmBridge.createPoolOptional')}
</Button>
)}
{showPoolCreation && (
<Button
onClick={handleCreatePool}
className="flex-1 bg-green-600 hover:bg-green-700"
disabled={isLoading}
>
{step === 'pool-creation' ? (
<>
<Loader2 className="w-4 h-4 animate-spin mr-2" />
{t('xcmBridge.creatingPool')}
</>
) : (
t('xcmBridge.createPool')
)}
</Button>
)}
</div>
{/* Note */}
<div className="text-xs text-gray-500 text-center">
{t('xcmBridge.sudoWarning')}
</div>
</CardContent>
</Card>
</div>
);
};
-94
View File
@@ -639,9 +639,6 @@ export default {
'dex.admin.tokenMinting': 'سك التوكنات',
'dex.admin.tokenMintingDesc': 'سك توكنات مغلفة للاختبار وتوفير السيولة',
'dex.admin.mintToken': 'سك {{symbol}}',
'dex.admin.xcmWizard': 'معالج إعداد XCM',
'dex.admin.xcmWizardDesc': 'إعداد الباراتشين من 6 خطوات: حجز ParaId، إنشاء المخرجات، تسجيل الباراتشين، فتح قنوات HRMP، تسجيل الأصول الأجنبية، واختبار تحويلات XCM.',
'dex.admin.openXcmWizard': 'فتح معالج إعداد XCM',
'dex.admin.poolManagement': 'إدارة المجمعات',
'dex.admin.poolManagementDesc': 'إنشاء مجمعات سيولة جديدة لأزواج التوكنات على PezkuwiChain',
'dex.admin.createNewPool': 'إنشاء مجمع جديد',
@@ -783,41 +780,6 @@ export default {
'mintUsdt.mintBtn': 'سك wUSDT',
'mintUsdt.minted': 'تم سك {{amount}} wUSDT بنجاح',
// XCMBridgeSetupModal
'xcmBridge.title': 'إعداد جسر XCM',
'xcmBridge.adminOnly': 'للمشرف فقط - إعداد XCM',
'xcmBridge.info': 'إعداد جسر Asset Hub USDT → wUSDT بنقرة واحدة. يتيح هذا التحويلات عبر السلاسل من Westend Asset Hub إلى PezkuwiChain.',
'xcmBridge.currentStatus': 'الحالة الحالية',
'xcmBridge.assetHubConnection': 'اتصال Asset Hub:',
'xcmBridge.connected': 'متصل',
'xcmBridge.checking': 'جاري التحقق...',
'xcmBridge.wusdtAssetExists': 'أصل wUSDT موجود:',
'xcmBridge.yesId': 'نعم (المعرّف: 1000)',
'xcmBridge.notFound': 'غير موجود',
'xcmBridge.xcmConfigured': 'جسر XCM مُهيّأ:',
'xcmBridge.configured': 'مُهيّأ',
'xcmBridge.notConfigured': 'غير مُهيّأ',
'xcmBridge.assetHubInfo': 'معلومات Asset Hub USDT',
'xcmBridge.configDetails': 'تفاصيل الإعداد',
'xcmBridge.checkingStatus': 'جاري التحقق من حالة الجسر...',
'xcmBridge.fetchingInfo': 'جاري جلب معلومات Asset Hub USDT...',
'xcmBridge.statusComplete': 'اكتمل التحقق من الحالة',
'xcmBridge.configComplete': 'اكتمل إعداد الجسر!',
'xcmBridge.poolComplete': 'اكتمل إنشاء المجمع!',
'xcmBridge.close': 'إغلاق',
'xcmBridge.configureBridge': 'إعداد الجسر',
'xcmBridge.configuring': 'جاري الإعداد...',
'xcmBridge.createPoolOptional': 'إنشاء مجمع (اختياري)',
'xcmBridge.createPool': 'إنشاء مجمع',
'xcmBridge.creatingPool': 'جاري الإنشاء...',
'xcmBridge.wusdtAmount': 'كمية wUSDT',
'xcmBridge.hezAmount': 'كمية HEZ',
'xcmBridge.createPoolSection': 'إنشاء مجمع wUSDT/HEZ (اختياري)',
'xcmBridge.sudoWarning': 'إعداد جسر XCM يتطلب صلاحيات sudo',
'xcmBridge.bridgeConfigured': 'تم إعداد جسر XCM بنجاح',
'xcmBridge.configFailed': 'فشل الإعداد',
'xcmBridge.poolCreated': 'تم إنشاء مجمع wUSDT/HEZ بنجاح',
'xcmBridge.poolFailed': 'فشل إنشاء المجمع',
// TokenSwap
'tokenSwap.dexComingSoon': 'DEX قريبًا',
@@ -3156,62 +3118,6 @@ export default {
'kyc.approval.failedDesc': 'فشل في الموافقة على الإحالة',
// Batch 11: XCM Wizard
'xcmWizard.title': 'معالج تكوين XCM',
'xcmWizard.subtitle': 'أكمل إعداد الباراتشين والتكامل عبر السلاسل',
'xcmWizard.progress': '{{completed}} / {{total}} خطوات مكتملة',
'xcmWizard.walletNotConnected': 'المحفظة غير متصلة',
'xcmWizard.connectFirst': 'يرجى ربط محفظتك أولاً',
'xcmWizard.relayChainLabel': 'اختر سلسلة الإرسال',
'xcmWizard.westend': 'Westend (شبكة اختبار)',
'xcmWizard.rococo': 'Rococo (شبكة اختبار)',
'xcmWizard.polkadot': 'Polkadot (الشبكة الرئيسية)',
'xcmWizard.stepReserve': 'حجز ParaId',
'xcmWizard.stepArtifacts': 'إنشاء مكونات السلسلة',
'xcmWizard.stepParachain': 'تسجيل الباراتشين',
'xcmWizard.stepHrmp': 'فتح قنوات HRMP',
'xcmWizard.stepAssets': 'تسجيل الأصول الخارجية',
'xcmWizard.stepTest': 'اختبار نقل XCM',
'xcmWizard.reserving': 'جارٍ حجز ParaId...',
'xcmWizard.reserved': 'تم حجز ParaId',
'xcmWizard.reserveBtn': 'حجز ParaId',
'xcmWizard.reserveSuccess': 'تم حجز ParaId {{paraId}} على {{chain}} بنجاح',
'xcmWizard.reserveFailed': 'فشل في حجز ParaId',
'xcmWizard.generating': 'جارٍ إنشاء المكونات...',
'xcmWizard.generated': 'تم إنشاء المكونات',
'xcmWizard.generateBtn': 'إنشاء مكونات السلسلة',
'xcmWizard.artifactsReady': 'تم إنشاء المكونات. حمّل الملفات للتسجيل.',
'xcmWizard.artifactsFailed': 'فشل في إنشاء مكونات السلسلة',
'xcmWizard.genesisLabel': 'رفع حالة Genesis',
'xcmWizard.wasmLabel': 'رفع Runtime WASM',
'xcmWizard.missingFiles': 'يرجى رفع ملفات genesis و WASM معاً',
'xcmWizard.registering': 'جارٍ تسجيل الباراتشين...',
'xcmWizard.registered': 'تم تسجيل الباراتشين',
'xcmWizard.registerBtn': 'تسجيل الباراتشين',
'xcmWizard.registerSuccess': 'تم تسجيل ParaId {{paraId}} على {{chain}}',
'xcmWizard.registerFailed': 'فشل في تسجيل الباراتشين',
'xcmWizard.openingHrmp': 'جارٍ فتح قنوات HRMP...',
'xcmWizard.channelsOpened': 'تم فتح القنوات',
'xcmWizard.hrmpBtn': 'فتح قنوات HRMP',
'xcmWizard.hrmpSuccess': 'تم فتح {{count}} قناة مع Asset Hub',
'xcmWizard.hrmpFailed': 'فشل في فتح قنوات HRMP',
'xcmWizard.registeringAssets': 'جارٍ تسجيل الأصول...',
'xcmWizard.assetsRegistered': 'تم تسجيل الأصول',
'xcmWizard.assetsBtn': 'تسجيل الأصول الخارجية',
'xcmWizard.assetsDesc': 'تسجيل الأصول الخارجية: USDT وDOT والرموز الأخرى عبر السلاسل',
'xcmWizard.assetsSuccess': 'تم تسجيل {{count}} أصل خارجي',
'xcmWizard.assetsFailed': 'فشل في تسجيل الأصول الخارجية',
'xcmWizard.testing': 'جارٍ اختبار نقل XCM...',
'xcmWizard.testPassed': 'نجح اختبار XCM',
'xcmWizard.testBtn': 'اختبار نقل XCM',
'xcmWizard.testDesc': 'اختبر نقل XCM من Asset Hub للتحقق من وظيفة الجسر',
'xcmWizard.testSuccess': 'تم استلام {{balance}} wUSDT',
'xcmWizard.testFailed': 'فشل النقل التجريبي',
'xcmWizard.notReady': 'يرجى انتظار اتصال Asset Hub',
'xcmWizard.previous': 'السابق',
'xcmWizard.next': 'التالي',
'xcmWizard.finish': 'إنهاء التكوين',
'xcmWizard.complete': 'اكتمل تكوين XCM!',
'xcmWizard.completeDesc': 'الباراتشين مُهيأ بالكامل وجاهز للتحويلات عبر السلاسل',
// Batch 11: Permission Editor
'permission.title': 'محرر الصلاحيات',
-94
View File
@@ -630,9 +630,6 @@ export default {
'dex.admin.tokenMinting': 'چاپکردنی تۆکن',
'dex.admin.tokenMintingDesc': 'چاپکردنی تۆکنی پێچراو بۆ تاقیکردنەوە و دابینکردنی لیکویدیتی',
'dex.admin.mintToken': 'چاپکردنی {{symbol}}',
'dex.admin.xcmWizard': 'ویزاردی ڕێکخستنی XCM',
'dex.admin.xcmWizardDesc': '٦ هەنگاوی ڕێکخستنی پاراچەین: گرتنەوەی ParaId، دروستکردنی بەرهەمەکان، تۆمارکردنی پاراچەین، کردنەوەی کەناڵەکانی HRMP، تۆمارکردنی سامانە بیانییەکان، و تاقیکردنەوەی گواستنەوەکانی XCM.',
'dex.admin.openXcmWizard': 'کردنەوەی ویزاردی ڕێکخستنی XCM',
'dex.admin.poolManagement': 'بەڕێوەبردنی حەوز',
'dex.admin.poolManagementDesc': 'دروستکردنی حەوزی لیکویدیتی نوێ بۆ جووتە تۆکنەکان لەسەر PezkuwiChain',
'dex.admin.createNewPool': 'دروستکردنی حەوزی نوێ',
@@ -774,41 +771,6 @@ export default {
'mintUsdt.mintBtn': 'چاپکردنی wUSDT',
'mintUsdt.minted': 'بە سەرکەوتوویی {{amount}} wUSDT چاپکرا',
// XCMBridgeSetupModal
'xcmBridge.title': 'ڕێکخستنی پردی XCM',
'xcmBridge.adminOnly': 'تەنها بەڕێوەبەر - ڕێکخستنی XCM',
'xcmBridge.info': 'ڕێکخستنی پردی Asset Hub USDT → wUSDT بە یەک کرتە. ئەمە گواستنەوەی نێوان زنجیرەکان لە Westend Asset Hub بۆ PezkuwiChain چالاک دەکات.',
'xcmBridge.currentStatus': 'بارودۆخی ئێستا',
'xcmBridge.assetHubConnection': 'پەیوەندی Asset Hub:',
'xcmBridge.connected': 'پەیوەستکراوە',
'xcmBridge.checking': 'پشکنین...',
'xcmBridge.wusdtAssetExists': 'سامانی wUSDT هەیە:',
'xcmBridge.yesId': 'بەڵێ (ID: 1000)',
'xcmBridge.notFound': 'نەدۆزرایەوە',
'xcmBridge.xcmConfigured': 'پردی XCM ڕێکخراوە:',
'xcmBridge.configured': 'ڕێکخراوە',
'xcmBridge.notConfigured': 'ڕێکنەخراوە',
'xcmBridge.assetHubInfo': 'زانیاری USDT ی Asset Hub',
'xcmBridge.configDetails': 'وردەکاریەکانی ڕێکخستن',
'xcmBridge.checkingStatus': 'پشکنینی بارودۆخی پرد...',
'xcmBridge.fetchingInfo': 'هێنانی زانیاری USDT ی Asset Hub...',
'xcmBridge.statusComplete': 'پشکنینی بارودۆخ تەواو بوو',
'xcmBridge.configComplete': 'ڕێکخستنی پرد تەواو بوو!',
'xcmBridge.poolComplete': 'دروستکردنی حەوز تەواو بوو!',
'xcmBridge.close': 'داخستن',
'xcmBridge.configureBridge': 'ڕێکخستنی پرد',
'xcmBridge.configuring': 'ڕێکخستن...',
'xcmBridge.createPoolOptional': 'دروستکردنی حەوز (ئارەزوومەندانە)',
'xcmBridge.createPool': 'دروستکردنی حەوز',
'xcmBridge.creatingPool': 'دروستکردن...',
'xcmBridge.wusdtAmount': 'بڕی wUSDT',
'xcmBridge.hezAmount': 'بڕی HEZ',
'xcmBridge.createPoolSection': 'دروستکردنی حەوزی wUSDT/HEZ (ئارەزوومەندانە)',
'xcmBridge.sudoWarning': 'ڕێکخستنی پردی XCM پێویستی بە دەستگەیشتنی sudo هەیە',
'xcmBridge.bridgeConfigured': 'پردی XCM بە سەرکەوتوویی ڕێکخرا',
'xcmBridge.configFailed': 'ڕێکخستن سەرکەوتوو نەبوو',
'xcmBridge.poolCreated': 'حەوزی wUSDT/HEZ بە سەرکەوتوویی دروستکرا',
'xcmBridge.poolFailed': 'دروستکردنی حەوز سەرکەوتوو نەبوو',
// TokenSwap
'tokenSwap.dexComingSoon': 'DEX بەم زووانە دێت',
@@ -3146,62 +3108,6 @@ export default {
'kyc.approval.failedDesc': 'پەسەندکردنی ئاماژە سەرنەکەوت',
// Batch 11: XCM Wizard
'xcmWizard.title': 'ئەفسوونگەری ڕێکخستنی XCM',
'xcmWizard.subtitle': 'دامەزراندنی پاراچەین و یەکگرتنی نێوان زنجیرەکان تەواو بکە',
'xcmWizard.progress': '{{completed}} / {{total}} هەنگاو تەواوکرا',
'xcmWizard.walletNotConnected': 'جزدان پەیوەست نییە',
'xcmWizard.connectFirst': 'تکایە سەرەتا جزدانت پەیوەند بکە',
'xcmWizard.relayChainLabel': 'زنجیرەی ڕیلەی هەڵبژێرە',
'xcmWizard.westend': 'Westend (تاقیکاری)',
'xcmWizard.rococo': 'Rococo (تاقیکاری)',
'xcmWizard.polkadot': 'Polkadot (سەرەکی)',
'xcmWizard.stepReserve': 'جێگرتنی ParaId',
'xcmWizard.stepArtifacts': 'دروستکردنی بەرهەمەکانی زنجیرە',
'xcmWizard.stepParachain': 'تۆمارکردنی پاراچەین',
'xcmWizard.stepHrmp': 'کردنەوەی کەناڵەکانی HRMP',
'xcmWizard.stepAssets': 'تۆمارکردنی سامانە دەرەکیەکان',
'xcmWizard.stepTest': 'تاقیکردنەوەی گواستنەوەی XCM',
'xcmWizard.reserving': 'ParaId جێدەگیرێت...',
'xcmWizard.reserved': 'ParaId جێگیرا',
'xcmWizard.reserveBtn': 'جێگرتنی ParaId',
'xcmWizard.reserveSuccess': 'لەسەر {{chain}} ParaId {{paraId}} بە سەرکەوتوویی جێگیرا',
'xcmWizard.reserveFailed': 'جێگرتنی ParaId سەرنەکەوت',
'xcmWizard.generating': 'بەرهەمەکان دروست دەکرێن...',
'xcmWizard.generated': 'بەرهەمەکان دروستکران',
'xcmWizard.generateBtn': 'دروستکردنی بەرهەمەکانی زنجیرە',
'xcmWizard.artifactsReady': 'بەرهەمەکان دروستکران. فایلەکان دابەزێنە بۆ تۆمارکردن.',
'xcmWizard.artifactsFailed': 'دروستکردنی بەرهەمەکانی زنجیرە سەرنەکەوت',
'xcmWizard.genesisLabel': 'بارکردنی حاڵەتی Genesis',
'xcmWizard.wasmLabel': 'بارکردنی Runtime WASM',
'xcmWizard.missingFiles': 'تکایە هەردوو فایلی genesis و WASM بار بکە',
'xcmWizard.registering': 'پاراچەین تۆمار دەکرێت...',
'xcmWizard.registered': 'پاراچەین تۆمارکرا',
'xcmWizard.registerBtn': 'تۆمارکردنی پاراچەین',
'xcmWizard.registerSuccess': 'ParaId {{paraId}} لەسەر {{chain}} تۆمارکرا',
'xcmWizard.registerFailed': 'تۆمارکردنی پاراچەین سەرنەکەوت',
'xcmWizard.openingHrmp': 'کەناڵەکانی HRMP دەکرێنەوە...',
'xcmWizard.channelsOpened': 'کەناڵەکان کرانەوە',
'xcmWizard.hrmpBtn': 'کردنەوەی کەناڵەکانی HRMP',
'xcmWizard.hrmpSuccess': '{{count}} کەناڵ لەگەڵ Asset Hub کرایەوە',
'xcmWizard.hrmpFailed': 'کردنەوەی کەناڵەکانی HRMP سەرنەکەوت',
'xcmWizard.registeringAssets': 'سامانەکان تۆمار دەکرێن...',
'xcmWizard.assetsRegistered': 'سامانەکان تۆمارکران',
'xcmWizard.assetsBtn': 'تۆمارکردنی سامانە دەرەکیەکان',
'xcmWizard.assetsDesc': 'سامانە دەرەکیەکان تۆمار بکە: USDT، DOT و تۆکنەکانی دیکەی نێوان زنجیرە',
'xcmWizard.assetsSuccess': '{{count}} سامانی دەرەکی تۆمارکرا',
'xcmWizard.assetsFailed': 'تۆمارکردنی سامانە دەرەکیەکان سەرنەکەوت',
'xcmWizard.testing': 'تاقیکردنەوەی گواستنەوەی XCM...',
'xcmWizard.testPassed': 'تاقیکردنەوەی XCM سەرکەوتوو بوو',
'xcmWizard.testBtn': 'تاقیکردنەوەی گواستنەوەی XCM',
'xcmWizard.testDesc': 'بۆ پشتڕاستکردنی کارکردنی پردەکە گواستنەوەی XCM لە Asset Hub تاقی بکەرەوە',
'xcmWizard.testSuccess': '{{balance}} wUSDT وەرگیرا',
'xcmWizard.testFailed': 'گواستنەوەی تاقیکردنەوە سەرنەکەوت',
'xcmWizard.notReady': 'تکایە چاوەڕوانی پەیوەندی Asset Hub بکە',
'xcmWizard.previous': 'پێشوو',
'xcmWizard.next': 'دواتر',
'xcmWizard.finish': 'تەواوکردنی ڕێکخستن',
'xcmWizard.complete': 'ڕێکخستنی XCM تەواو بوو!',
'xcmWizard.completeDesc': 'پاراچەینەکەت بە تەواوی ڕێکخرا و ئامادەیە بۆ گواستنەوەی نێوان زنجیرەکان',
// Batch 11: Permission Editor
'permission.title': 'دەستکاریکاری مۆڵەتەکان',
-94
View File
@@ -972,9 +972,6 @@ export default {
'dex.admin.tokenMinting': 'Token Minting',
'dex.admin.tokenMintingDesc': 'Mint wrapped tokens for testing and liquidity provision',
'dex.admin.mintToken': 'Mint {{symbol}}',
'dex.admin.xcmWizard': 'XCM Configuration Wizard',
'dex.admin.xcmWizardDesc': 'Complete 6-step parachain setup: Reserve ParaId, generate artifacts, register parachain, open HRMP channels, register foreign assets, and test XCM transfers.',
'dex.admin.openXcmWizard': 'Open XCM Configuration Wizard',
'dex.admin.poolManagement': 'Pool Management',
'dex.admin.poolManagementDesc': 'Create new liquidity pools for token pairs on PezkuwiChain',
'dex.admin.createNewPool': 'Create New Pool',
@@ -1116,41 +1113,6 @@ export default {
'mintUsdt.mintBtn': 'Mint wUSDT',
'mintUsdt.minted': 'Successfully minted {{amount}} wUSDT',
// XCMBridgeSetupModal
'xcmBridge.title': 'XCM Bridge Setup',
'xcmBridge.adminOnly': 'Admin Only - XCM Configuration',
'xcmBridge.info': 'Configure Asset Hub USDT → wUSDT bridge with one click. This enables cross-chain transfers from Westend Asset Hub to PezkuwiChain.',
'xcmBridge.currentStatus': 'Current Status',
'xcmBridge.assetHubConnection': 'Asset Hub Connection:',
'xcmBridge.connected': 'Connected',
'xcmBridge.checking': 'Checking...',
'xcmBridge.wusdtAssetExists': 'wUSDT Asset Exists:',
'xcmBridge.yesId': 'Yes (ID: 1000)',
'xcmBridge.notFound': 'Not Found',
'xcmBridge.xcmConfigured': 'XCM Bridge Configured:',
'xcmBridge.configured': 'Configured',
'xcmBridge.notConfigured': 'Not Configured',
'xcmBridge.assetHubInfo': 'Asset Hub USDT Info',
'xcmBridge.configDetails': 'Configuration Details',
'xcmBridge.checkingStatus': 'Checking bridge status...',
'xcmBridge.fetchingInfo': 'Fetching Asset Hub USDT info...',
'xcmBridge.statusComplete': 'Status check complete',
'xcmBridge.configComplete': 'Bridge configuration complete!',
'xcmBridge.poolComplete': 'Pool creation complete!',
'xcmBridge.close': 'Close',
'xcmBridge.configureBridge': 'Configure Bridge',
'xcmBridge.configuring': 'Configuring...',
'xcmBridge.createPoolOptional': 'Create Pool (Optional)',
'xcmBridge.createPool': 'Create Pool',
'xcmBridge.creatingPool': 'Creating...',
'xcmBridge.wusdtAmount': 'wUSDT Amount',
'xcmBridge.hezAmount': 'HEZ Amount',
'xcmBridge.createPoolSection': 'Create wUSDT/HEZ Pool (Optional)',
'xcmBridge.sudoWarning': 'XCM bridge configuration requires sudo access',
'xcmBridge.bridgeConfigured': 'XCM bridge configured successfully',
'xcmBridge.configFailed': 'Configuration Failed',
'xcmBridge.poolCreated': 'wUSDT/HEZ pool created successfully',
'xcmBridge.poolFailed': 'Pool Creation Failed',
// TokenSwap
'tokenSwap.dexComingSoon': 'DEX Coming Soon',
@@ -3441,62 +3403,6 @@ export default {
'kyc.approval.failedDesc': 'Failed to approve referral',
// Batch 11: XCM Configuration Wizard
'xcmWizard.title': 'XCM Configuration Wizard',
'xcmWizard.subtitle': 'Complete parachain setup and cross-chain integration',
'xcmWizard.progress': '{{completed}} / {{total}} steps completed',
'xcmWizard.walletNotConnected': 'Wallet not connected',
'xcmWizard.connectFirst': 'Please connect your wallet first',
'xcmWizard.relayChainLabel': 'Select Relay Chain',
'xcmWizard.westend': 'Westend (Testnet)',
'xcmWizard.rococo': 'Rococo (Testnet)',
'xcmWizard.polkadot': 'Polkadot (Mainnet)',
'xcmWizard.stepReserve': 'Reserve ParaId',
'xcmWizard.stepArtifacts': 'Generate Chain Artifacts',
'xcmWizard.stepParachain': 'Register Parachain',
'xcmWizard.stepHrmp': 'Open HRMP Channels',
'xcmWizard.stepAssets': 'Register Foreign Assets',
'xcmWizard.stepTest': 'Test XCM Transfer',
'xcmWizard.reserving': 'Reserving ParaId...',
'xcmWizard.reserved': 'ParaId Reserved',
'xcmWizard.reserveBtn': 'Reserve ParaId',
'xcmWizard.reserveSuccess': 'Successfully reserved ParaId {{paraId}} on {{chain}}',
'xcmWizard.reserveFailed': 'Failed to reserve ParaId',
'xcmWizard.generating': 'Generating Artifacts...',
'xcmWizard.generated': 'Artifacts Generated',
'xcmWizard.generateBtn': 'Generate Chain Artifacts',
'xcmWizard.artifactsReady': 'Artifacts generated. Download files for registration.',
'xcmWizard.artifactsFailed': 'Failed to generate chain artifacts',
'xcmWizard.genesisLabel': 'Upload Genesis State',
'xcmWizard.wasmLabel': 'Upload Runtime WASM',
'xcmWizard.missingFiles': 'Please upload both genesis and WASM files',
'xcmWizard.registering': 'Registering Parachain...',
'xcmWizard.registered': 'Parachain Registered',
'xcmWizard.registerBtn': 'Register Parachain',
'xcmWizard.registerSuccess': 'ParaId {{paraId}} registered on {{chain}}',
'xcmWizard.registerFailed': 'Failed to register parachain',
'xcmWizard.openingHrmp': 'Opening HRMP Channels...',
'xcmWizard.channelsOpened': 'Channels Opened',
'xcmWizard.hrmpBtn': 'Open HRMP Channels',
'xcmWizard.hrmpSuccess': 'Opened {{count}} channel(s) with Asset Hub',
'xcmWizard.hrmpFailed': 'Failed to open HRMP channels',
'xcmWizard.registeringAssets': 'Registering Assets...',
'xcmWizard.assetsRegistered': 'Assets Registered',
'xcmWizard.assetsBtn': 'Register Foreign Assets',
'xcmWizard.assetsDesc': 'Register foreign assets: USDT, DOT, and other cross-chain tokens',
'xcmWizard.assetsSuccess': 'Registered {{count}} foreign asset(s)',
'xcmWizard.assetsFailed': 'Failed to register foreign assets',
'xcmWizard.testing': 'Testing XCM Transfer...',
'xcmWizard.testPassed': 'XCM Test Passed',
'xcmWizard.testBtn': 'Test XCM Transfer',
'xcmWizard.testDesc': 'Test XCM transfer from Asset Hub to verify bridge functionality',
'xcmWizard.testSuccess': 'Received {{balance}} wUSDT',
'xcmWizard.testFailed': 'Test transfer failed',
'xcmWizard.notReady': 'Please wait for Asset Hub connection',
'xcmWizard.previous': 'Previous',
'xcmWizard.next': 'Next',
'xcmWizard.finish': 'Finish Configuration',
'xcmWizard.complete': 'XCM Configuration Complete!',
'xcmWizard.completeDesc': 'Your parachain is fully configured and ready for cross-chain transfers',
// Batch 11: Permission Editor
'permission.title': 'Permission Editor',
-94
View File
@@ -642,9 +642,6 @@ export default {
'dex.admin.tokenMinting': 'ضرب توکن',
'dex.admin.tokenMintingDesc': 'ضرب توکن‌های بسته‌بندی شده برای آزمایش و تأمین نقدینگی',
'dex.admin.mintToken': 'ضرب {{symbol}}',
'dex.admin.xcmWizard': 'جادوگر پیکربندی XCM',
'dex.admin.xcmWizardDesc': 'راه‌اندازی ۶ مرحله‌ای پاراچین: رزرو ParaId، تولید مصنوعات، ثبت پاراچین، باز کردن کانال‌های HRMP، ثبت دارایی‌های خارجی و آزمایش انتقال‌های XCM.',
'dex.admin.openXcmWizard': 'باز کردن جادوگر پیکربندی XCM',
'dex.admin.poolManagement': 'مدیریت استخر',
'dex.admin.poolManagementDesc': 'ایجاد استخرهای نقدینگی جدید برای جفت توکن‌ها در PezkuwiChain',
'dex.admin.createNewPool': 'ایجاد استخر جدید',
@@ -786,41 +783,6 @@ export default {
'mintUsdt.mintBtn': 'ضرب wUSDT',
'mintUsdt.minted': '{{amount}} wUSDT با موفقیت ضرب شد',
// XCMBridgeSetupModal
'xcmBridge.title': 'راه‌اندازی پل XCM',
'xcmBridge.adminOnly': 'فقط مدیر - پیکربندی XCM',
'xcmBridge.info': 'پیکربندی پل Asset Hub USDT → wUSDT با یک کلیک. این امکان انتقال‌های بین زنجیره‌ای از Westend Asset Hub به PezkuwiChain را فراهم می‌کند.',
'xcmBridge.currentStatus': 'وضعیت فعلی',
'xcmBridge.assetHubConnection': 'اتصال Asset Hub:',
'xcmBridge.connected': 'متصل',
'xcmBridge.checking': 'در حال بررسی...',
'xcmBridge.wusdtAssetExists': 'دارایی wUSDT موجود است:',
'xcmBridge.yesId': 'بله (شناسه: ۱۰۰۰)',
'xcmBridge.notFound': 'یافت نشد',
'xcmBridge.xcmConfigured': 'پل XCM پیکربندی شده:',
'xcmBridge.configured': 'پیکربندی شده',
'xcmBridge.notConfigured': 'پیکربندی نشده',
'xcmBridge.assetHubInfo': 'اطلاعات USDT در Asset Hub',
'xcmBridge.configDetails': 'جزئیات پیکربندی',
'xcmBridge.checkingStatus': 'بررسی وضعیت پل...',
'xcmBridge.fetchingInfo': 'دریافت اطلاعات USDT از Asset Hub...',
'xcmBridge.statusComplete': 'بررسی وضعیت کامل شد',
'xcmBridge.configComplete': 'پیکربندی پل کامل شد!',
'xcmBridge.poolComplete': 'ایجاد استخر کامل شد!',
'xcmBridge.close': 'بستن',
'xcmBridge.configureBridge': 'پیکربندی پل',
'xcmBridge.configuring': 'در حال پیکربندی...',
'xcmBridge.createPoolOptional': 'ایجاد استخر (اختیاری)',
'xcmBridge.createPool': 'ایجاد استخر',
'xcmBridge.creatingPool': 'در حال ایجاد...',
'xcmBridge.wusdtAmount': 'مقدار wUSDT',
'xcmBridge.hezAmount': 'مقدار HEZ',
'xcmBridge.createPoolSection': 'ایجاد استخر wUSDT/HEZ (اختیاری)',
'xcmBridge.sudoWarning': 'پیکربندی پل XCM نیاز به دسترسی sudo دارد',
'xcmBridge.bridgeConfigured': 'پل XCM با موفقیت پیکربندی شد',
'xcmBridge.configFailed': 'پیکربندی ناموفق بود',
'xcmBridge.poolCreated': 'استخر wUSDT/HEZ با موفقیت ایجاد شد',
'xcmBridge.poolFailed': 'ایجاد استخر ناموفق بود',
// TokenSwap
'tokenSwap.dexComingSoon': 'DEX به زودی',
@@ -3190,62 +3152,6 @@ export default {
'kyc.approval.failedDesc': 'تأیید معرفی ناموفق بود',
// Batch 11: XCM Wizard
'xcmWizard.title': 'جادوگر پیکربندی XCM',
'xcmWizard.subtitle': 'نصب پاراچین و یکپارچه‌سازی بین زنجیره‌ای را تکمیل کنید',
'xcmWizard.progress': '{{completed}} / {{total}} مرحله تکمیل شد',
'xcmWizard.walletNotConnected': 'کیف پول متصل نیست',
'xcmWizard.connectFirst': 'لطفاً ابتدا کیف پول خود را متصل کنید',
'xcmWizard.relayChainLabel': 'زنجیره ریله را انتخاب کنید',
'xcmWizard.westend': 'Westend (تست‌نت)',
'xcmWizard.rococo': 'Rococo (تست‌نت)',
'xcmWizard.polkadot': 'Polkadot (اصلی)',
'xcmWizard.stepReserve': 'رزرو ParaId',
'xcmWizard.stepArtifacts': 'ایجاد مصنوعات زنجیره',
'xcmWizard.stepParachain': 'ثبت پاراچین',
'xcmWizard.stepHrmp': 'باز کردن کانال‌های HRMP',
'xcmWizard.stepAssets': 'ثبت دارایی‌های خارجی',
'xcmWizard.stepTest': 'تست انتقال XCM',
'xcmWizard.reserving': 'در حال رزرو ParaId...',
'xcmWizard.reserved': 'ParaId رزرو شد',
'xcmWizard.reserveBtn': 'رزرو ParaId',
'xcmWizard.reserveSuccess': 'ParaId {{paraId}} روی {{chain}} با موفقیت رزرو شد',
'xcmWizard.reserveFailed': 'رزرو ParaId ناموفق بود',
'xcmWizard.generating': 'در حال ایجاد مصنوعات...',
'xcmWizard.generated': 'مصنوعات ایجاد شد',
'xcmWizard.generateBtn': 'ایجاد مصنوعات زنجیره',
'xcmWizard.artifactsReady': 'مصنوعات ایجاد شد. فایل‌ها را برای ثبت دانلود کنید.',
'xcmWizard.artifactsFailed': 'ایجاد مصنوعات زنجیره ناموفق بود',
'xcmWizard.genesisLabel': 'بارگذاری وضعیت Genesis',
'xcmWizard.wasmLabel': 'بارگذاری Runtime WASM',
'xcmWizard.missingFiles': 'لطفاً هم فایل genesis و هم WASM را بارگذاری کنید',
'xcmWizard.registering': 'در حال ثبت پاراچین...',
'xcmWizard.registered': 'پاراچین ثبت شد',
'xcmWizard.registerBtn': 'ثبت پاراچین',
'xcmWizard.registerSuccess': 'ParaId {{paraId}} روی {{chain}} ثبت شد',
'xcmWizard.registerFailed': 'ثبت پاراچین ناموفق بود',
'xcmWizard.openingHrmp': 'در حال باز کردن کانال‌های HRMP...',
'xcmWizard.channelsOpened': 'کانال‌ها باز شد',
'xcmWizard.hrmpBtn': 'باز کردن کانال‌های HRMP',
'xcmWizard.hrmpSuccess': '{{count}} کانال با Asset Hub باز شد',
'xcmWizard.hrmpFailed': 'باز کردن کانال‌های HRMP ناموفق بود',
'xcmWizard.registeringAssets': 'در حال ثبت دارایی‌ها...',
'xcmWizard.assetsRegistered': 'دارایی‌ها ثبت شد',
'xcmWizard.assetsBtn': 'ثبت دارایی‌های خارجی',
'xcmWizard.assetsDesc': 'ثبت دارایی‌های خارجی: USDT، DOT و توکن‌های بین زنجیره‌ای دیگر',
'xcmWizard.assetsSuccess': '{{count}} دارایی خارجی ثبت شد',
'xcmWizard.assetsFailed': 'ثبت دارایی‌های خارجی ناموفق بود',
'xcmWizard.testing': 'در حال تست انتقال XCM...',
'xcmWizard.testPassed': 'تست XCM موفق بود',
'xcmWizard.testBtn': 'تست انتقال XCM',
'xcmWizard.testDesc': 'برای تأیید عملکرد پل، انتقال XCM از Asset Hub را تست کنید',
'xcmWizard.testSuccess': '{{balance}} wUSDT دریافت شد',
'xcmWizard.testFailed': 'انتقال تست ناموفق بود',
'xcmWizard.notReady': 'لطفاً منتظر اتصال Asset Hub باشید',
'xcmWizard.previous': 'قبلی',
'xcmWizard.next': 'بعدی',
'xcmWizard.finish': 'تکمیل پیکربندی',
'xcmWizard.complete': 'پیکربندی XCM تکمیل شد!',
'xcmWizard.completeDesc': 'پاراچین شما کاملاً پیکربندی شده و آماده انتقال بین زنجیره‌ای است',
// Batch 11: Permission Editor
'permission.title': 'ویرایشگر مجوزها',
-94
View File
@@ -636,9 +636,6 @@ export default {
'dex.admin.tokenMinting': 'Darvekirina Tokenê',
'dex.admin.tokenMintingDesc': 'Ji bo ceribandin û peydakirina lîkîdîteyê tokenên pêçandî darveke',
'dex.admin.mintToken': '{{symbol}} Darveke',
'dex.admin.xcmWizard': 'Sêrbazê Mîhengên XCM',
'dex.admin.xcmWizardDesc': 'Sazkirina parachain bi 6 gavan: ParaId reserve bike, artefaktan biafirîne, parachain tomar bike, kanalên HRMP veke, veberhênanên biyanî tomar bike, û veguheztinên XCM biceribîne.',
'dex.admin.openXcmWizard': 'Sêrbazê Mîhengên XCM Veke',
'dex.admin.poolManagement': 'Rêveberiya Hewzê',
'dex.admin.poolManagementDesc': 'Ji bo cotên tokenan li ser PezkuwiChain hewzên lîkîdîteyê yên nû biafirîne',
'dex.admin.createNewPool': 'Hewzeke Nû Biafirîne',
@@ -780,41 +777,6 @@ export default {
'mintUsdt.mintBtn': 'wUSDT Darveke',
'mintUsdt.minted': '{{amount}} wUSDT bi serkeftî hat darvekirin',
// XCMBridgeSetupModal
'xcmBridge.title': 'Sazkirina Pira XCM',
'xcmBridge.adminOnly': 'Tenê Rêvebir - Mîhengên XCM',
'xcmBridge.info': 'Bi yek klîkê pira Asset Hub USDT → wUSDT mîheng bike. Ev veguheztinên cross-chain ji Westend Asset Hub bo PezkuwiChain çalak dike.',
'xcmBridge.currentStatus': 'Rewşa Niha',
'xcmBridge.assetHubConnection': 'Girêdana Asset Hub:',
'xcmBridge.connected': 'Girêdayî',
'xcmBridge.checking': 'Tê kontrol kirin...',
'xcmBridge.wusdtAssetExists': 'Veberhênanên wUSDT Hene:',
'xcmBridge.yesId': 'Erê (ID: 1000)',
'xcmBridge.notFound': 'Nehat Dîtin',
'xcmBridge.xcmConfigured': 'Pira XCM Mîheng Kirî:',
'xcmBridge.configured': 'Mîheng Kirî',
'xcmBridge.notConfigured': 'Ne Mîheng Kirî',
'xcmBridge.assetHubInfo': 'Agahiyên USDT yên Asset Hub',
'xcmBridge.configDetails': 'Hûrguliyên Mîhengê',
'xcmBridge.checkingStatus': 'Rewşa pirê tê kontrol kirin...',
'xcmBridge.fetchingInfo': 'Agahiyên USDT yên Asset Hub tên anîn...',
'xcmBridge.statusComplete': 'Kontrola rewşê qediya',
'xcmBridge.configComplete': 'Mîhenga pirê qediya!',
'xcmBridge.poolComplete': 'Afirandina hewzê qediya!',
'xcmBridge.close': 'Bigire',
'xcmBridge.configureBridge': 'Pirê Mîheng Bike',
'xcmBridge.configuring': 'Tê mîheng kirin...',
'xcmBridge.createPoolOptional': 'Hewz Biafirîne (Bijare)',
'xcmBridge.createPool': 'Hewz Biafirîne',
'xcmBridge.creatingPool': 'Tê afirandin...',
'xcmBridge.wusdtAmount': 'Miqdarê wUSDT',
'xcmBridge.hezAmount': 'Miqdarê HEZ',
'xcmBridge.createPoolSection': 'Hewza wUSDT/HEZ Biafirîne (Bijare)',
'xcmBridge.sudoWarning': 'Mîhenga pira XCM gihîştina sudo hewce dike',
'xcmBridge.bridgeConfigured': 'Pira XCM bi serkeftî hat mîheng kirin',
'xcmBridge.configFailed': 'Mîheng Têk Çû',
'xcmBridge.poolCreated': 'Hewza wUSDT/HEZ bi serkeftî hat afirandin',
'xcmBridge.poolFailed': 'Afirandina Hewzê Têk Çû',
// TokenSwap
'tokenSwap.dexComingSoon': 'DEX Tê',
@@ -3173,62 +3135,6 @@ export default {
'kyc.approval.failedDesc': 'Referans nehat pejirandin',
// Batch 11: XCM Wizard
'xcmWizard.title': 'Sêrbazê Veavakirina XCM',
'xcmWizard.subtitle': 'Sazkirina parachain û yekbûna cross-chain temam bikin',
'xcmWizard.progress': '{{completed}} / {{total}} gav temam bûn',
'xcmWizard.walletNotConnected': 'Cîzdan negirêdayî',
'xcmWizard.connectFirst': 'Ji kerema xwe pêşî cîzdanê xwe ve girêdin',
'xcmWizard.relayChainLabel': 'Relay Chain Hilbijêrin',
'xcmWizard.westend': 'Westend (Testnet)',
'xcmWizard.rococo': 'Rococo (Testnet)',
'xcmWizard.polkadot': 'Polkadot (Mainnet)',
'xcmWizard.stepReserve': 'ParaId Veqetîne',
'xcmWizard.stepArtifacts': 'Berwariyên Zincîrê Biafirîne',
'xcmWizard.stepParachain': 'Parachain Tomar Bike',
'xcmWizard.stepHrmp': 'Kanalên HRMP Veke',
'xcmWizard.stepAssets': 'Malên Biyanî Tomar Bike',
'xcmWizard.stepTest': 'Veguhastina XCM Test Bike',
'xcmWizard.reserving': 'ParaId tê veqetandin...',
'xcmWizard.reserved': 'ParaId Hat Veqetandin',
'xcmWizard.reserveBtn': 'ParaId Veqetîne',
'xcmWizard.reserveSuccess': 'Li ser {{chain}} ParaId {{paraId}} bi serkeftî hat veqetandin',
'xcmWizard.reserveFailed': 'ParaId nehat veqetandin',
'xcmWizard.generating': 'Berwarî tên afirandin...',
'xcmWizard.generated': 'Berwarî Hatin Afirandin',
'xcmWizard.generateBtn': 'Berwariyên Zincîrê Biafirîne',
'xcmWizard.artifactsReady': 'Berwarî hatin afirandin. Pelan daxînin ji bo tomarkirinê.',
'xcmWizard.artifactsFailed': 'Berwariyên zincîrê nehatin afirandin',
'xcmWizard.genesisLabel': 'Rewşa Genesis Bar Bike',
'xcmWizard.wasmLabel': 'Runtime WASM Bar Bike',
'xcmWizard.missingFiles': 'Ji kerema xwe hem genesis hem jî WASM pelan bar bikin',
'xcmWizard.registering': 'Parachain tê tomarkirin...',
'xcmWizard.registered': 'Parachain Hat Tomarkirin',
'xcmWizard.registerBtn': 'Parachain Tomar Bike',
'xcmWizard.registerSuccess': 'ParaId {{paraId}} li ser {{chain}} hat tomarkirin',
'xcmWizard.registerFailed': 'Parachain nehat tomarkirin',
'xcmWizard.openingHrmp': 'Kanalên HRMP tên vekirin...',
'xcmWizard.channelsOpened': 'Kanal Hatin Vekirin',
'xcmWizard.hrmpBtn': 'Kanalên HRMP Veke',
'xcmWizard.hrmpSuccess': '{{count}} kanal bi Asset Hub re hatin vekirin',
'xcmWizard.hrmpFailed': 'Kanalên HRMP nehatin vekirin',
'xcmWizard.registeringAssets': 'Mal tên tomarkirin...',
'xcmWizard.assetsRegistered': 'Mal Hatin Tomarkirin',
'xcmWizard.assetsBtn': 'Malên Biyanî Tomar Bike',
'xcmWizard.assetsDesc': 'Malên biyanî tomar bikin: USDT, DOT û tokenên din ên cross-chain',
'xcmWizard.assetsSuccess': '{{count}} malên biyanî hatin tomarkirin',
'xcmWizard.assetsFailed': 'Malên biyanî nehatin tomarkirin',
'xcmWizard.testing': 'Veguhastina XCM tê test kirin...',
'xcmWizard.testPassed': 'Testa XCM Serkeftî',
'xcmWizard.testBtn': 'Veguhastina XCM Test Bike',
'xcmWizard.testDesc': 'Ji bo piştrastkirina fonksiyona pirê veguhastina XCM ji Asset Hub test bikin',
'xcmWizard.testSuccess': '{{balance}} wUSDT hat standin',
'xcmWizard.testFailed': 'Veguhastina testê biserneket',
'xcmWizard.notReady': 'Ji kerema xwe girêdana Asset Hub li bendê bin',
'xcmWizard.previous': 'Berê',
'xcmWizard.next': 'Pêş',
'xcmWizard.finish': 'Veavakirinê Temam Bike',
'xcmWizard.complete': 'Veavakirina XCM Temam Bû!',
'xcmWizard.completeDesc': 'Parachain\'a we bi tevahî hat veavakirina û ji bo veguhastinên cross-chain amade ye',
// Batch 11: Permission Editor
'permission.title': 'Edîtorê Destûran',
-94
View File
@@ -630,9 +630,6 @@ export default {
'dex.admin.tokenMinting': 'Token Basımı',
'dex.admin.tokenMintingDesc': 'Test ve likidite sağlama amacıyla sarmalanmış token basın',
'dex.admin.mintToken': '{{symbol}} Bas',
'dex.admin.xcmWizard': 'XCM Yapılandırma Sihirbazı',
'dex.admin.xcmWizardDesc': '6 adımlı parachain kurulumunu tamamlayın: ParaId ayırın, yapılandırma dosyaları oluşturun, parachain kaydedin, HRMP kanallarını açın, yabancı varlıkları kaydedin ve XCM transferlerini test edin.',
'dex.admin.openXcmWizard': 'XCM Yapılandırma Sihirbazını Aç',
'dex.admin.poolManagement': 'Havuz Yönetimi',
'dex.admin.poolManagementDesc': 'PezkuwiChain üzerinde token çiftleri için yeni likidite havuzları oluşturun',
'dex.admin.createNewPool': 'Yeni Havuz Oluştur',
@@ -774,41 +771,6 @@ export default {
'mintUsdt.mintBtn': 'wUSDT Bas',
'mintUsdt.minted': '{{amount}} wUSDT başarıyla basıldı',
// XCMBridgeSetupModal
'xcmBridge.title': 'XCM Köprü Kurulumu',
'xcmBridge.adminOnly': 'Yalnızca Yönetici - XCM Yapılandırma',
'xcmBridge.info': 'Tek tıklamayla Asset Hub USDT → wUSDT köprüsünü yapılandırın. Bu, Westend Asset Hub\'dan PezkuwiChain\'e zincirler arası transferleri etkinleştirir.',
'xcmBridge.currentStatus': 'Mevcut Durum',
'xcmBridge.assetHubConnection': 'Asset Hub Bağlantısı:',
'xcmBridge.connected': 'Bağlı',
'xcmBridge.checking': 'Kontrol Ediliyor...',
'xcmBridge.wusdtAssetExists': 'wUSDT Varlığı Mevcut:',
'xcmBridge.yesId': 'Evet (ID: 1000)',
'xcmBridge.notFound': 'Bulunamadı',
'xcmBridge.xcmConfigured': 'XCM Köprüsü Yapılandırılmış:',
'xcmBridge.configured': 'Yapılandırılmış',
'xcmBridge.notConfigured': 'Yapılandırılmamış',
'xcmBridge.assetHubInfo': 'Asset Hub USDT Bilgisi',
'xcmBridge.configDetails': 'Yapılandırma Ayrıntıları',
'xcmBridge.checkingStatus': 'Köprü durumu kontrol ediliyor...',
'xcmBridge.fetchingInfo': 'Asset Hub USDT bilgisi getiriliyor...',
'xcmBridge.statusComplete': 'Durum kontrolü tamamlandı',
'xcmBridge.configComplete': 'Köprü yapılandırması tamamlandı!',
'xcmBridge.poolComplete': 'Havuz oluşturma tamamlandı!',
'xcmBridge.close': 'Kapat',
'xcmBridge.configureBridge': 'Köprüyü Yapılandır',
'xcmBridge.configuring': 'Yapılandırılıyor...',
'xcmBridge.createPoolOptional': 'Havuz Oluştur (İsteğe Bağlı)',
'xcmBridge.createPool': 'Havuz Oluştur',
'xcmBridge.creatingPool': 'Oluşturuluyor...',
'xcmBridge.wusdtAmount': 'wUSDT Miktarı',
'xcmBridge.hezAmount': 'HEZ Miktarı',
'xcmBridge.createPoolSection': 'wUSDT/HEZ Havuzu Oluştur (İsteğe Bağlı)',
'xcmBridge.sudoWarning': 'XCM köprü yapılandırması sudo erişimi gerektirir',
'xcmBridge.bridgeConfigured': 'XCM köprüsü başarıyla yapılandırıldı',
'xcmBridge.configFailed': 'Yapılandırma Başarısız',
'xcmBridge.poolCreated': 'wUSDT/HEZ havuzu başarıyla oluşturuldu',
'xcmBridge.poolFailed': 'Havuz Oluşturma Başarısız',
// TokenSwap
'tokenSwap.dexComingSoon': 'DEX Yakında',
@@ -3176,62 +3138,6 @@ export default {
'kyc.approval.failedDesc': 'Referans onaylanamadı',
// Batch 11: XCM Wizard
'xcmWizard.title': 'XCM Yapılandırma Sihirbazı',
'xcmWizard.subtitle': 'Parachain kurulumu ve çapraz zincir entegrasyonunu tamamlayın',
'xcmWizard.progress': '{{completed}} / {{total}} adım tamamlandı',
'xcmWizard.walletNotConnected': 'Cüzdan bağlı değil',
'xcmWizard.connectFirst': 'Lütfen önce cüzdanınızı bağlayın',
'xcmWizard.relayChainLabel': 'Relay Chain Seçin',
'xcmWizard.westend': 'Westend (Testnet)',
'xcmWizard.rococo': 'Rococo (Testnet)',
'xcmWizard.polkadot': 'Polkadot (Mainnet)',
'xcmWizard.stepReserve': 'ParaId Ayır',
'xcmWizard.stepArtifacts': 'Zincir Yapıtaşları Oluştur',
'xcmWizard.stepParachain': 'Parachain Kaydet',
'xcmWizard.stepHrmp': 'HRMP Kanalları Aç',
'xcmWizard.stepAssets': 'Yabancı Varlıkları Kaydet',
'xcmWizard.stepTest': 'XCM Transferi Test Et',
'xcmWizard.reserving': 'ParaId ayrılıyor...',
'xcmWizard.reserved': 'ParaId Ayrıldı',
'xcmWizard.reserveBtn': 'ParaId Ayır',
'xcmWizard.reserveSuccess': '{{chain}} üzerinde ParaId {{paraId}} başarıyla ayrıldı',
'xcmWizard.reserveFailed': 'ParaId ayrılamadı',
'xcmWizard.generating': 'Yapıtaşları oluşturuluyor...',
'xcmWizard.generated': 'Yapıtaşları Oluşturuldu',
'xcmWizard.generateBtn': 'Zincir Yapıtaşları Oluştur',
'xcmWizard.artifactsReady': 'Yapıtaşları oluşturuldu. Kayıt için dosyaları indirin.',
'xcmWizard.artifactsFailed': 'Zincir yapıtaşları oluşturulamadı',
'xcmWizard.genesisLabel': 'Genesis Durumu Yükle',
'xcmWizard.wasmLabel': 'Runtime WASM Yükle',
'xcmWizard.missingFiles': 'Lütfen hem genesis hem de WASM dosyalarını yükleyin',
'xcmWizard.registering': 'Parachain kaydediliyor...',
'xcmWizard.registered': 'Parachain Kaydedildi',
'xcmWizard.registerBtn': 'Parachain Kaydet',
'xcmWizard.registerSuccess': 'ParaId {{paraId}} {{chain}} üzerinde kaydedildi',
'xcmWizard.registerFailed': 'Parachain kaydedilemedi',
'xcmWizard.openingHrmp': 'HRMP kanalları açılıyor...',
'xcmWizard.channelsOpened': 'Kanallar Açıldı',
'xcmWizard.hrmpBtn': 'HRMP Kanalları Aç',
'xcmWizard.hrmpSuccess': 'Asset Hub ile {{count}} kanal açıldı',
'xcmWizard.hrmpFailed': 'HRMP kanalları açılamadı',
'xcmWizard.registeringAssets': 'Varlıklar kaydediliyor...',
'xcmWizard.assetsRegistered': 'Varlıklar Kaydedildi',
'xcmWizard.assetsBtn': 'Yabancı Varlıkları Kaydet',
'xcmWizard.assetsDesc': 'Yabancı varlıkları kaydedin: USDT, DOT ve diğer çapraz zincir token\'ları',
'xcmWizard.assetsSuccess': '{{count}} yabancı varlık kaydedildi',
'xcmWizard.assetsFailed': 'Yabancı varlıklar kaydedilemedi',
'xcmWizard.testing': 'XCM Transferi test ediliyor...',
'xcmWizard.testPassed': 'XCM Testi Başarılı',
'xcmWizard.testBtn': 'XCM Transferi Test Et',
'xcmWizard.testDesc': 'Köprü işlevselliğini doğrulamak için Asset Hub\'dan XCM transferi test edin',
'xcmWizard.testSuccess': '{{balance}} wUSDT alındı',
'xcmWizard.testFailed': 'Test transferi başarısız oldu',
'xcmWizard.notReady': 'Lütfen Asset Hub bağlantısını bekleyin',
'xcmWizard.previous': 'Önceki',
'xcmWizard.next': 'Sonraki',
'xcmWizard.finish': 'Yapılandırmayı Tamamla',
'xcmWizard.complete': 'XCM Yapılandırması Tamamlandı!',
'xcmWizard.completeDesc': 'Parachain\'iniz tamamen yapılandırıldı ve çapraz zincir transferlerine hazır',
// Batch 11: Permission Editor
'permission.title': 'Yetki Düzenleyici',