Skip to content

Conversation

@developerfred
Copy link
Owner

@developerfred developerfred commented Dec 23, 2025

User description

This PR adds a comprehensive Asset Hub operations example to the PAPI Simulator.

Changes

  • Created AssetHubExample.ts with Asset Hub specific operations
  • Demonstrates foreign asset queries and balances
  • Shows asset transfers, teleport assets, and reserve transfers
  • Includes asset metadata and approval queries
  • Advanced level example covering assets, XCM, transfers, and parachains

Features Demonstrated

  • Foreign Assets: Query and interact with foreign assets on Asset Hub
  • XCM Operations: Teleport assets and reserve transfers between chains
  • Asset Metadata: Query asset information and approvals
  • Cross-chain Transfers: Operations that work across parachains

This example helps developers understand how to work with Polkadot's Asset Hub for cross-chain asset operations.

Closes #50


PR Type

Enhancement, Tests


Description

  • Add Asset Hub Operations example demonstrating foreign assets and XCM operations

  • Implement comprehensive error handling with retry logic in code runner

  • Add timeout management and error categorization for execution failures

  • Register new example in the example registry


Diagram Walkthrough

flowchart LR
  A["AssetHubExample.ts"] -->|"demonstrates"| B["Asset Hub Operations"]
  B -->|"includes"| C["Foreign Assets"]
  B -->|"includes"| D["XCM Transfers"]
  B -->|"includes"| E["Asset Metadata"]
  F["useCodeRunner.ts"] -->|"adds"| G["Error Handling"]
  G -->|"includes"| H["Retry Logic"]
  G -->|"includes"| I["Timeout Management"]
  G -->|"includes"| J["Error Categorization"]
  K["index.ts"] -->|"registers"| A
Loading

File Walkthrough

Relevant files
Enhancement
AssetHubExample.ts
Asset Hub operations example with XCM demonstrations         

src/lib/examples/AssetHubExample.ts

  • Created new example class extending ExampleFactory for Asset Hub
    operations
  • Demonstrates foreign asset queries, balances, and transfers
  • Shows XCM operations including teleport assets and reserve transfers
  • Includes asset metadata and approval queries with error handling
  • Marked as advanced level with categories for assets, xcm, transfers,
    and parachains
+168/-0 
Configuration changes
index.ts
Register Asset Hub example in registry                                     

src/lib/examples/index.ts

  • Import new AssetHubExample class
  • Register AssetHubExample instance in the example registry
+4/-0     
Error handling
useCodeRunner.ts
Implement retry logic and error categorization                     

src/lib/hooks/useCodeRunner.ts

  • Add CodeExecutionError custom error class with error type
    categorization (network, timeout, simulation, unknown)
  • Implement retry logic with exponential backoff (up to maxRetries
    attempts)
  • Add timeout management with configurable timeout duration (default 30
    seconds)
  • Enhance error messages with specific guidance based on error type
  • Add progress tracking during retries and improved console output
    messages
  • Extract timeout and maxRetries options from hook parameters
+120/-38

- Create AssetHubExample.ts demonstrating Asset Hub operations
- Shows foreign asset queries, asset transfers, teleport assets, reserve transfers
- Includes asset metadata and approval queries
- Advanced level example with assets, xcm, transfers, and parachains categories
- Registered the example in the example registry
@vercel
Copy link

vercel bot commented Dec 23, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
papi-simulator Building Building Preview, Comment Dec 23, 2025 6:06pm

@qodo-code-review
Copy link

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🟡
🎫 #50
🟢 Create examples for Polkadot Asset Hub operations.
Include foreign asset transfers examples.
Include teleport assets (XCM) examples.
Include examples interacting with Assets-related pallets on system parachains (e.g.,
querying assets, metadata, approvals, balances).
Confirm the example runs end-to-end against intended Asset Hub networks/descriptors
(queries/tx builders match the runtime metadata for targeted chains).
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Missing cleanup/finally: The new retry/timeout flow no longer reliably resets isRunning/progress after completion
or failure and does not clear the timeout timer, risking stuck UI state and lingering
timers.

Referred Code
async (example: Example, network: Network) => {
	setIsRunning(true);
	setProgress(10);
	options.onRunStart?.();

	setOutputs([
		{
			type: "log",
			content: `🚀 Starting execution on ${network.name}...`,
			timestamp: Date.now(),
		},
	]);

	let attempt = 0;
	let lastError: Error | null = null;

	while (attempt <= maxRetries) {
		try {
			setProgress(20 + (attempt * 10));

			if (attempt > 0) {


 ... (clipped 96 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status:
Exposes raw errors: User-facing output messages embed raw lastError.message (and may include internal details)
directly into UI-visible console output instead of restricting details to internal logs.

Referred Code
		const categorizedError = new CodeExecutionError(errorMessage, errorType, lastError);

		// If this was the last attempt, report the error
		if (attempt > maxRetries) {
			setOutputs(prev => [...prev, {
				type: "error",
				content: `❌ ${categorizedError.message}${errorType === 'network' ? ' (Check network connection)' : ''}${errorType === 'timeout' ? ' (Try simplifying the code)' : ''}`,
				timestamp: Date.now(),
			}]);

			options.onRunError?.(categorizedError);
		}

		// Wait before retry (exponential backoff)
		if (attempt <= maxRetries) {
			const delay = Math.min(1000 * Math.pow(2, attempt - 1), 5000);
			await new Promise(resolve => setTimeout(resolve, delay));
		}
	}
}



 ... (clipped 6 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Unstructured console logs: The example emits multiple free-form console.log/console.error strings (including dumping
firstAsset.value) rather than structured logs, making them difficult to parse/monitor and
potentially leaking detailed internal data.

Referred Code
console.log("🚀 Starting Asset Hub operations demonstration...");

// 1. Query foreign assets
console.log("\\n🔍 Querying foreign assets:");
const foreignAssets = await typedApi.query.ForeignAssets.Asset.getEntries();
console.log("Found", foreignAssets.length, "foreign assets");

if (foreignAssets.length > 0) {
  const firstAsset = foreignAssets[0];
  console.log("First asset details:", {
    assetId: firstAsset.key?.args?.[0],
    details: firstAsset.value
  });
}

// 2. Query asset balances
console.log("\\n💰 Querying asset balances:");
const aliceAddress = "${this.getTestAccount("alice")}";

// Native token balance (DOT/KSM)
const nativeBalance = await typedApi.query.System.Account.getValue(aliceAddress);


 ... (clipped 110 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Unvalidated options: timeoutMs and maxRetries are consumed without validation (e.g., negative/zero/very large
values), which can cause unexpected behavior or denial-of-service style runaway
execution/retry behavior.

Referred Code
const {
	timeoutMs = 30000, // 30 seconds default
	maxRetries = 2,
} = options;

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@developerfred developerfred merged commit a5f0002 into main Dec 23, 2025
2 of 3 checks passed
@qodo-code-review
Copy link

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Restore finally block for state cleanup

Restore the finally block to wrap the retry logic, ensuring the isRunning state
is always reset to false after execution, which prevents the UI from getting
stuck.

src/lib/hooks/useCodeRunner.ts [159-171]

 			}
 
 			// If we get here, all retries failed
 			setOutputs(prev => [...prev, {
 				type: "error",
 				content: `❌ All ${maxRetries + 1} attempts failed. Last error: ${lastError?.message || 'Unknown error'}`,
 				timestamp: Date.now(),
 			}]);
 
 			options.onRunError?.(lastError || new Error('All retry attempts failed'));
-		},
-		[options, timeoutMs, maxRetries],
-	);
+		} finally {
+			setIsRunning(false);
+			setProgress(100);
+			setTimeout(() => setProgress(0), 500);
+		}
+	},
+	[options, timeoutMs, maxRetries],
+);

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 9

__

Why: This suggestion correctly identifies a critical bug where the isRunning state is never reset, which would freeze the UI. The proposed finally block is the correct and robust way to ensure state cleanup on both success and failure paths.

High
Fix incorrect MultiAddress construction

Correct the construction of the MultiAddress object for the target parameter by
changing MultiAddress.Id(...) to { Id: "..." } to prevent a runtime error.

src/lib/examples/AssetHubExample.ts [58-62]

 const transferTx = typedApi.tx.ForeignAssets.transfer({
   id: { parents: 0, interior: { X1: { PalletInstance: 50 } } }, // Example asset ID
-  target: MultiAddress.Id("${this.getTestAccount("bob")}"),
+  target: { Id: "${this.getTestAccount("bob")}" },
   amount: 1000000000000n // 1000 tokens (adjust for decimals)
 });
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: This suggestion correctly identifies a runtime error in the generated example code due to incorrect object construction for MultiAddress. Fixing this is crucial for the example to be valid and executable.

Medium
Clear timeout to avoid leaks

Clear the setTimeout timer after the Promise.race completes to prevent potential
memory leaks and unhandled promise rejections if the main operation finishes
before the timeout.

src/lib/hooks/useCodeRunner.ts [82-95]

+// Timeout promise with clearable timer
+let timeoutId: ReturnType<typeof setTimeout>;
 const timeoutPromise = new Promise<never>((_, reject) => {
-  setTimeout(() => {
+  timeoutId = setTimeout(() => {
     reject(new CodeExecutionError(
       `Execution timed out after ${timeoutMs}ms`,
       'timeout'
     ));
   }, timeoutMs);
 });
 
 // Race between simulation and timeout
 const simulatedOutputs = await Promise.race([
   simulateCodeExecution(example, network),
   timeoutPromise
 ]);
 
+// Clear timeout to avoid unhandled rejection
+clearTimeout(timeoutId);
+
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: This suggestion correctly points out a potential memory leak and unhandled promise rejection by not clearing the timeout. While this is a good practice for robustness, the current implementation's impact is minor as the timeout only logs an error.

Medium
  • More

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Asset Hub Examples

2 participants