Skip to content

Commit 8c6526f

Browse files
Merge pull request #35 from developerfred/chore/xcm-paseo
feat(xcm): enable xcm on paseo testnet
2 parents a9ff93b + 8ee4ad1 commit 8c6526f

File tree

11 files changed

+2515
-1430
lines changed

11 files changed

+2515
-1430
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "papi-simulator",
33
"version": "0.4.2",
4-
"author": "codingsh <codinsh@pm.me>",
4+
"author": "codingsh <codingsh@pm.me>",
55
"private": true,
66
"scripts": {
77
"dev": "next dev --turbopack",

src/components/blockchain/BlockchainDashboard.tsx

Lines changed: 36 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import {
1818
import dynamic from "next/dynamic";
1919
import { networkManager, type Network, NetworkSchema } from "./dynamic-blockchain-config";
2020

21-
2221
const WalletAccountSchema = z.object({
2322
address: z.string(),
2423
meta: z.object({
@@ -61,7 +60,6 @@ const BlockExplorer = createDynamicComponent(() => import("./components/BlockExp
6160
const TransactionMonitor = createDynamicComponent(() => import("./components/TransactionMonitor"), "Transaction Monitor");
6261
const TransactionBuilder = createDynamicComponent(() => import("./components/TransactionBuilder"), "Transaction Builder");
6362

64-
// Enhanced Polkadot API hook
6563
const usePolkadotApi = (network: Network, isWalletConnected: boolean): ChainConnectionState => {
6664
const [state, setState] = useState<ChainConnectionState>({
6765
api: null,
@@ -92,7 +90,6 @@ const usePolkadotApi = (network: Network, isWalletConnected: boolean): ChainConn
9290
const connectionKey = `${network.rpcUrl}-${isWalletConnected}`;
9391
if (connectionAttemptRef.current === connectionKey) return;
9492

95-
// Abort previous connection
9693
if (abortControllerRef.current) {
9794
abortControllerRef.current.abort();
9895
}
@@ -111,18 +108,24 @@ const usePolkadotApi = (network: Network, isWalletConnected: boolean): ChainConn
111108
setState(prev => ({ ...prev, status: "connecting", error: null }));
112109

113110
provider = new WsProvider(network.rpcUrl, 1000);
114-
115-
provider.on('disconnected', () => {
111+
112+
const handleDisconnect = () => {
116113
if (isMounted && mountedRef.current) {
117114
setState(prev => ({ ...prev, status: "disconnected" }));
118115
}
119-
});
116+
};
120117

121-
provider.on('error', (error) => {
118+
const handleError = (error: any) => {
122119
if (isMounted && mountedRef.current) {
123120
setState(prev => ({ ...prev, status: "error", error: error.message }));
124121
}
125-
});
122+
};
123+
124+
125+
if (typeof provider.on === 'function') {
126+
provider.on('disconnected', handleDisconnect);
127+
provider.on('error', handleError);
128+
}
126129

127130
apiInstance = await Promise.race([
128131
ApiPromise.create({
@@ -163,11 +166,16 @@ const usePolkadotApi = (network: Network, isWalletConnected: boolean): ChainConn
163166

164167
const cleanup = async () => {
165168
try {
169+
166170
if (provider) {
167-
provider.removeAllListeners();
168-
await provider.disconnect();
171+
if (typeof provider.removeAllListeners === 'function') {
172+
provider.removeAllListeners();
173+
}
174+
if (typeof provider.disconnect === 'function') {
175+
await provider.disconnect();
176+
}
169177
}
170-
if (apiInstance) {
178+
if (apiInstance && typeof apiInstance.disconnect === 'function') {
171179
await apiInstance.disconnect();
172180
}
173181
} catch (error) {
@@ -182,7 +190,6 @@ const usePolkadotApi = (network: Network, isWalletConnected: boolean): ChainConn
182190
return state;
183191
};
184192

185-
// Utility functions
186193
const getAccountDisplayName = (account: WalletAccount | null): string =>
187194
account?.meta?.name ||
188195
account?.name ||
@@ -212,40 +219,27 @@ const getNetworkTypeIcon = (type: Network["type"], className = "w-4 h-4") => {
212219
return icons[type] || <Globe className={className} aria-hidden="true" />;
213220
};
214221

215-
// UI Components
216222
const StatusIndicator = memo<{ status: ConnectionStatus; showLabel?: boolean }>(({ status, showLabel = true }) => {
217-
const colors = {
218-
connected: "bg-green-500",
219-
connecting: "bg-yellow-500 animate-pulse",
220-
disconnected: "bg-gray-400",
221-
error: "bg-red-500",
222-
};
223-
224-
const labels = {
225-
connected: "Connected",
226-
connecting: "Connecting",
227-
disconnected: "Disconnected",
228-
error: "Error",
223+
const config = {
224+
connected: { color: "bg-green-500", label: "Connected", icon: <Wifi className="w-3 h-3" /> },
225+
connecting: { color: "bg-yellow-500 animate-pulse", label: "Connecting", icon: <div className="w-3 h-3 animate-spin rounded-full border border-gray-300 border-t-white" /> },
226+
disconnected: { color: "bg-gray-400", label: "Disconnected", icon: <WifiOff className="w-3 h-3" /> },
227+
error: { color: "bg-red-500", label: "Error", icon: <AlertCircle className="w-3 h-3" /> },
229228
};
230229

231-
const icons = {
232-
connected: <Wifi className="w-3 h-3" aria-hidden="true" />,
233-
connecting: <div className="w-3 h-3 animate-spin rounded-full border border-gray-300 border-t-white" />,
234-
disconnected: <WifiOff className="w-3 h-3" aria-hidden="true" />,
235-
error: <AlertCircle className="w-3 h-3" aria-hidden="true" />,
236-
};
230+
const { color, label, icon } = config[status];
237231

238232
return (
239-
<div className="flex items-center space-x-2" role="status" aria-label={`${labels[status]} status`}>
240-
<div className={`w-2 h-2 rounded-full ${colors[status]} relative overflow-hidden`}>
233+
<div className="flex items-center space-x-2" role="status" aria-label={`${label} status`}>
234+
<div className={`w-2 h-2 rounded-full ${color} relative overflow-hidden`}>
241235
{status === "connecting" && (
242236
<div className="absolute inset-0 bg-yellow-500 animate-ping" />
243237
)}
244238
</div>
245239
{showLabel && (
246240
<div className="flex items-center space-x-1">
247-
<span className="text-xs text-theme-secondary">{labels[status]}</span>
248-
<span className="text-theme-tertiary">{icons[status]}</span>
241+
<span className="text-xs text-theme-secondary">{label}</span>
242+
<span className="text-theme-tertiary">{icon}</span>
249243
</div>
250244
)}
251245
</div>
@@ -315,25 +309,20 @@ const NetworkSelector = memo<{
315309

316310
const networks = useMemo(() => {
317311
let filtered = networkManager.getAllNetworks();
318-
319312
if (selectedFilter !== "all") {
320313
filtered = networkManager.getNetworksByType(selectedFilter);
321314
}
322-
323315
if (searchQuery) {
324316
filtered = networkManager.searchNetworks(searchQuery);
325317
}
326-
327318
return filtered;
328319
}, [searchQuery, selectedFilter]);
329320

330321
const networkGroups = useMemo(() => {
331322
if (selectedFilter !== "all") {
332323
return { [selectedFilter]: networks };
333324
}
334-
335325
const groups = networkManager.getNetworkGroups();
336-
337326
if (searchQuery) {
338327
Object.keys(groups).forEach(key => {
339328
groups[key] = groups[key].filter(network =>
@@ -344,7 +333,6 @@ const NetworkSelector = memo<{
344333
}
345334
});
346335
}
347-
348336
return groups;
349337
}, [networks, selectedFilter, searchQuery]);
350338

@@ -629,12 +617,13 @@ const ConnectionStatusDisplay = memo<{
629617
if (layoutMode === "transaction-fullscreen") return null;
630618

631619
const getStatusColor = (status: string) => {
632-
switch (status) {
633-
case "connected": return "border-green-200/70 dark:border-green-600/70 bg-green-50/80 dark:bg-green-900/40";
634-
case "connecting": return "border-yellow-200/70 dark:border-yellow-600/70 bg-yellow-50/80 dark:bg-yellow-900/40";
635-
case "error": return "border-red-200/70 dark:border-red-600/70 bg-red-50/80 dark:bg-red-900/40";
636-
default: return "border-theme bg-theme-surface";
637-
}
620+
const colors = {
621+
connected: "border-green-200/70 dark:border-green-600/70 bg-green-50/80 dark:bg-green-900/40",
622+
connecting: "border-yellow-200/70 dark:border-yellow-600/70 bg-yellow-50/80 dark:bg-yellow-900/40",
623+
error: "border-red-200/70 dark:border-red-600/70 bg-red-50/80 dark:bg-red-900/40",
624+
default: "border-theme bg-theme-surface",
625+
};
626+
return colors[status] || colors.default;
638627
};
639628

640629
return (
@@ -889,12 +878,6 @@ const KeyboardShortcutsHelp = memo<{ layoutMode: LayoutMode; selectedNetwork: Ne
889878
Esc
890879
</kbd>
891880
</div>
892-
<div className="flex items-center justify-between">
893-
<span className="text-theme-secondary">Search Networks:</span>
894-
<kbd className="bg-theme-surface-variant px-2 py-1 rounded border text-theme-primary font-mono">
895-
{modifierKey}+K
896-
</kbd>
897-
</div>
898881
</div>
899882
<button
900883
onClick={() => setIsVisible(false)}

src/components/blockchain/EventMonitor.tsx

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import Badge, { type BadgeVariant } from "@/components/ui/Badge";
88
import { Button } from "@/components/ui";
99
import { Activity, Pause, Play, Trash2, Eye, EyeOff, Filter, AlertCircle } from "lucide-react";
1010
import type { ApiPromise } from "@polkadot/api";
11-
11+
import { buildSubscanUrl } from "@/lib/utils/explorer";
1212

1313
interface ChainEvent {
1414
id: string;
@@ -39,28 +39,7 @@ interface EventMonitorProps {
3939
}
4040

4141

42-
const buildSubscanUrl = (network: Network, type: 'block' | 'extrinsic' | 'account', identifier: string | number): string => {
43-
const baseUrl = network.explorer?.replace(/\/$/, '') || '';
4442

45-
46-
if (!baseUrl || baseUrl === 'undefined' || !baseUrl.includes('subscan.io')) {
47-
console.warn('Invalid explorer URL:', network.explorer);
48-
const networkName = network.name?.toLowerCase() || 'polkadot';
49-
const fallbackUrl = `https://${networkName}.subscan.io`;
50-
return `${fallbackUrl}/${type}/${identifier}`;
51-
}
52-
53-
switch (type) {
54-
case 'block':
55-
return `${baseUrl}/block/${identifier}`;
56-
case 'extrinsic':
57-
return `${baseUrl}/extrinsic/${identifier}`;
58-
case 'account':
59-
return `${baseUrl}/account/${identifier}`;
60-
default:
61-
return baseUrl;
62-
}
63-
};
6443

6544

6645
const useEventMonitor = (api: ApiPromise, limit: number) => {

0 commit comments

Comments
 (0)