diff --git a/.gitignore b/.gitignore index f0f444b7..2af249f6 100644 --- a/.gitignore +++ b/.gitignore @@ -75,5 +75,24 @@ founder_validators.json founder_governance.json mainnet/ relay-mainnet.json +relay-mainnet-raw.json +asset-hub-plain.json +asset-hub-raw.json +people-chain.json +people-chain-raw.json + +# Mainnet operation scripts (may contain sensitive data) +vendor/pezkuwi-subxt/subxt/examples/check_staking.rs +vendor/pezkuwi-subxt/subxt/examples/comprehensive_test.rs +vendor/pezkuwi-subxt/subxt/examples/create_nft_collection.rs +vendor/pezkuwi-subxt/subxt/examples/debug_transfer.rs +vendor/pezkuwi-subxt/subxt/examples/register_teyrchain.rs +vendor/pezkuwi-subxt/subxt/examples/transfer_mainnet.rs + +# Local tools (not part of SDK) +tools/asset-creator/ +tools/build-mainnet-chainspec.sh +tools/runtime-upgrade/ +tools/wasm-crypto/ tools/usdt-bridge/bridge_db.json .claude/domains-repositories diff --git a/vendor/pezkuwi-subxt/subxt/examples/comprehensive_test.rs b/vendor/pezkuwi-subxt/subxt/examples/comprehensive_test.rs deleted file mode 100644 index e76bcd62..00000000 --- a/vendor/pezkuwi-subxt/subxt/examples/comprehensive_test.rs +++ /dev/null @@ -1,731 +0,0 @@ -//! Comprehensive Post-Upgrade Test Suite (spec_version 1_020_003) -//! -//! Tests all functionality after runtime upgrade: -//! - Balance queries on all 3 chains -//! - XCM teleport from Relay to Asset Hub (1000 HEZ) -//! - XCM teleport from Relay to People Chain (1000 HEZ) -//! - Welati (citizenship) application on People Chain -//! - Staking queries on Relay Chain -//! - Trust score verification on People Chain -//! -//! Run with: -//! FOUNDER_MNEMONIC='foam hope ...' cargo run --example comprehensive_test - -#![allow(missing_docs)] -use pezkuwi_subxt::dynamic::{At, Value}; -use pezkuwi_subxt::utils::AccountId32; -use pezkuwi_subxt::{OnlineClient, PezkuwiConfig}; -use pezkuwi_subxt_signer::bip39::Mnemonic; -use pezkuwi_subxt_signer::sr25519::Keypair; -use scale_value::Composite; -use std::time::Duration; - -// Generate interface from relay chain metadata (spec_version 1_020_003) -#[pezkuwi_subxt::subxt(runtime_metadata_path = "../artifacts/relay_mainnet_v3.scale")] -pub mod relay {} - -// XCM type aliases for convenience -use relay::runtime_types::pezstaging_xcm::v4::{ - asset::{Asset, AssetId, Assets, Fungibility}, - junction::Junction, - junctions::Junctions, - location::Location, -}; -use relay::runtime_types::xcm::{ - v3::WeightLimit, VersionedAssetId, VersionedAssets, VersionedLocation, -}; - -// RPC endpoints (direct to VPS3) -const RELAY_RPC: &str = "ws://217.77.6.126:9944"; -const ASSET_HUB_RPC: &str = "ws://217.77.6.126:40944"; -const PEOPLE_RPC: &str = "ws://217.77.6.126:41944"; - -// 1 HEZ = 10^12 TYR -const TYR_PER_HEZ: u128 = 1_000_000_000_000; - -// Para IDs -const ASSET_HUB_ID: u32 = 1000; -const PEOPLE_CHAIN_ID: u32 = 1004; - -// Test wallet mnemonic -const TEST_MNEMONIC: &str = - "REDACTED_MNEMONIC"; - -fn format_hez(tyr: u128) -> String { - let whole = tyr / TYR_PER_HEZ; - let frac = (tyr % TYR_PER_HEZ) / (TYR_PER_HEZ / 10000); - format!("{}.{:04} HEZ", whole, frac) -} - -/// Query balance using dynamic storage query (works on any chain) -async fn query_balance( - api: &OnlineClient, - account: &AccountId32, -) -> Result> { - let storage_query = - pezkuwi_subxt::dynamic::storage::<(AccountId32,), Value>("System", "Account"); - let client_at = api.storage().at_latest().await?; - match client_at.entry(storage_query)?.try_fetch((account.clone(),)).await? { - Some(val) => { - let decoded = val.decode()?; - let free = decoded - .at("data") - .at("free") - .ok_or("Could not find free balance")? - .as_u128() - .ok_or("Could not parse balance")?; - Ok(free) - }, - None => Ok(0), - } -} - -/// Dynamic storage query helper for People Chain - map types -async fn people_storage_map( - api: &OnlineClient, - pallet: &str, - entry: &str, - account: &AccountId32, -) -> Result>, Box> { - let query = pezkuwi_subxt::dynamic::storage::<(AccountId32,), Value>(pallet, entry); - match api - .storage() - .at_latest() - .await? - .entry(query)? - .try_fetch((account.clone(),)) - .await? - { - Some(val) => Ok(Some(val.decode()?)), - None => Ok(None), - } -} - -/// Dynamic storage query helper for People Chain - value types (no key) -async fn people_storage_value( - api: &OnlineClient, - pallet: &str, - entry: &str, -) -> Result>, Box> { - let query = pezkuwi_subxt::dynamic::storage::<(), Value>(pallet, entry); - match api.storage().at_latest().await?.entry(query)?.try_fetch(()).await? { - Some(val) => Ok(Some(val.decode()?)), - None => Ok(None), - } -} - -/// Build XCM destination for a teyrchain -fn xcm_dest(para_id: u32) -> VersionedLocation { - VersionedLocation::V4(Location { - parents: 0, - interior: Junctions::X1([Junction::Teyrchain(para_id)]), - }) -} - -/// Build XCM beneficiary for an account -fn xcm_beneficiary(pubkey: [u8; 32]) -> VersionedLocation { - VersionedLocation::V4(Location { - parents: 0, - interior: Junctions::X1([Junction::AccountId32 { network: None, id: pubkey }]), - }) -} - -/// Build XCM assets (native HEZ token) -fn xcm_native_assets(amount: u128) -> VersionedAssets { - VersionedAssets::V4(Assets(vec![Asset { - id: AssetId(Location { parents: 0, interior: Junctions::Here }), - fun: Fungibility::Fungible(amount), - }])) -} - -/// Native fee asset ID -fn xcm_fee_asset() -> VersionedAssetId { - VersionedAssetId::V4(AssetId(Location { parents: 0, interior: Junctions::Here })) -} - -#[tokio::main] -async fn main() -> Result<(), Box> { - println!("╔══════════════════════════════════════════════════════════════╗"); - println!("║ PEZKUWICHAIN COMPREHENSIVE POST-UPGRADE TEST SUITE ║"); - println!("║ spec_version: 1_020_003 (Trust Score System) ║"); - println!("╚══════════════════════════════════════════════════════════════╝\n"); - - // ═══════════════════════════════════════════════════════════════════ - // SECTION 1: Setup wallets - // ═══════════════════════════════════════════════════════════════════ - println!("═══ SECTION 1: Setup Wallets ═══\n"); - - let test_mnemonic = Mnemonic::parse(TEST_MNEMONIC)?; - let test_wallet = Keypair::from_phrase(&test_mnemonic, None)?; - let test_account = AccountId32(test_wallet.public_key().0); - println!(" Test Wallet: {}", test_account); - - let founder_mnemonic_str = std::env::var("FOUNDER_MNEMONIC") - .expect("FOUNDER_MNEMONIC env var required (founder/sudo seed)"); - let founder_mnemonic = Mnemonic::parse(&founder_mnemonic_str)?; - let founder_wallet = Keypair::from_phrase(&founder_mnemonic, None)?; - let founder_account = AccountId32(founder_wallet.public_key().0); - println!(" Founder: {}", founder_account); - - // ═══════════════════════════════════════════════════════════════════ - // SECTION 2: Connect to all chains - // ═══════════════════════════════════════════════════════════════════ - println!("\n═══ SECTION 2: Connect to Chains ═══\n"); - - let relay_api = OnlineClient::::from_insecure_url(RELAY_RPC).await?; - println!(" ✓ Relay Chain connected ({})", RELAY_RPC); - - let ah_api = OnlineClient::::from_insecure_url(ASSET_HUB_RPC).await?; - println!(" ✓ Asset Hub connected ({})", ASSET_HUB_RPC); - - let people_api = OnlineClient::::from_insecure_url(PEOPLE_RPC).await?; - println!(" ✓ People Chain connected ({})", PEOPLE_RPC); - - // ═══════════════════════════════════════════════════════════════════ - // SECTION 3: Verify spec_version on all chains - // ═══════════════════════════════════════════════════════════════════ - println!("\n═══ SECTION 3: Verify Runtime Versions ═══\n"); - - let relay_ver = relay_api.runtime_version().spec_version; - let ah_ver = ah_api.runtime_version().spec_version; - let people_ver = people_api.runtime_version().spec_version; - - println!(" Relay Chain: spec_version = {}", relay_ver); - println!(" Asset Hub: spec_version = {}", ah_ver); - println!(" People Chain: spec_version = {}", people_ver); - - assert_eq!(relay_ver, 1_020_003, "Relay spec_version mismatch!"); - assert_eq!(ah_ver, 1_020_003, "Asset Hub spec_version mismatch!"); - assert_eq!(people_ver, 1_020_003, "People Chain spec_version mismatch!"); - println!(" ✓ All chains at spec_version 1_020_003"); - - // ═══════════════════════════════════════════════════════════════════ - // SECTION 4: Check initial balances - // ═══════════════════════════════════════════════════════════════════ - println!("\n═══ SECTION 4: Initial Balances ═══\n"); - - let relay_balance = query_balance(&relay_api, &test_account).await?; - let ah_balance = query_balance(&ah_api, &test_account).await?; - let people_balance = query_balance(&people_api, &test_account).await?; - - println!(" Test Wallet Balances:"); - println!(" Relay Chain: {} ({} TYR)", format_hez(relay_balance), relay_balance); - println!(" Asset Hub: {} ({} TYR)", format_hez(ah_balance), ah_balance); - println!(" People Chain: {} ({} TYR)", format_hez(people_balance), people_balance); - - let need_teleport = - relay_balance >= 2000 * TYR_PER_HEZ && ah_balance == 0 && people_balance == 0; - - let (ah_received, people_received); - - if need_teleport { - println!(" ✓ Sufficient balance for teleports"); - - // ═══════════════════════════════════════════════════════════════════ - // SECTION 5: XCM Teleport — Relay → Asset Hub (1000 HEZ) - // ═══════════════════════════════════════════════════════════════════ - println!("\n═══ SECTION 5: XCM Teleport → Asset Hub (1000 HEZ) ═══\n"); - - let teleport_amount: u128 = 1000 * TYR_PER_HEZ; - - let xcm_ah_tx = relay::tx().xcm_pallet().limited_teleport_assets( - xcm_dest(ASSET_HUB_ID), - xcm_beneficiary(test_wallet.public_key().0), - xcm_native_assets(teleport_amount), - xcm_fee_asset(), - WeightLimit::Unlimited, - ); - - println!(" Submitting XCM teleport to Asset Hub (1000 HEZ)..."); - let events_ah = relay_api - .tx() - .sign_and_submit_then_watch_default(&xcm_ah_tx, &test_wallet) - .await? - .wait_for_finalized_success() - .await?; - - println!(" ✓ Teleport to Asset Hub finalized!"); - match events_ah.find_first::()? { - Some(event) => println!(" XCM Attempted: {:?}", event.outcome), - None => println!(" ⚠ No Attempted event"), - } - - // ═══════════════════════════════════════════════════════════════════ - // SECTION 6: XCM Teleport — Relay → People Chain (1000 HEZ) - // ═══════════════════════════════════════════════════════════════════ - println!("\n═══ SECTION 6: XCM Teleport → People Chain (1000 HEZ) ═══\n"); - - let xcm_people_tx = relay::tx().xcm_pallet().limited_teleport_assets( - xcm_dest(PEOPLE_CHAIN_ID), - xcm_beneficiary(test_wallet.public_key().0), - xcm_native_assets(teleport_amount), - xcm_fee_asset(), - WeightLimit::Unlimited, - ); - - println!(" Submitting XCM teleport to People Chain (1000 HEZ)..."); - let events_people = relay_api - .tx() - .sign_and_submit_then_watch_default(&xcm_people_tx, &test_wallet) - .await? - .wait_for_finalized_success() - .await?; - - println!(" ✓ Teleport to People Chain finalized!"); - match events_people.find_first::()? { - Some(event) => println!(" XCM Attempted: {:?}", event.outcome), - None => println!(" ⚠ No Attempted event"), - } - - // ═══════════════════════════════════════════════════════════════════ - // SECTION 7: Wait for XCM delivery & verify teleport balances - // ═══════════════════════════════════════════════════════════════════ - println!("\n═══ SECTION 7: Verify Teleport Results ═══\n"); - println!(" Waiting 30 seconds for XCM messages to be delivered..."); - tokio::time::sleep(Duration::from_secs(30)).await; - - let relay_after = query_balance(&relay_api, &test_account).await?; - let ah_after = query_balance(&ah_api, &test_account).await?; - let people_after = query_balance(&people_api, &test_account).await?; - - println!(" Post-Teleport Balances:"); - println!( - " Relay Chain: {} (was {})", - format_hez(relay_after), - format_hez(relay_balance) - ); - println!(" Asset Hub: {} (was {})", format_hez(ah_after), format_hez(ah_balance)); - println!( - " People Chain: {} (was {})", - format_hez(people_after), - format_hez(people_balance) - ); - - ah_received = ah_after.saturating_sub(ah_balance); - people_received = people_after.saturating_sub(people_balance); - - println!("\n Transfer Summary:"); - println!(" Relay spent: {}", format_hez(relay_balance.saturating_sub(relay_after))); - println!(" AH received: {}", format_hez(ah_received)); - println!(" People received: {}", format_hez(people_received)); - println!(" → Asset Hub: {}", if ah_received > 0 { "✓ SUCCESS" } else { "✗ FAILED" }); - println!( - " → People Chain: {}", - if people_received > 0 { "✓ SUCCESS" } else { "✗ FAILED" } - ); - } else { - println!("\n═══ SECTIONS 5-7: XCM Teleport (SKIPPED - already done) ═══\n"); - println!(" Relay: {}", format_hez(relay_balance)); - println!(" AH: {}", format_hez(ah_balance)); - println!(" People: {}", format_hez(people_balance)); - println!(" ✓ Balances already distributed across chains"); - ah_received = ah_balance; - people_received = people_balance; - } - - // ═══════════════════════════════════════════════════════════════════ - // SECTION 8: Staking Queries (Relay Chain) - // ═══════════════════════════════════════════════════════════════════ - println!("\n═══ SECTION 8: Staking Status (Relay Chain) ═══\n"); - - let block = relay_api.blocks().at_latest().await?; - println!(" Current Block: #{}", block.number()); - - let storage = relay_api.storage().at_latest().await?; - - let active_era = storage.try_fetch(relay::storage().staking().active_era(), ()).await?; - println!(" Active Era: {:?}", active_era.and_then(|v| v.decode().ok())); - - let current_era = storage.try_fetch(relay::storage().staking().current_era(), ()).await?; - println!(" Current Era: {:?}", current_era.and_then(|v| v.decode().ok())); - - let session_index = storage.try_fetch(relay::storage().session().current_index(), ()).await?; - println!(" Session Index: {:?}", session_index.and_then(|v| v.decode().ok())); - - let val_count = storage.try_fetch(relay::storage().staking().validator_count(), ()).await?; - println!(" Validator Count: {:?}", val_count.and_then(|v| v.decode().ok())); - - let force_era = storage.try_fetch(relay::storage().staking().force_era(), ()).await?; - println!(" Force Era: {:?}", force_era.and_then(|v| v.decode().ok())); - - println!(" ✓ Staking system operational"); - - // ═══════════════════════════════════════════════════════════════════ - // SECTION 9: Welati (Citizenship) Application on People Chain - // ═══════════════════════════════════════════════════════════════════ - println!("\n═══ SECTION 9: Welati (Citizenship) Application ═══\n"); - - // Check if test wallet already has KYC status - let kyc_status = - people_storage_map(&people_api, "IdentityKyc", "KycStatuses", &test_account).await?; - - let already_citizen = if let Some(status) = &kyc_status { - let status_str = format!("{:?}", status); - println!(" Current KYC status: {}", status_str); - status_str.contains("Approved") - } else { - println!(" KYC status: NotStarted (no entry)"); - false - }; - - if already_citizen { - println!(" ✓ Already a citizen (KYC Approved), skipping application steps"); - } else { - // Step 1: Apply for citizenship - let identity_data = b"Azad Qasimlo|DR.QAsimlo"; - let identity_hash = pezsp_crypto_hashing::blake2_256(identity_data); - println!( - " Identity hash: 0x{}", - identity_hash.iter().map(|b| format!("{:02x}", b)).collect::() - ); - - let apply_tx = pezkuwi_subxt::dynamic::tx( - "IdentityKyc", - "apply_for_citizenship", - Composite::unnamed([ - Value::from_bytes(identity_hash), - Value::unnamed_variant("None", []), - ]), - ); - - println!(" Submitting citizenship application..."); - let apply_events = people_api - .tx() - .sign_and_submit_then_watch_default(&apply_tx, &test_wallet) - .await? - .wait_for_finalized_success() - .await?; - println!(" ✓ Citizenship application submitted and finalized!"); - - for event in apply_events.iter() { - let event = event?; - if event.pallet_name() == "IdentityKyc" { - println!(" Event: {}::{}", event.pallet_name(), event.variant_name()); - } - } - - // Step 2: Founder approves referral - println!("\n Founder approving referral..."); - let approve_tx = pezkuwi_subxt::dynamic::tx( - "IdentityKyc", - "approve_referral", - Composite::unnamed([Value::from_bytes(&test_account.0)]), - ); - - let approve_events = people_api - .tx() - .sign_and_submit_then_watch_default(&approve_tx, &founder_wallet) - .await? - .wait_for_finalized_success() - .await?; - println!(" ✓ Referral approved by founder!"); - - for event in approve_events.iter() { - let event = event?; - if event.pallet_name() == "IdentityKyc" { - println!(" Event: {}::{}", event.pallet_name(), event.variant_name()); - } - } - - // Step 3: Test wallet confirms citizenship - println!("\n Confirming citizenship (self-confirmation)..."); - let confirm_tx = pezkuwi_subxt::dynamic::tx( - "IdentityKyc", - "confirm_citizenship", - Composite::unnamed([]), - ); - - let confirm_events = people_api - .tx() - .sign_and_submit_then_watch_default(&confirm_tx, &test_wallet) - .await? - .wait_for_finalized_success() - .await?; - println!(" ✓ Citizenship confirmed!"); - - println!("\n Confirmation events:"); - for event in confirm_events.iter() { - let event = event?; - let pallet = event.pallet_name(); - match pallet { - "IdentityKyc" | "Tiki" | "Referral" | "Trust" | "Nfts" | "Balances" => { - println!(" {}::{}", pallet, event.variant_name()); - }, - _ => {}, - } - } - } - - // ═══════════════════════════════════════════════════════════════════ - // SECTION 9b: Ensure NFT Collection exists & mint CitizenNft - // ═══════════════════════════════════════════════════════════════════ - println!("\n═══ SECTION 9b: NFT Collection & Citizen NFT Fix ═══\n"); - - // Check if Tiki collection (ID=0) exists - let _collection_exists = people_storage_map( - &people_api, - "Nfts", - "Collection", - // Collection storage key is a u32 (collection_id = 0), not an AccountId - // Use a raw dynamic query instead - &AccountId32([0u8; 32]), // placeholder - ) - .await; - - // Use a different approach: check if NextItemId storage exists in Tiki - let next_item_id = people_storage_value(&people_api, "Tiki", "NextItemId").await?; - println!(" Tiki NextItemId: {:?}", next_item_id); - - // Check if test wallet already has CitizenNft - let has_citizen_nft = - people_storage_map(&people_api, "Tiki", "CitizenNft", &test_account).await?; - - if has_citizen_nft.is_some() { - println!(" ✓ Test Wallet already has Citizen NFT"); - } else { - println!(" ✗ Test Wallet does NOT have Citizen NFT - attempting sudo fix..."); - - // Step 1: Create NFT collection 0 via sudo (Nfts::force_create) - // force_create(owner, config) where owner = founder, config = default - println!(" Creating NFT Collection 0 via sudo..."); - let create_collection_inner = pezkuwi_subxt::dynamic::tx( - "Nfts", - "force_create", - Composite::unnamed([ - // owner - Value::unnamed_variant("Id", [Value::from_bytes(&founder_account.0)]), - // config (CollectionConfig) - Value::unnamed_composite([ - // settings: u64 (all features enabled = 0) - Value::u128(0), - // max_supply: Option - Value::unnamed_variant("None", []), - // mint_settings: MintSettings - Value::unnamed_composite([ - // mint_type - Value::unnamed_variant("Issuer", []), - // price: Option - Value::unnamed_variant("None", []), - // start_block: Option - Value::unnamed_variant("None", []), - // end_block: Option - Value::unnamed_variant("None", []), - // default_item_settings: u64 - Value::u128(0), - ]), - ]), - ]), - ); - - let sudo_create = - pezkuwi_subxt::dynamic::tx("Sudo", "sudo", vec![create_collection_inner.into_value()]); - - match people_api - .tx() - .sign_and_submit_then_watch_default(&sudo_create, &founder_wallet) - .await - { - Ok(progress) => match progress.wait_for_finalized_success().await { - Ok(events) => { - println!(" ✓ NFT Collection 0 created!"); - for event in events.iter() { - let event = event?; - if event.pallet_name() == "Nfts" || event.pallet_name() == "Sudo" { - println!(" {}::{}", event.pallet_name(), event.variant_name()); - } - } - }, - Err(e) => println!(" ⚠ Collection creation finalized with error: {}", e), - }, - Err(e) => println!(" ⚠ Collection creation failed: {}", e), - } - - // Step 2: Force mint citizen NFT for test wallet via sudo (Tiki::force_mint_citizen_nft) - tokio::time::sleep(Duration::from_secs(6)).await; - - println!(" Force minting Citizen NFT for test wallet..."); - let mint_inner = pezkuwi_subxt::dynamic::tx( - "Tiki", - "force_mint_citizen_nft", - Composite::unnamed([Value::from_bytes(&test_account.0)]), - ); - - let sudo_mint = pezkuwi_subxt::dynamic::tx("Sudo", "sudo", vec![mint_inner.into_value()]); - - match people_api - .tx() - .sign_and_submit_then_watch_default(&sudo_mint, &founder_wallet) - .await - { - Ok(progress) => match progress.wait_for_finalized_success().await { - Ok(events) => { - println!(" ✓ Citizen NFT minted!"); - for event in events.iter() { - let event = event?; - let pallet = event.pallet_name(); - match pallet { - "Tiki" | "Nfts" | "Sudo" => { - println!(" {}::{}", pallet, event.variant_name()); - }, - _ => {}, - } - } - }, - Err(e) => println!(" ⚠ NFT mint finalized with error: {}", e), - }, - Err(e) => println!(" ⚠ NFT mint failed: {}", e), - } - - tokio::time::sleep(Duration::from_secs(6)).await; - } - - // ═══════════════════════════════════════════════════════════════════ - // SECTION 10: Trust Score Verification (People Chain) - // ═══════════════════════════════════════════════════════════════════ - println!("\n═══ SECTION 10: Trust Score Verification ═══\n"); - - match people_storage_map(&people_api, "Trust", "TrustScores", &test_account).await? { - Some(val) => println!(" Test Wallet Trust Score: {:?}", val), - None => println!(" Test Wallet Trust Score: 0 (not set)"), - } - - match people_storage_value(&people_api, "Trust", "TotalActiveTrustScore").await? { - Some(val) => println!(" Total Active Trust Score: {:?}", val), - None => println!(" Total Active Trust Score: 0"), - } - - match people_storage_map(&people_api, "Trust", "TrustScores", &founder_account).await? { - Some(val) => println!(" Founder Trust Score: {:?}", val), - None => println!(" Founder Trust Score: 0 (not set)"), - } - - // ═══════════════════════════════════════════════════════════════════ - // SECTION 11: Tiki (Role NFT) Verification - // ═══════════════════════════════════════════════════════════════════ - println!("\n═══ SECTION 11: Tiki (Role NFT) Verification ═══\n"); - - match people_storage_map(&people_api, "Tiki", "CitizenNft", &test_account).await? { - Some(val) => println!(" ✓ Test Wallet has Citizen NFT: {:?}", val), - None => println!(" ✗ Test Wallet does NOT have Citizen NFT"), - } - - match people_storage_map(&people_api, "Tiki", "UserTikis", &test_account).await? { - Some(val) => println!(" Test Wallet Roles: {:?}", val), - None => println!(" Test Wallet has no roles assigned"), - } - - // ═══════════════════════════════════════════════════════════════════ - // SECTION 12: Referral System Check - // ═══════════════════════════════════════════════════════════════════ - println!("\n═══ SECTION 12: Referral System ═══\n"); - - match people_storage_map(&people_api, "IdentityKyc", "CitizenReferrers", &test_account).await? { - Some(val) => println!(" Test Wallet referrer: {:?}", val), - None => println!(" No referrer recorded"), - } - - match people_storage_map(&people_api, "Referral", "ReferralCount", &founder_account).await { - Ok(Some(val)) => println!(" Founder referral count: {:?}", val), - Ok(None) => println!(" Founder referral count: 0"), - Err(e) => println!(" ⚠ ReferralCount query error: {}", e), - } - - match people_storage_map(&people_api, "Referral", "Referrals", &test_account).await { - Ok(Some(val)) => println!(" Test Wallet referral info: {:?}", val), - Ok(None) => println!(" No referral info for test wallet"), - Err(e) => println!(" ⚠ Referrals query error: {}", e), - } - - match people_storage_map(&people_api, "Referral", "ReferrerStatsStorage", &founder_account) - .await - { - Ok(Some(val)) => println!(" Founder referrer stats: {:?}", val), - Ok(None) => println!(" No referrer stats for founder"), - Err(e) => println!(" ⚠ ReferrerStats query error: {}", e), - } - - // ═══════════════════════════════════════════════════════════════════ - // SECTION 13: Staking Score (People Chain - Cross-chain) - // ═══════════════════════════════════════════════════════════════════ - println!("\n═══ SECTION 13: Staking Score System ═══\n"); - - match people_storage_map(&people_api, "StakingScore", "StakingScores", &test_account).await { - Ok(Some(val)) => println!(" Test Wallet Staking Score: {:?}", val), - Ok(None) => println!(" Test Wallet Staking Score: 0 (not staking)"), - Err(e) => println!(" ⚠ StakingScore query error: {}", e), - } - - // Check if staking score bridge from relay is configured - match people_storage_value(&people_api, "StakingScore", "LastRelayUpdate").await { - Ok(Some(val)) => println!(" Last Relay Update: {:?}", val), - Ok(None) => println!(" Last Relay Update: None (no cross-chain data yet)"), - Err(_) => println!(" StakingScore: LastRelayUpdate storage not found"), - } - - // ═══════════════════════════════════════════════════════════════════ - // SECTION 14: Final Balances & Summary - // ═══════════════════════════════════════════════════════════════════ - println!("\n═══ SECTION 14: Final Summary ═══\n"); - - let final_relay = query_balance(&relay_api, &test_account).await?; - let final_ah = query_balance(&ah_api, &test_account).await?; - let final_people = query_balance(&people_api, &test_account).await?; - - // Re-check critical states for summary - let final_kyc = people_storage_map(&people_api, "IdentityKyc", "KycStatuses", &test_account) - .await - .ok() - .flatten(); - let final_nft = people_storage_map(&people_api, "Tiki", "CitizenNft", &test_account) - .await - .ok() - .flatten(); - let final_trust = people_storage_map(&people_api, "Trust", "TrustScores", &test_account) - .await - .ok() - .flatten(); - - let kyc_ok = final_kyc - .as_ref() - .map(|v| format!("{:?}", v).contains("Approved")) - .unwrap_or(false); - let nft_ok = final_nft.is_some(); - - println!("╔══════════════════════════════════════════════════════════════╗"); - println!("║ PEZKUWICHAIN TEST RESULTS SUMMARY ║"); - println!("╠══════════════════════════════════════════════════════════════╣"); - println!("║ ║"); - println!("║ spec_version: {} / {} / {} ║", relay_ver, ah_ver, people_ver); - println!("║ ║"); - println!("║ Balances (Test Wallet): ║"); - println!("║ Relay: {:>42} ║", format_hez(final_relay)); - println!("║ AH: {:>42} ║", format_hez(final_ah)); - println!("║ People: {:>42} ║", format_hez(final_people)); - println!("║ ║"); - println!( - "║ XCM Teleport: {} AH {} People ║", - if ah_received > 0 { "✓" } else { "✗" }, - if people_received > 0 { "✓" } else { "✗" } - ); - println!( - "║ Welati (KYC): {} ║", - if kyc_ok { "✓ Approved" } else { "✗ NOT Approved" } - ); - println!( - "║ Citizen NFT: {} ║", - if nft_ok { "✓ Minted " } else { "✗ NOT Minted " } - ); - println!( - "║ Trust Score: {:?} ║", - final_trust - .as_ref() - .map(|v| format!("{:?}", v)) - .unwrap_or_else(|| "0".to_string()) - ); - println!("║ ║"); - println!("╚══════════════════════════════════════════════════════════════╝"); - - println!("\n✓ COMPREHENSIVE TEST SUITE COMPLETED"); - - Ok(()) -} diff --git a/vendor/pezkuwi-subxt/subxt/examples/create_nft_collection.rs b/vendor/pezkuwi-subxt/subxt/examples/create_nft_collection.rs deleted file mode 100644 index dce1c162..00000000 --- a/vendor/pezkuwi-subxt/subxt/examples/create_nft_collection.rs +++ /dev/null @@ -1,322 +0,0 @@ -//! Create NFT Collection 0 on People Chain via XCM from Relay Chain -//! -//! This script sends XCM Transact messages from the Relay Chain (via sudo) -//! to the People Chain to: -//! 1. Create NFT Collection 0 using Nfts::force_create -//! 2. Mint NFT Item 0 in that collection for the founder -//! -//! Both calls are executed as XCM Transact with Superuser origin, wrapped -//! in sudo_unchecked_weight on the Relay Chain. -//! -//! Run with: -//! FOUNDER_MNEMONIC='foam hope ...' cargo run --release --example create_nft_collection - -#![allow(missing_docs)] -use pezkuwi_subxt::dynamic::Value; -use pezkuwi_subxt::utils::AccountId32; -use pezkuwi_subxt::{OnlineClient, PezkuwiConfig}; -use pezkuwi_subxt_signer::bip39::Mnemonic; -use pezkuwi_subxt_signer::sr25519::Keypair; -use scale_value::Composite; -use std::time::Duration; - -const RELAY_RPC: &str = "ws://217.77.6.126:9944"; -const PEOPLE_RPC: &str = "ws://217.77.6.126:41944"; -const PEOPLE_CHAIN_PARA_ID: u128 = 1004; - -/// Query a single-key storage map on the People Chain. -async fn query_storage_map( - api: &OnlineClient, - pallet: &str, - entry: &str, - key: u32, -) -> Result>, Box> { - let query = pezkuwi_subxt::dynamic::storage::<(u32,), Value>(pallet, entry); - let storage = api.storage().at_latest().await?; - match storage.entry(query)?.try_fetch((key,)).await? { - Some(val) => Ok(Some(val.decode()?)), - None => Ok(None), - } -} - -/// Query a double-key storage map on the People Chain. -async fn query_storage_double_map( - api: &OnlineClient, - pallet: &str, - entry: &str, - key1: u32, - key2: u32, -) -> Result>, Box> { - let query = pezkuwi_subxt::dynamic::storage::<(u32, u32), Value>(pallet, entry); - let storage = api.storage().at_latest().await?; - match storage.entry(query)?.try_fetch((key1, key2)).await? { - Some(val) => Ok(Some(val.decode()?)), - None => Ok(None), - } -} - -/// Query an AccountId-keyed storage map on the People Chain. -async fn query_storage_by_account( - api: &OnlineClient, - pallet: &str, - entry: &str, - account: &AccountId32, -) -> Result>, Box> { - let query = pezkuwi_subxt::dynamic::storage::<(AccountId32,), Value>(pallet, entry); - let storage = api.storage().at_latest().await?; - match storage.entry(query)?.try_fetch((account.clone(),)).await? { - Some(val) => Ok(Some(val.decode()?)), - None => Ok(None), - } -} - -#[tokio::main] -async fn main() -> Result<(), Box> { - println!("=== CREATE NFT COLLECTION ON PEOPLE CHAIN VIA XCM ===\n"); - - // Step 1: Load founder keypair from environment - let mnemonic_str = - std::env::var("FOUNDER_MNEMONIC").expect("FOUNDER_MNEMONIC environment variable required"); - let mnemonic = Mnemonic::parse(&mnemonic_str)?; - let founder_keypair = Keypair::from_phrase(&mnemonic, None)?; - let founder_account = AccountId32(founder_keypair.public_key().0); - println!("Founder account: {}", founder_account); - - // Step 2: Connect to Relay Chain and People Chain - println!("\nConnecting to Relay Chain at {} ...", RELAY_RPC); - let relay_api = OnlineClient::::from_insecure_url(RELAY_RPC).await?; - println!( - "Connected to Relay Chain (spec_version: {})", - relay_api.runtime_version().spec_version - ); - - println!("Connecting to People Chain at {} ...", PEOPLE_RPC); - let people_api = OnlineClient::::from_insecure_url(PEOPLE_RPC).await?; - println!( - "Connected to People Chain (spec_version: {})", - people_api.runtime_version().spec_version - ); - - // Step 3: Check if Collection 0 already exists - println!("\n--- Checking if Collection 0 already exists ---"); - match query_storage_map(&people_api, "Nfts", "Collection", 0).await? { - Some(_val) => { - println!("Collection 0 ALREADY EXISTS on People Chain!"); - println!("Skipping collection creation."); - }, - None => { - println!("Collection 0 does NOT exist. Creating...\n"); - - // Encode Nfts::force_create call bytes via People Chain metadata - let force_create = pezkuwi_subxt::dynamic::tx( - "Nfts", - "force_create", - Composite::unnamed([ - // owner: MultiAddress::Id(founder) - Value::unnamed_variant("Id", [Value::from_bytes(&founder_account.0)]), - // config: CollectionConfig { settings, max_supply, mint_settings } - Value::unnamed_composite([ - Value::u128(0), // settings: u64 - Value::unnamed_variant("None", []), // max_supply - Value::unnamed_composite([ - // mint_settings - Value::unnamed_variant("Issuer", []), // mint_type - Value::unnamed_variant("None", []), // price - Value::unnamed_variant("None", []), // start_block - Value::unnamed_variant("None", []), // end_block - Value::u128(0), // default_item_settings - ]), - ]), - ]), - ); - - let force_create_bytes = people_api.tx().call_data(&force_create)?; - println!( - "force_create encoded: {} bytes (0x{}...)", - force_create_bytes.len(), - hex::encode(&force_create_bytes[..force_create_bytes.len().min(16)]) - ); - - // Send force_create via XCM Transact from Relay Chain - let sudo_create = build_xcm_sudo_transact(&force_create_bytes); - - let call_bytes = relay_api.tx().call_data(&sudo_create)?; - println!( - "sudo XCM encoded: {} bytes (0x{}...)", - call_bytes.len(), - hex::encode(&call_bytes[..call_bytes.len().min(32)]) - ); - - println!("Submitting sudo XCM transact for force_create..."); - let create_progress = relay_api - .tx() - .sign_and_submit_then_watch_default(&sudo_create, &founder_keypair) - .await?; - - println!("Transaction submitted. Waiting for finalization..."); - let create_events = create_progress.wait_for_finalized_success().await?; - println!("Transaction finalized on Relay Chain!"); - - for event in create_events.iter() { - let event = event?; - let pallet = event.pallet_name(); - if pallet == "Sudo" || pallet == "XcmPallet" { - println!(" Event: {}::{}", pallet, event.variant_name()); - } - } - - println!("\nWaiting 18 seconds for XCM delivery..."); - tokio::time::sleep(Duration::from_secs(18)).await; - - match query_storage_map(&people_api, "Nfts", "Collection", 0).await? { - Some(_) => println!("Collection 0 created successfully!"), - None => { - println!("WARNING: Collection 0 NOT found yet."); - println!("Check People Chain logs. Continuing anyway..."); - }, - } - }, - } - - // Step 4: Check if NFT #0 already exists - println!("\n--- Checking if NFT #0 already exists ---"); - match query_storage_double_map(&people_api, "Nfts", "Item", 0, 0).await? { - Some(_val) => { - println!("NFT #0 ALREADY EXISTS in Collection 0!"); - println!("No minting needed."); - }, - None => { - println!("NFT #0 does NOT exist. Minting for founder...\n"); - - let force_mint = pezkuwi_subxt::dynamic::tx( - "Nfts", - "force_mint", - Composite::unnamed([ - Value::u128(0), // collection - Value::u128(0), // item - Value::unnamed_variant("Id", [Value::from_bytes(&founder_account.0)]), - Value::unnamed_composite([Value::u128(0)]), // item_config - ]), - ); - - let force_mint_bytes = people_api.tx().call_data(&force_mint)?; - println!( - "force_mint encoded: {} bytes (0x{}...)", - force_mint_bytes.len(), - hex::encode(&force_mint_bytes[..force_mint_bytes.len().min(16)]) - ); - - let sudo_mint = build_xcm_sudo_transact(&force_mint_bytes); - - println!("Submitting sudo XCM transact for force_mint..."); - let mint_progress = relay_api - .tx() - .sign_and_submit_then_watch_default(&sudo_mint, &founder_keypair) - .await?; - - println!("Transaction submitted. Waiting for finalization..."); - let mint_events = mint_progress.wait_for_finalized_success().await?; - println!("Transaction finalized on Relay Chain!"); - - for event in mint_events.iter() { - let event = event?; - let pallet = event.pallet_name(); - if pallet == "Sudo" || pallet == "XcmPallet" { - println!(" Event: {}::{}", pallet, event.variant_name()); - } - } - - println!("\nWaiting 18 seconds for XCM delivery..."); - tokio::time::sleep(Duration::from_secs(18)).await; - }, - } - - // Step 5: Final verification - println!("\n--- Final Verification ---"); - - match query_storage_map(&people_api, "Nfts", "Collection", 0).await? { - Some(val) => println!("Collection 0: EXISTS - {:?}", val), - None => println!("Collection 0: NOT FOUND"), - } - - match query_storage_double_map(&people_api, "Nfts", "Item", 0, 0).await? { - Some(val) => println!("NFT #0: EXISTS - {:?}", val), - None => println!("NFT #0: NOT FOUND"), - } - - match query_storage_by_account(&people_api, "Tiki", "CitizenNft", &founder_account).await? { - Some(val) => println!("Tiki CitizenNft for founder: {:?}", val), - None => { - println!("Tiki CitizenNft for founder: None"); - println!( - " (Expected - Tiki storage is populated by confirm_citizenship, not force_mint)" - ); - }, - } - - println!("\n=== NFT COLLECTION CREATION COMPLETE ==="); - Ok(()) -} - -/// Build an XCM V3 Transact message wrapped in sudo_unchecked_weight. -/// -/// Uses the same proven pattern as the runtime-upgrade tool. -fn build_xcm_sudo_transact(encoded_call: &[u8]) -> pezkuwi_subxt_core::tx::payload::DynamicPayload { - let dest = Value::unnamed_variant( - "V3", - vec![Value::named_composite([ - ("parents", Value::u128(0)), - ( - "interior", - Value::unnamed_variant( - "X1", - vec![Value::unnamed_variant( - "Teyrchain", - vec![Value::u128(PEOPLE_CHAIN_PARA_ID)], - )], - ), - ), - ])], - ); - - let message = Value::unnamed_variant( - "V3", - vec![Value::unnamed_composite(vec![ - Value::named_variant( - "UnpaidExecution", - [ - ("weight_limit", Value::unnamed_variant("Unlimited", vec![])), - ("check_origin", Value::unnamed_variant("None", vec![])), - ], - ), - Value::named_variant( - "Transact", - [ - ("origin_kind", Value::unnamed_variant("Superuser", vec![])), - ( - "require_weight_at_most", - Value::named_composite([ - ("ref_time", Value::u128(5_000_000_000u128)), - ("proof_size", Value::u128(500_000u128)), - ]), - ), - ("call", Value::from_bytes(encoded_call)), - ], - ), - ])], - ); - - let xcm_send = pezkuwi_subxt::dynamic::tx("XcmPallet", "send", vec![dest, message]); - - pezkuwi_subxt::dynamic::tx( - "Sudo", - "sudo_unchecked_weight", - vec![ - xcm_send.into_value(), - Value::named_composite([ - ("ref_time", Value::u128(1u128)), - ("proof_size", Value::u128(1u128)), - ]), - ], - ) -}