glin_client/
lib.rs

1//! GLIN Network Client
2//!
3//! Core blockchain client for connecting to GLIN Network and performing RPC operations.
4
5use anyhow::Result;
6use subxt::{OnlineClient, PolkadotConfig};
7use subxt::backend::legacy::LegacyRpcMethods;
8use subxt::backend::rpc::RpcClient;
9use subxt_signer::sr25519::Keypair;
10
11pub type GlinConfig = PolkadotConfig;
12pub type GlinClient = OnlineClient<GlinConfig>;
13
14/// Create a client connection to GLIN network
15///
16/// # Example
17/// ```no_run
18/// use glin_client::create_client;
19///
20/// #[tokio::main]
21/// async fn main() -> anyhow::Result<()> {
22///     let client = create_client("wss://testnet.glin.ai").await?;
23///     Ok(())
24/// }
25/// ```
26pub async fn create_client(rpc_url: &str) -> Result<GlinClient> {
27    let client = OnlineClient::<GlinConfig>::from_url(rpc_url).await?;
28    Ok(client)
29}
30
31/// Create legacy RPC methods for direct RPC calls
32pub async fn create_rpc_client(rpc_url: &str) -> Result<LegacyRpcMethods<GlinConfig>> {
33    let rpc_client = RpcClient::from_url(rpc_url).await?;
34    Ok(LegacyRpcMethods::<GlinConfig>::new(rpc_client))
35}
36
37/// Get account keypair from name (for development)
38///
39/// Supported names: alice, bob, charlie, dave, eve, ferdie
40pub fn get_dev_account(name: &str) -> Result<Keypair> {
41    use subxt_signer::sr25519::dev;
42
43    let keypair = match name.to_lowercase().as_str() {
44        "alice" => dev::alice(),
45        "bob" => dev::bob(),
46        "charlie" => dev::charlie(),
47        "dave" => dev::dave(),
48        "eve" => dev::eve(),
49        "ferdie" => dev::ferdie(),
50        _ => anyhow::bail!(
51            "Unknown dev account: {}. Use alice, bob, charlie, dave, eve, or ferdie",
52            name
53        ),
54    };
55
56    Ok(keypair)
57}
58
59/// Load account from seed phrase or secret URI
60///
61/// Supports:
62/// - Secret URI format (e.g., `//Alice`)
63/// - BIP39 mnemonic phrases
64pub fn account_from_seed(seed: &str) -> Result<Keypair> {
65    use subxt_signer::SecretUri;
66    use std::str::FromStr;
67
68    // Try as secret URI first (supports //Alice format)
69    if let Ok(uri) = SecretUri::from_str(seed) {
70        return Keypair::from_uri(&uri)
71            .map_err(|e| anyhow::anyhow!("Failed to create keypair from URI: {:?}", e));
72    }
73
74    // Try as mnemonic phrase
75    use subxt_signer::bip39::Mnemonic;
76    if let Ok(mnemonic) = Mnemonic::parse(seed) {
77        return Keypair::from_phrase(&mnemonic, None)
78            .map_err(|e| anyhow::anyhow!("Failed to create keypair from phrase: {:?}", e));
79    }
80
81    anyhow::bail!("Invalid seed format. Use a secret URI (e.g., //Alice) or mnemonic phrase")
82}
83
84/// Get account address from keypair
85///
86/// Returns SS58-formatted address string
87pub fn get_address(keypair: &Keypair) -> String {
88    use subxt::utils::AccountId32;
89
90    let account_id: AccountId32 = keypair.public_key().into();
91    format!("{:?}", account_id)
92}
93
94#[cfg(test)]
95mod tests {
96    use super::*;
97
98    #[test]
99    fn test_dev_accounts() {
100        let alice = get_dev_account("alice");
101        assert!(alice.is_ok());
102
103        let invalid = get_dev_account("invalid");
104        assert!(invalid.is_err());
105    }
106
107    #[test]
108    fn test_secret_uri() {
109        let keypair = account_from_seed("//Alice");
110        assert!(keypair.is_ok());
111    }
112}