Files
pezkuwi-sdk/vendor/pezkuwi-subxt/subxt/examples/set_pool_metadata.rs
T
pezkuwichain 0e809c3a74 sec: remove hardcoded mnemonics, add mainnet tools and subxt examples
- Replace all hardcoded wallet mnemonics with env variable reads
- Add comprehensive e2e test suite (tools/e2e-test/)
- Add zagros validator management tools
- Add subxt examples for mainnet operations
- Update CRITICAL_STATE with zagros testnet and mainnet status
- Fix people chain spec ID and chainspec build script
2026-02-16 08:18:26 +03:00

192 lines
4.9 KiB
Rust

//! Set metadata (names) for existing nomination pools on Asset Hub
//!
//! Environment variables:
//! WALLETS_FILE - JSON file with wallet list (required)
//! ASSET_HUB_RPC - Asset Hub RPC endpoint (default: ws://217.77.6.126:40944)
//! START_ID - First pool ID to set metadata for (default: 1)
//!
//! Wallets JSON format:
//! [
//! { "name": "Pool Name", "mnemonic": "word1 word2 ...", "ss58": "5..." },
//! ...
//! ]
//!
//! Run with:
//! WALLETS_FILE="wallets.json" \
//! cargo run --release -p pezkuwi-subxt --example set_pool_metadata
#![allow(missing_docs)]
use pezkuwi_subxt::dynamic::Value;
use pezkuwi_subxt::{OnlineClient, PezkuwiConfig};
use pezkuwi_subxt_signer::bip39::Mnemonic;
use pezkuwi_subxt_signer::sr25519::Keypair;
use std::str::FromStr;
const DEFAULT_ASSET_HUB_RPC: &str = "ws://217.77.6.126:40944";
#[derive(serde::Deserialize)]
struct WalletInfo {
name: String,
mnemonic: String,
#[allow(dead_code)]
ss58: String,
}
fn load_wallets() -> Vec<WalletInfo> {
let path = std::env::var("WALLETS_FILE").expect(
"WALLETS_FILE environment variable required. \
Point it to a JSON file with wallet entries: \
[{\"name\": \"...\", \"mnemonic\": \"...\", \"ss58\": \"5...\"}]",
);
let data = std::fs::read_to_string(&path)
.unwrap_or_else(|e| panic!("Failed to read wallets file '{}': {}", path, e));
serde_json::from_str(&data)
.unwrap_or_else(|e| panic!("Failed to parse wallets file '{}': {}", path, e))
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== SET POOL METADATA ===\n");
let start_id: u32 = std::env::var("START_ID")
.unwrap_or_else(|_| "1".to_string())
.parse()?;
let rpc =
std::env::var("ASSET_HUB_RPC").unwrap_or_else(|_| DEFAULT_ASSET_HUB_RPC.to_string());
let api = OnlineClient::<PezkuwiConfig>::from_insecure_url(&rpc).await?;
println!("Connected to Asset Hub!\n");
// First, query LastPoolId to confirm
let last_pool_query =
pezkuwi_subxt::dynamic::storage::<(), Value>("NominationPools", "LastPoolId");
let storage = api.storage().at_latest().await?;
let last_pool = storage.entry(last_pool_query)?.try_fetch(()).await?;
if let Some(val) = last_pool {
let decoded = val.decode()?;
println!("LastPoolId raw value: {:?}", decoded);
println!(
"LastPoolId as_u128: {:?}",
decoded.as_u128()
);
}
let wallets = load_wallets();
for (i, wallet) in wallets.iter().enumerate() {
let pool_id = start_id + i as u32;
println!(
"--- [{}/{}] Pool {} -> '{}' ---",
i + 1,
wallets.len(),
pool_id,
wallet.name
);
let mnemonic = Mnemonic::from_str(&wallet.mnemonic)?;
let keypair = Keypair::from_phrase(&mnemonic, None)?;
println!(" Signer: {}", keypair.public_key().to_account_id());
let name_bytes = wallet.name.as_bytes().to_vec();
let metadata_tx = pezkuwi_subxt::dynamic::tx(
"NominationPools",
"set_metadata",
vec![Value::u128(pool_id as u128), Value::from_bytes(&name_bytes)],
);
let mut ok = false;
for attempt in 0..3 {
if attempt > 0 {
println!(" Retry attempt {}...", attempt + 1);
tokio::time::sleep(std::time::Duration::from_secs(18)).await;
}
let tx_progress = match api
.tx()
.sign_and_submit_then_watch_default(&metadata_tx, &keypair)
.await
{
Ok(p) => p,
Err(e) => {
println!(" SUBMIT ERROR (attempt {}): {}", attempt + 1, e);
continue;
},
};
println!(
" TX: 0x{}",
hex::encode(tx_progress.extrinsic_hash().as_ref())
);
use pezkuwi_subxt::tx::TxStatus;
let mut progress = tx_progress;
loop {
let status = progress.next().await;
match status {
Some(Ok(TxStatus::InBestBlock(details))) => {
match details.wait_for_success().await {
Ok(events) => {
println!(" SUCCESS!");
for event in events.iter() {
if let Ok(ev) = event {
println!(
" {}::{}",
ev.pallet_name(),
ev.variant_name()
);
}
}
ok = true;
},
Err(e) => {
println!(" DISPATCH ERROR: {}", e);
},
}
break;
},
Some(Ok(TxStatus::Error { message })) => {
println!(" TX ERROR: {}", message);
break;
},
Some(Ok(TxStatus::Invalid { message })) => {
println!(" TX INVALID: {}", message);
break;
},
Some(Ok(TxStatus::Dropped { message })) => {
println!(" TX DROPPED: {}", message);
break;
},
Some(Err(e)) => {
println!(" STREAM ERROR: {}", e);
break;
},
None => {
println!(" STREAM ENDED");
break;
},
_ => {},
}
}
if ok {
break;
}
}
if ok {
println!(" Pool {} named '{}'\n", pool_id, wallet.name);
} else {
println!(" FAILED to name pool {}\n", pool_id);
}
// Wait between txs
if i + 1 < wallets.len() {
tokio::time::sleep(std::time::Duration::from_secs(18)).await;
}
}
println!("\n=== DONE ===");
Ok(())
}