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(|| anyhow::anyhow!("Contract not found at address: {}", contract_address))?;
44
45 decode_contract_info_from_bytes(&raw_bytes)
47}
48
49fn decode_contract_info_from_bytes(encoded: &[u8]) -> Result<ContractInfo> {
54 use scale::Decode;
55
56 if encoded.len() < 32 {
65 anyhow::bail!(
66 "Encoded ContractInfo too short: {} bytes (expected at least 32)",
67 encoded.len()
68 );
69 }
70
71 let mut code_hash = [0u8; 32];
72 code_hash.copy_from_slice(&encoded[0..32]);
73
74 let mut cursor = &encoded[32..];
76 let storage_deposit =
77 u128::decode(&mut cursor).context("Failed to decode storage_deposit from ContractInfo")?;
78
79 Ok(ContractInfo {
80 code_hash,
81 storage_deposit,
82 })
83}
84
85fn parse_address(address: &str) -> Result<Vec<u8>> {
87 let address = address.strip_prefix("0x").unwrap_or(address);
89
90 if let Ok(bytes) = hex::decode(address) {
92 if bytes.len() == 32 {
93 return Ok(bytes);
94 }
95 }
96
97 use std::str::FromStr;
99 use subxt::utils::AccountId32;
100
101 let account = AccountId32::from_str(address)
102 .context("Invalid contract address format (expected hex or SS58)")?;
103
104 Ok(account.0.to_vec())
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn test_parse_hex_address() {
113 let hex_addr = "0x1234567890123456789012345678901234567890123456789012345678901234";
114 let result = parse_address(hex_addr);
115 assert!(result.is_ok());
116 assert_eq!(result.unwrap().len(), 32);
117 }
118
119 #[test]
120 fn test_parse_address_without_prefix() {
121 let hex_addr = "1234567890123456789012345678901234567890123456789012345678901234";
122 let result = parse_address(hex_addr);
123 assert!(result.is_ok());
124 assert_eq!(result.unwrap().len(), 32);
125 }
126}