glin_contracts/
chain_info.rs1use anyhow::{Context, Result};
4use subxt::dynamic;
5use subxt_core::storage;
6
7use glin_client::GlinClient;
8
9#[derive(Debug, Clone)]
11pub struct ContractInfo {
12 pub code_hash: [u8; 32],
13 pub storage_deposit: u128,
14}
15
16pub async fn get_contract_info(
18 client: &GlinClient,
19 contract_address: &str,
20) -> Result<ContractInfo> {
21 let address_bytes = parse_address(contract_address)?;
23
24 let storage_addr = dynamic::storage(
26 "Contracts",
27 "ContractInfoOf",
28 vec![dynamic::Value::from_bytes(address_bytes)],
29 );
30
31 let lookup_bytes = storage::get_address_bytes(&storage_addr, &client.metadata())
33 .context("Failed to encode storage address")?;
34
35 let raw_bytes = client
37 .storage()
38 .at_latest()
39 .await?
40 .fetch_raw(lookup_bytes)
41 .await
42 .context("Failed to fetch contract info")?
43 .ok_or_else(|| {
44 anyhow::anyhow!("Contract not found at address: {}", contract_address)
45 })?;
46
47 decode_contract_info_from_bytes(&raw_bytes)
49}
50
51fn decode_contract_info_from_bytes(encoded: &[u8]) -> Result<ContractInfo> {
56 use scale::Decode;
57
58 if encoded.len() < 32 {
67 anyhow::bail!(
68 "Encoded ContractInfo too short: {} bytes (expected at least 32)",
69 encoded.len()
70 );
71 }
72
73 let mut code_hash = [0u8; 32];
74 code_hash.copy_from_slice(&encoded[0..32]);
75
76 let mut cursor = &encoded[32..];
78 let storage_deposit = u128::decode(&mut cursor)
79 .context("Failed to decode storage_deposit from ContractInfo")?;
80
81 Ok(ContractInfo {
82 code_hash,
83 storage_deposit,
84 })
85}
86
87fn parse_address(address: &str) -> Result<Vec<u8>> {
89 let address = address.strip_prefix("0x").unwrap_or(address);
91
92 if let Ok(bytes) = hex::decode(address) {
94 if bytes.len() == 32 {
95 return Ok(bytes);
96 }
97 }
98
99 use subxt::utils::AccountId32;
101 use std::str::FromStr;
102
103 let account = AccountId32::from_str(address)
104 .context("Invalid contract address format (expected hex or SS58)")?;
105
106 Ok(account.0.to_vec())
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn test_parse_hex_address() {
115 let hex_addr = "0x1234567890123456789012345678901234567890123456789012345678901234";
116 let result = parse_address(hex_addr);
117 assert!(result.is_ok());
118 assert_eq!(result.unwrap().len(), 32);
119 }
120
121 #[test]
122 fn test_parse_address_without_prefix() {
123 let hex_addr = "1234567890123456789012345678901234567890123456789012345678901234";
124 let result = parse_address(hex_addr);
125 assert!(result.is_ok());
126 assert_eq!(result.unwrap().len(), 32);
127 }
128}