avail_rust_client/
extensions.rs

1use crate::{
2	UserError,
3	subxt_signer::{SecretUri, sr25519::Keypair},
4};
5use avail_rust_core::{
6	AccountId, H256,
7	ext::subxt_core::utils::AccountId32,
8	utils::{account_id_from_slice, account_id_from_str},
9};
10
11/// Extension helpers for working with `H256` values.
12pub trait H256Ext {
13	/// Parses a string (with or without `0x`) into an `H256`.
14	///
15	/// # Arguments
16	/// * `s` - Hexadecimal string representation of the hash, optionally prefixed with `0x`.
17	///
18	/// # Returns
19	/// Returns the decoded `H256` value.
20	///
21	/// # Errors
22	/// Returns an error if the string is not 64 characters (after removing prefix) or contains invalid hex.
23	fn from_str(s: &str) -> Result<H256, String>;
24}
25
26impl H256Ext for H256 {
27	fn from_str(s: &str) -> Result<H256, String> {
28		let mut s = s;
29		if s.starts_with("0x") {
30			s = &s[2..];
31		}
32
33		if s.len() != 64 {
34			let msg = std::format!(
35				"Failed to convert string to H256. Expected 64 bytes got {}. Input string: {}",
36				s.len(),
37				s
38			);
39			return Err(msg);
40		}
41
42		let block_hash = const_hex::decode(s).map_err(|e| e.to_string())?;
43		let block_hash = TryInto::<[u8; 32]>::try_into(block_hash);
44		match block_hash {
45			Ok(v) => Ok(H256(v)),
46			Err(e) => {
47				let msg = std::format!("Failed to covert decoded string to H256. Input {:?}", e);
48				Err(msg)
49			},
50		}
51	}
52}
53
54/// Extension helpers for constructing `AccountId` values.
55pub trait AccountIdExt {
56	/// Parses an address string into an `AccountId`.
57	///
58	/// # Arguments
59	/// * `value` - SS58-encoded address string.
60	///
61	/// # Returns
62	/// Returns the decoded `AccountId`.
63	///
64	/// # Errors
65	/// Returns an error if the address string is malformed or uses an invalid SS58 format.
66	fn from_str(value: &str) -> Result<AccountId, String>;
67
68	/// Decodes an `AccountId` from raw bytes.
69	///
70	/// # Arguments
71	/// * `value` - Raw 32-byte account identifier.
72	///
73	/// # Returns
74	/// Returns the decoded `AccountId`.
75	///
76	/// # Errors
77	/// Returns an error if the byte slice is not exactly 32 bytes.
78	fn from_slice(value: &[u8]) -> Result<AccountId, String>;
79
80	/// Returns the zero `AccountId`.
81	///
82	/// # Returns
83	/// Returns an `AccountId` with all bytes set to zero.
84	fn default() -> AccountId;
85}
86
87impl AccountIdExt for AccountId {
88	fn from_str(value: &str) -> Result<AccountId, String> {
89		account_id_from_str(value)
90	}
91
92	fn from_slice(value: &[u8]) -> Result<AccountId, String> {
93		account_id_from_slice(value)
94	}
95
96	fn default() -> AccountId {
97		AccountId32([0u8; 32])
98	}
99}
100
101/// Extension helpers for parsing signer URIs.
102pub trait SecretUriExt {
103	/// Parses a secret URI string into a signer `SecretUri`.
104	///
105	/// # Arguments
106	/// * `value` - Secret URI string (e.g., seed phrase, mnemonic, or raw secret).
107	///
108	/// # Returns
109	/// Returns the parsed `SecretUri`.
110	///
111	/// # Errors
112	/// Returns a `UserError` if the URI format is invalid or cannot be parsed.
113	fn from_str(value: &str) -> Result<SecretUri, UserError>;
114}
115
116impl SecretUriExt for SecretUri {
117	fn from_str(value: &str) -> Result<SecretUri, UserError> {
118		value.parse().map_err(|e| UserError::Other(std::format!("{:?}", e)))
119	}
120}
121
122/// Extension helpers for building and inspecting sr25519 keypairs.
123pub trait KeypairExt {
124	/// Parses a secret URI string into a sr25519 keypair.
125	///
126	/// # Arguments
127	/// * `value` - Secret URI string (e.g., seed phrase or mnemonic).
128	///
129	/// # Returns
130	/// Returns the derived sr25519 keypair.
131	///
132	/// # Errors
133	/// Returns a `UserError` if the URI cannot be parsed or keypair derivation fails.
134	fn from_str(value: &str) -> Result<Keypair, UserError>;
135
136	/// Derives the associated `AccountId` from the public key.
137	///
138	/// # Returns
139	/// Returns the `AccountId` corresponding to this keypair's public key.
140	fn account_id(&self) -> AccountId;
141}
142
143impl KeypairExt for Keypair {
144	fn from_str(value: &str) -> Result<Keypair, UserError> {
145		let secret_uri = SecretUri::from_str(value).map_err(|e| UserError::Other(e.to_string()))?;
146		let keypair = Keypair::from_uri(&secret_uri).map_err(|e| UserError::Other(e.to_string()))?;
147		Ok(keypair)
148	}
149
150	fn account_id(&self) -> AccountId {
151		self.public_key().to_account_id()
152	}
153}