feat(web): add network subpages and subdomains listing page

- Add /subdomains page listing all 20 PezkuwiChain subdomains
- Add Back to Home button to Subdomains page
- Create NetworkPage reusable component for network details
- Add 7 network subpages: /mainnet, /staging, /testnet, /beta, /alfa, /development, /local
- Update ChainSpecs network cards to navigate to network subpages
- Add i18n translations for chainSpecs section in en.ts
- Add SDK docs with rebranding support (rebrand-rustdoc.cjs)
- Add generate-docs-structure.cjs for automatic docs generation
- Update shared libs: endpoints, polkadot, wallet, xcm-bridge
- Add new token logos: TYR, ZGR, pezkuwi_icon
- Add new pages: Explorer, Docs, Wallet, Api, Faucet, Developers, Grants, Wiki, Forum, Telemetry
This commit is contained in:
2025-12-11 00:33:47 +03:00
parent 2c6c4f5606
commit 11678fe7cd
976 changed files with 60601 additions and 168 deletions
+44 -8
View File
@@ -42,13 +42,31 @@ export const NETWORK_ENDPOINTS: Record<string, NetworkConfig> = {
description: 'Staging environment for pre-production testing',
},
// Development Testnet
TESTNET: {
name: 'Pezkuwi Testnet',
endpoint: 'https://testnet.pezkuwichain.io',
wsEndpoint: 'wss://testnet.pezkuwichain.io',
// Alfa Testnet
ALFA: {
name: 'Pezkuwi Alfa Testnet',
endpoint: 'https://alfa.pezkuwichain.io',
wsEndpoint: 'wss://alfa.pezkuwichain.io',
type: 'development',
description: 'Development testnet for feature testing',
description: 'Alfa testnet for early feature testing',
},
// Development Environment
DEV: {
name: 'Pezkuwi Development',
endpoint: 'https://dev.pezkuwichain.io',
wsEndpoint: 'wss://dev.pezkuwichain.io',
type: 'development',
description: 'Development environment for feature testing',
},
// Local Development
LOCAL: {
name: 'Local Development',
endpoint: 'http://127.0.0.1:9944',
wsEndpoint: 'ws://127.0.0.1:9944',
type: 'development',
description: 'Local development node',
},
};
@@ -57,8 +75,8 @@ export const NETWORK_ENDPOINTS: Record<string, NetworkConfig> = {
*/
export const DEFAULT_NETWORK =
process.env.NODE_ENV === 'production'
? NETWORK_ENDPOINTS.BETA // Currently using Beta for production
: NETWORK_ENDPOINTS.TESTNET;
? NETWORK_ENDPOINTS.BETA // Currently using Beta for production
: NETWORK_ENDPOINTS.DEV;
/**
* Port Configuration
@@ -98,6 +116,23 @@ export function getAllNetworks(): NetworkConfig[] {
return Object.values(NETWORK_ENDPOINTS);
}
/**
* Get the current network configuration based on the VITE_NETWORK environment variable.
* This serves as the single source of truth for the application's network configuration.
* @returns {NetworkConfig} The active network configuration.
*/
export const getCurrentNetworkConfig = (): NetworkConfig => {
const networkName = (import.meta.env.VITE_NETWORK || 'local').toUpperCase();
const validNetworkKeys = Object.keys(NETWORK_ENDPOINTS);
if (validNetworkKeys.includes(networkName)) {
return NETWORK_ENDPOINTS[networkName as keyof typeof NETWORK_ENDPOINTS];
}
// Fallback to a default or local configuration if the name is invalid
return NETWORK_ENDPOINTS.LOCAL;
};
/**
* Check if endpoint is available
*/
@@ -109,3 +144,4 @@ export async function checkEndpoint(endpoint: string): Promise<boolean> {
return false;
}
}
export const NETWORKS = NETWORK_ENDPOINTS;
+4 -28
View File
@@ -3,46 +3,22 @@
*/
import type { BlockchainNetwork } from '../types/blockchain';
import { getCurrentNetworkConfig } from './endpoints';
/**
* Pezkuwi blockchain network configuration
* Uses BETA endpoint from centralized endpoints.ts (source of truth)
*/
export const PEZKUWI_NETWORK: BlockchainNetwork = {
name: 'Pezkuwi',
endpoint: 'wss://beta-rpc.pezkuwi.art',
endpoint: getCurrentNetworkConfig().wsEndpoint,
chainId: 'pezkuwi',
};
/**
* Common blockchain endpoints
*/
export const BLOCKCHAIN_ENDPOINTS = {
mainnet: 'wss://mainnet.pezkuwichain.io',
testnet: 'wss://ws.pezkuwichain.io',
local: 'ws://127.0.0.1:9944',
} as const;
/**
* Get the appropriate WebSocket endpoint based on environment
*/
function getWebSocketEndpoint(): string {
const network = import.meta.env.VITE_NETWORK || 'local';
switch (network) {
case 'mainnet':
return import.meta.env.VITE_WS_ENDPOINT_MAINNET || BLOCKCHAIN_ENDPOINTS.mainnet;
case 'testnet':
return import.meta.env.VITE_WS_ENDPOINT_TESTNET || BLOCKCHAIN_ENDPOINTS.testnet;
case 'local':
default:
return import.meta.env.VITE_WS_ENDPOINT_LOCAL || BLOCKCHAIN_ENDPOINTS.local;
}
}
/**
* Default endpoint (reads from environment variables)
*/
export const DEFAULT_ENDPOINT = getWebSocketEndpoint();
export const DEFAULT_ENDPOINT = getCurrentNetworkConfig().wsEndpoint;
/**
* Get block explorer URL for a transaction
Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

After

Width:  |  Height:  |  Size: 289 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 469 KiB

After

Width:  |  Height:  |  Size: 586 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 719 KiB

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

+3 -14
View File
@@ -4,17 +4,7 @@
// This file configures wallet connectivity for Substrate-based chains
import type { InjectedAccountWithMeta } from '@polkadot/extension-inject/types';
// ========================================
// NETWORK ENDPOINTS
// ========================================
export const NETWORK_ENDPOINTS = {
local: import.meta.env.VITE_DEVELOPMENT_WS || 'ws://127.0.0.1:9944',
testnet: import.meta.env.VITE_TESTNET_WS || 'wss://testnet.pezkuwichain.io',
mainnet: import.meta.env.VITE_MAINNET_WS || 'wss://mainnet.pezkuwichain.io',
staging: import.meta.env.VITE_STAGING_WS || 'wss://staging.pezkuwichain.io',
beta: import.meta.env.VITE_BETA_WS || 'wss://beta.pezkuwichain.io',
};
import { getCurrentNetworkConfig } from '../blockchain/endpoints';
// ========================================
// CHAIN CONFIGURATION
@@ -38,7 +28,7 @@ export const CHAIN_CONFIG = {
export const ASSET_IDS = {
WHEZ: parseInt(import.meta.env.VITE_ASSET_WHEZ || '0'), // Wrapped HEZ
PEZ: parseInt(import.meta.env.VITE_ASSET_PEZ || '1'), // PEZ utility token
WUSDT: parseInt(import.meta.env.VITE_ASSET_WUSDT || '1000'), // Wrapped USDT (6 decimals, matches SDK)
WUSDT: parseInt(import.meta.env.VITE_ASSET_WUSDT || '1000'), // Wrapped USDT (6 decimals, Asset ID 1000)
USDT: parseInt(import.meta.env.VITE_ASSET_USDT || '3'),
BTC: parseInt(import.meta.env.VITE_ASSET_BTC || '4'),
ETH: parseInt(import.meta.env.VITE_ASSET_ETH || '5'),
@@ -146,8 +136,7 @@ export const getAssetSymbol = (assetId: number): string => {
* @returns WebSocket endpoint URL
*/
export const getCurrentEndpoint = (): string => {
const network = import.meta.env.VITE_NETWORK || 'local';
return NETWORK_ENDPOINTS[network as keyof typeof NETWORK_ENDPOINTS] || NETWORK_ENDPOINTS.local;
return getCurrentNetworkConfig().wsEndpoint;
};
// ========================================
+74 -2
View File
@@ -3,17 +3,40 @@
*
* 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 '@polkadot/api';
import type { Signer } from '@polkadot/api/types';
// Westend Asset Hub endpoint
// 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
export const WUSDT_ASSET_ID = 1000; // wUSDT on PezkuwiChain (was 2, now 1000)
export const ASSET_HUB_PARACHAIN_ID = 1000;
/**
@@ -42,6 +65,12 @@ export interface AssetHubUsdtInfo {
* 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 });
@@ -60,6 +89,17 @@ export async function connectToAssetHub(): Promise<ApiPromise> {
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;
@@ -106,6 +146,19 @@ export async function checkBridgeStatus(
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 {
@@ -155,6 +208,25 @@ export async function configureXcmBridge(
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...');
+506
View File
@@ -0,0 +1,506 @@
/**
* XCM Configuration Wizard Backend Functions
*
* Handles parachain registration, HRMP channels, foreign asset registration,
* and XCM transfer testing for PezkuwiChain.
*/
import type { ApiPromise } from '@polkadot/api';
import type { InjectedAccountWithMeta } from '@polkadot/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.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.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.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.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',
};
}
}
// ========================================
// 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];
}