glin_client/
lib.rs

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