mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-10-20 18:56:16 +00:00
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:
1 parent
b778493eaa
commit
ac730481d9
12 files changed
-3041
No files matched your search
@@ -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
|
||||
|
||||
@@ -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';
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
@@ -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': 'محرر الصلاحيات',
|
||||
|
||||
@@ -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': 'دەستکاریکاری مۆڵەتەکان',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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': 'ویرایشگر مجوزها',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in new issue
Block a user