Complete Tutorial: Building Your First React Component on Paseo Network with PAPI Simulator
@codingsh

@codingsh @codingsh

About: @codingsh I Papi Simulator

Joined:
Oct 26, 2019

Complete Tutorial: Building Your First React Component on Paseo Network with PAPI Simulator

Publish Date: Jun 27
0 0

Image description

Target Audience: Developers with basic React knowledge but zero blockchain experience

Duration: 45-60 minutes

Prerequisites: Basic JavaScript/React familiarity


Table of Contents

  1. Understanding the Blockchain Basics
  2. Getting Started with PAPI Simulator
  3. Building Your First Component: Account Balance Checker
  4. Adding Interactive Features
  5. Understanding What's Happening
  6. Next Steps

Understanding the Blockchain Basics

What is Blockchain? (For Complete Beginners)

Think of blockchain as a digital ledger (like a bank statement) that:

  • Records all transactions transparently
  • Cannot be altered once written
  • Is distributed across many computers
  • Requires no central authority (like a bank)

What is Polkadot?

Polkadot is a network of blockchains that can communicate with each other. Imagine it as a "blockchain internet" where different specialized chains can work together.

What is Paseo Network?

Paseo is a test network (testnet) for Polkadot. It's like a playground where developers can:

  • Test applications safely
  • Use fake tokens (no real money)
  • Learn without financial risk

Key Concepts You'll Use:

  • Account: Like a digital wallet with a unique address
  • Balance: Amount of tokens in an account
  • Transaction: Transfer of tokens between accounts
  • Block: Group of transactions recorded together

Getting Started with PAPI Simulator

What is PAPI Simulator?

PAPI Simulator is an online development environment where you can:

  • Write blockchain code without setup
  • Test on real testnets instantly
  • See results in real-time
  • Learn through interactive examples

Step 1: Access the Simulator

  1. Open your browser and go to: https://papi-simulator.aipop.fun
  2. You'll see the main interface with:
    • Code Editor (left side)
    • Network Selector (top)
    • Examples Dropdown (top)
    • Console Output (bottom)

Step 2: Select Paseo Network

Let me search for more specific information about the PAPI Simulator interface and Paseo network.Based on the documentation provided and my understanding of the PAPI Simulator, let me continue with the tutorial:

  1. In the top-right corner, you'll see a network dropdown
  2. Select "Paseo" from the list
  3. The interface will show you're now connected to the Paseo testnet

Step 3: Explore a Basic Example

  1. Click the "Examples" dropdown in the top menu
  2. Select "Account Balance Checker"
  3. Click "Run Code" to see it in action

You'll see:

  • Code that connects to Paseo network
  • A query for an account balance
  • Results displayed in the console below

Building Your First Component: Account Balance Checker

Now we'll build a React component that checks account balances on the Paseo network.

Step 1: Understanding the Basic Structure

// This is what we're building - a React component that:
// 1. Connects to Paseo network
// 2. Queries account balances
// 3. Displays results in a nice interface

import React, { useState, useEffect } from 'react';
import { createClient } from "polkadot-api";
import { paseo } from "@polkadot-api/descriptors";
import { getWsProvider } from "polkadot-api/ws-provider/web";
import { withPolkadotSdkCompat } from "polkadot-api/polkadot-sdk-compat";
Enter fullscreen mode Exit fullscreen mode

What each import does:

  • React - For building the user interface
  • createClient - Creates connection to blockchain
  • paseo - Type definitions for Paseo network
  • getWsProvider - WebSocket connection provider
  • withPolkadotSdkCompat - Compatibility layer

Step 2: Create the Component Structure

Copy this code into the PAPI Simulator:

// Account Balance Checker Component for Paseo Network
import React, { useState, useEffect } from 'react';
import { createClient } from "polkadot-api";
import { paseo } from "@polkadot-api/descriptors";
import { getWsProvider } from "polkadot-api/ws-provider/web";
import { withPolkadotSdkCompat } from "polkadot-api/polkadot-sdk-compat";

export default function AccountBalanceChecker() {
  // State variables - think of these as the component's memory
  const [address, setAddress] = useState("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"); // Alice's test address
  const [balance, setBalance] = useState(null);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState("");
  const [client, setClient] = useState(null);
  const [api, setApi] = useState(null);

  // Network information for Paseo
  const networkInfo = {
    name: "Paseo",
    tokenSymbol: "PAS",
    tokenDecimals: 10,
    endpoint: "wss://rpc.ibp.network/paseo",
    explorer: "https://paseo.subscan.io"
  };

  // Connect to Paseo network when component loads
  useEffect(() => {
    const initConnection = async () => {
      try {
        console.log("🔌 Connecting to Paseo network...");

        // Create WebSocket connection to Paseo
        const provider = getWsProvider(networkInfo.endpoint);

        // Create client with compatibility wrapper
        const newClient = createClient(
          withPolkadotSdkCompat(provider)
        );

        // Get typed API for Paseo
        const unsafeApi = newClient.getUnsafeApi();

        setClient(newClient);
        setApi(unsafeApi);

        console.log("✅ Connected to Paseo network!");
      } catch (err) {
        console.error("❌ Connection failed:", err);
        setError(`Connection failed: ${err.message}`);
      }
    };

    initConnection();

    // Cleanup function - runs when component unmounts
    return () => {
      if (client) {
        client.destroy();
      }
    };
  }, []); // Empty dependency array means this runs once when component loads

  // Function to check account balance
  const checkBalance = async () => {
    if (!api || !address) {
      setError("Please enter an address and wait for connection");
      return;
    }

    setIsLoading(true);
    setError("");
    setBalance(null);

    try {
      console.log(`🔍 Checking balance for: ${address}`);

      // Query the account information from the blockchain
      const accountInfo = await api.query.System.Account.getValue(address);

      if (!accountInfo) {
        throw new Error("Account not found");
      }

      // Extract balance information
      const freeBalance = accountInfo.data.free;
      const reservedBalance = accountInfo.data.reserved;
      const totalBalance = freeBalance + reservedBalance;

      // Convert from smallest units to human-readable format
      const divisor = 10n ** BigInt(networkInfo.tokenDecimals);
      const formattedFree = Number(freeBalance) / Number(divisor);
      const formattedReserved = Number(reservedBalance) / Number(divisor);
      const formattedTotal = Number(totalBalance) / Number(divisor);

      setBalance({
        free: freeBalance,
        reserved: reservedBalance,
        total: totalBalance,
        formattedFree,
        formattedReserved,
        formattedTotal
      });

      console.log(`💰 Balance found: ${formattedTotal.toFixed(4)} ${networkInfo.tokenSymbol}`);

    } catch (err) {
      console.error("❌ Error checking balance:", err);
      setError(`Error: ${err.message}`);
    } finally {
      setIsLoading(false);
    }
  };

  // Component's visual interface
  return (
    <div style={{
      fontFamily: 'system-ui, -apple-system, sans-serif',
      maxWidth: '600px',
      margin: '0 auto',
      backgroundColor: '#fff',
      color: '#000',
      borderRadius: '12px',
      boxShadow: '0 4px 20px rgba(0, 0, 0, 0.08)',
      overflow: 'hidden'
    }}>
      {/* Header */}
      <div style={{
        backgroundColor: '#FF7B00', // Paseo orange color
        color: 'white',
        padding: '20px',
        textAlign: 'center'
      }}>
        <h2 style={{ margin: 0, fontSize: '24px' }}>
          🏦 Paseo Balance Checker
        </h2>
        <p style={{ margin: '8px 0 0', opacity: 0.9 }}>
          Check account balances on Paseo testnet
        </p>
      </div>

      {/* Main content */}
      <div style={{ padding: '24px' }}>
        {/* Connection status */}
        <div style={{
          padding: '12px',
          backgroundColor: api ? '#e8f5e8' : '#fff3e0',
          borderRadius: '8px',
          border: `1px solid ${api ? '#4caf50' : '#ff9800'}`,
          marginBottom: '20px',
          textAlign: 'center'
        }}>
          {api ? '✅ Connected to Paseo' : '⏳ Connecting to Paseo...'}
        </div>

        {/* Address input */}
        <div style={{ marginBottom: '20px' }}>
          <label style={{
            display: 'block',
            marginBottom: '8px',
            fontWeight: '600',
            color: '#333'
          }}>
            Account Address:
          </label>
          <input
            type="text"
            value={address}
            onChange={(e) => setAddress(e.target.value)}
            style={{
              width: '100%',
              padding: '12px',
              borderRadius: '8px',
              border: '2px solid #e0e0e0',
              fontSize: '14px',
              boxSizing: 'border-box',
              backgroundColor: '#fff'
            }}
            placeholder="Enter account address"
            disabled={isLoading}
          />
        </div>

        {/* Check balance button */}
        <button
          onClick={checkBalance}
          disabled={isLoading || !api}
          style={{
            backgroundColor: api && !isLoading ? '#FF7B00' : '#ccc',
            color: 'white',
            border: 'none',
            padding: '14px 20px',
            borderRadius: '8px',
            cursor: api && !isLoading ? 'pointer' : 'not-allowed',
            fontSize: '16px',
            fontWeight: '600',
            width: '100%'
          }}
        >
          {isLoading ? '⏳ Checking...' : '🔍 Check Balance'}
        </button>

        {/* Error display */}
        {error && (
          <div style={{
            marginTop: '20px',
            padding: '16px',
            backgroundColor: '#ffebee',
            color: '#c62828',
            borderRadius: '8px',
            fontSize: '14px'
          }}>
             {error}
          </div>
        )}

        {/* Balance results */}
        {balance && (
          <div style={{
            marginTop: '24px',
            padding: '20px',
            backgroundColor: '#f8f9fa',
            borderRadius: '12px',
            border: '1px solid #e0e0e0'
          }}>
            <h3 style={{ margin: '0 0 16px', color: '#333' }}>
              💰 Balance Information
            </h3>

            <div style={{
              display: 'flex',
              justifyContent: 'space-between',
              padding: '8px 0',
              borderBottom: '1px solid #eee'
            }}>
              <span style={{ color: '#666' }}>Free Balance:</span>
              <span style={{ fontWeight: '600' }}>
                {balance.formattedFree.toFixed(4)} {networkInfo.tokenSymbol}
              </span>
            </div>

            <div style={{
              display: 'flex',
              justifyContent: 'space-between',
              padding: '8px 0',
              borderBottom: '1px solid #eee'
            }}>
              <span style={{ color: '#666' }}>Reserved Balance:</span>
              <span style={{ fontWeight: '600' }}>
                {balance.formattedReserved.toFixed(4)} {networkInfo.tokenSymbol}
              </span>
            </div>

            <div style={{
              display: 'flex',
              justifyContent: 'space-between',
              padding: '8px 0',
              fontWeight: 'bold'
            }}>
              <span>Total Balance:</span>
              <span>{balance.formattedTotal.toFixed(4)} {networkInfo.tokenSymbol}</span>
            </div>

            {/* Raw values for developers */}
            <div style={{
              marginTop: '16px',
              padding: '12px',
              backgroundColor: '#f0f0f0',
              borderRadius: '6px',
              fontSize: '12px',
              fontFamily: 'monospace'
            }}>
              <div>Raw Values (Planck units):</div>
              <div>Free: {balance.free.toString()}</div>
              <div>Reserved: {balance.reserved.toString()}</div>
              <div>Total: {balance.total.toString()}</div>
            </div>
          </div>
        )}

        {/* Information box */}
        <div style={{
          marginTop: '24px',
          padding: '16px',
          backgroundColor: '#f0f8ff',
          borderRadius: '8px',
          borderLeft: '4px solid #2196f3',
          fontSize: '14px'
        }}>
          <h4 style={{ margin: '0 0 12px', color: '#1976d2' }}>
            💡 About Account Balances
          </h4>
          <ul style={{ margin: '0', paddingLeft: '20px' }}>
            <li style={{ marginBottom: '8px' }}>
              <strong>Free Balance:</strong> Tokens available for transfers
            </li>
            <li style={{ marginBottom: '8px' }}>
              <strong>Reserved Balance:</strong> Tokens locked for operations (staking, governance, etc.)
            </li>
            <li>
              <strong>Total Balance:</strong> Sum of free + reserved tokens
            </li>
          </ul>
        </div>
      </div>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Run Your Component

  1. Copy the code above into the PAPI Simulator editor
  2. Click "Run Code"
  3. Watch the console for connection messages
  4. Try checking different addresses:
    • Alice: 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
    • Bob: 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty

Step 4: Understanding What Happened

Connection Process:

  1. ✅ Component loaded and initiated connection
  2. ✅ WebSocket connected to Paseo network
  3. ✅ API client created with type safety
  4. ✅ Ready to make blockchain queries

Balance Query Process:

  1. 🔍 User enters account address
  2. 🔍 Component queries System.Account storage
  3. 🔍 Blockchain returns account data
  4. 💰 Component formats and displays balance

Adding Interactive Features

Let's enhance our component with more features:

Step 1: Add Multiple Account Support

// Add this after the networkInfo declaration
const wellKnownAccounts = {
  alice: {
    name: "Alice (Test Account)",
    address: "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"
  },
  bob: {
    name: "Bob (Test Account)", 
    address: "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"
  },
  charlie: {
    name: "Charlie (Test Account)",
    address: "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y"
  }
};
Enter fullscreen mode Exit fullscreen mode

Step 2: Add Quick Select Buttons

Add this before the address input:

{/* Quick select buttons */}
<div style={{ marginBottom: '16px' }}>
  <label style={{
    display: 'block',
    marginBottom: '8px',
    fontWeight: '600',
    color: '#333'
  }}>
    Quick Select:
  </label>
  <div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap' }}>
    {Object.entries(wellKnownAccounts).map(([key, account]) => (
      <button
        key={key}
        onClick={() => setAddress(account.address)}
        style={{
          padding: '6px 12px',
          backgroundColor: '#f5f5f5',
          border: '1px solid #ddd',
          borderRadius: '6px',
          cursor: 'pointer',
          fontSize: '12px'
        }}
      >
        {account.name}
      </button>
    ))}
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Step 3: Add Real-time Updates

// Add this state variable
const [autoRefresh, setAutoRefresh] = useState(false);

// Add this effect for auto-refresh
useEffect(() => {
  if (!autoRefresh || !api || !address) return;

  const interval = setInterval(() => {
    checkBalance();
  }, 10000); // Refresh every 10 seconds

  return () => clearInterval(interval);
}, [autoRefresh, api, address]);

// Add auto-refresh toggle
<div style={{ marginBottom: '20px' }}>
  <label style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
    <input
      type="checkbox"
      checked={autoRefresh}
      onChange={(e) => setAutoRefresh(e.target.checked)}
    />
    <span>Auto-refresh every 10 seconds</span>
  </label>
</div>
Enter fullscreen mode Exit fullscreen mode

Understanding What's Happening

Blockchain Concepts in Action

1. Network Connection:

// This creates a WebSocket connection to a Paseo node
const provider = getWsProvider(networkInfo.endpoint);

// This wraps it with compatibility features
const client = createClient(withPolkadotSdkCompat(provider));
Enter fullscreen mode Exit fullscreen mode

2. Querying Blockchain State:

// This queries the blockchain's state
const accountInfo = await api.query.System.Account.getValue(address);

// It returns data like this:
{
  data: {
    free: 1000000000000n,      // Free balance in smallest units
    reserved: 0n,              // Reserved/locked balance
    miscFrozen: 0n,           // Frozen for various reasons
    feeFrozen: 0n             // Frozen for transaction fees
  },
  nonce: 0,                   // Transaction counter
  consumers: 0,               // Number of consumers
  providers: 1                // Number of providers
}
Enter fullscreen mode Exit fullscreen mode

3. Unit Conversion:

// Blockchain stores values in smallest units (like cents)
// We convert to human-readable format (like dollars)
const divisor = 10n ** BigInt(networkInfo.tokenDecimals);
const formatted = Number(balance) / Number(divisor);
Enter fullscreen mode Exit fullscreen mode

Why This Matters

🔐 Decentralized: No single server controls the data
🌍 Global: Anyone can access the same information
🔍 Transparent: All transactions are publicly verifiable
💎 Immutable: Historical data cannot be changed


Next Steps

Beginner Projects:

  1. Block Explorer: Show recent blocks and transactions
  2. Transfer Tool: Send tokens between accounts
  3. Event Monitor: Watch for specific blockchain events

Intermediate Projects:

  1. Staking Dashboard: Display staking information
  2. Governance Tracker: Monitor proposals and voting
  3. Cross-chain Bridge: Move tokens between parachains

Advanced Projects:

  1. DeFi Interface: Interact with decentralized finance protocols
  2. NFT Marketplace: Create and trade digital assets
  3. DAO Manager: Participate in decentralized organizations

Learning Resources:

Official Documentation:

Community:

Key Takeaways:

You've learned:

  • How to connect to a blockchain network
  • How to query account information
  • How to build interactive blockchain UIs
  • Basic blockchain concepts through hands-on coding

You can now:

  • Create React components that interact with Paseo
  • Understand blockchain data structures
  • Debug connection and query issues
  • Build upon this foundation for more complex projects

Common Next Questions:

Q: How do I get test tokens?
A: Visit the Paseo Faucet to get free test tokens.

Q: Can I use this on mainnet?
A: Yes, but change the network endpoint and be very careful with real tokens.

Q: How do I send transactions?
A: You'll need to integrate wallet signing - check the "Wallet Transfer" example in PAPI Simulator.

Q: What other networks can I use?
A: Try Westend, or even Polkadot mainnet by changing the descriptors and endpoints.


Troubleshooting Guide

Common Issues:

🔗 Connection Problems:

Error: Connection failed
Enter fullscreen mode Exit fullscreen mode
  • Check internet connection
  • Try different RPC endpoint
  • Verify network is running

📍 Address Format Issues:

Error: Invalid address format
Enter fullscreen mode Exit fullscreen mode
  • Ensure address starts with '5' for Paseo
  • Check address length (47-48 characters)
  • Use test accounts provided

⏰ Timeout Errors:

Error: Request timeout
Enter fullscreen mode Exit fullscreen mode
  • Network might be slow
  • Try refreshing the page
  • Use different RPC endpoint

💾 State Issues:

Error: Account not found
Enter fullscreen mode Exit fullscreen mode
  • Address might not exist on chain
  • Try well-known test accounts
  • Check if using correct network

Remember: This is a testnet - everything here is for learning and testing. No real money is involved, so feel free to experiment!


Congratulations! 🎉 You've just built your first blockchain React component. You're now ready to explore the exciting world of decentralized applications on the Polkadot ecosystem!

Comments 0 total

    Add comment