neutron_sdk/interchain_queries/v045/
helpers.rs

1use crate::bindings::types::KVKey;
2use crate::errors::error::NeutronResult;
3use crate::interchain_queries::helpers::{decode_and_convert, length_prefix};
4use crate::interchain_queries::types::AddressBytes;
5use crate::interchain_queries::v045::types::{
6    BALANCES_PREFIX, BANK_STORE_KEY, DELEGATION_KEY, FEE_POOL_KEY, PARAMS_STORE_DELIMITER,
7    PROPOSALS_KEY_PREFIX, SUPPLY_PREFIX, UNBONDING_DELEGATION_KEY, VALIDATORS_KEY,
8    VALIDATOR_SIGNING_INFO_KEY, WASM_CONTRACT_STORE_PREFIX,
9};
10use crate::NeutronError;
11use cosmos_sdk_proto::cosmos::staking::v1beta1::Commission as ValidatorCommission;
12use cosmwasm_std::{Binary, Decimal, Uint128};
13use std::str::{from_utf8, FromStr};
14
15use super::types::{GOV_STORE_KEY, VOTES_KEY_PREFIX};
16
17/// Creates KV key to get **module** param by **key**
18pub fn create_params_store_key(module: &str, key: &str) -> Vec<u8> {
19    let mut s = String::with_capacity(module.len() + 1 + key.len());
20    s.push_str(module);
21    s.push_str(PARAMS_STORE_DELIMITER);
22    s.push_str(key);
23
24    s.into_bytes()
25}
26
27/// Creates balances Cosmos-SDK storage prefix for account with **addr**
28/// <https://github.com/cosmos/cosmos-sdk/blob/ad9e5620fb3445c716e9de45cfcdb56e8f1745bf/x/bank/types/key.go#L55>
29pub fn create_account_balances_prefix<AddrBytes: AsRef<[u8]>>(
30    addr: AddrBytes,
31) -> NeutronResult<Vec<u8>> {
32    let mut prefix: Vec<u8> = vec![BALANCES_PREFIX];
33    prefix.extend_from_slice(length_prefix(addr)?.as_slice());
34
35    Ok(prefix)
36}
37
38/// Creates **denom** balance Cosmos-SDK storage key for account with **addr**
39pub fn create_account_denom_balance_key<AddrBytes: AsRef<[u8]>, S: AsRef<str>>(
40    addr: AddrBytes,
41    denom: S,
42) -> NeutronResult<Vec<u8>> {
43    let mut account_balance_key = create_account_balances_prefix(addr)?;
44    account_balance_key.extend_from_slice(denom.as_ref().as_bytes());
45
46    Ok(account_balance_key)
47}
48
49/// Creates keys for an Interchain Query to get balance of account on remote chain for list of denoms
50///
51/// * **addr** address of an account on remote chain for which you want to get balances;
52/// * **denoms** denominations of the coins for which you want to get balance;
53pub fn create_balances_query_keys(addr: String, denoms: Vec<String>) -> NeutronResult<Vec<KVKey>> {
54    let converted_addr_bytes = decode_and_convert(addr.as_str())?;
55    let mut kv_keys: Vec<KVKey> = Vec::with_capacity(denoms.len());
56
57    for denom in denoms {
58        let balance_key = create_account_denom_balance_key(&converted_addr_bytes, denom)?;
59
60        let kv_key = KVKey {
61            path: BANK_STORE_KEY.to_string(),
62            key: Binary::new(balance_key),
63        };
64
65        kv_keys.push(kv_key)
66    }
67    Ok(kv_keys)
68}
69
70/// Deconstructs a storage key for an **account** balance of a particular **denom**.
71/// Returns two values: **address** of an account and **denom**
72pub fn deconstruct_account_denom_balance_key<Key: IntoIterator<Item = u8>>(
73    key: Key,
74) -> NeutronResult<(AddressBytes, String)> {
75    let mut key = key.into_iter();
76
77    // the first element must be BALANCES_PREFIX
78    let prefix = key
79        .next()
80        .ok_or(NeutronError::AccountDenomBalanceKeyDeconstructionError(
81            "invalid key length".to_string(),
82        ))?;
83    if prefix != BALANCES_PREFIX {
84        return Err(NeutronError::AccountDenomBalanceKeyDeconstructionError(
85            format!(
86                "first element in key does not equal to BALANCES_PREFIX: {:?} != {:?}",
87                prefix, BALANCES_PREFIX
88            )
89            .to_string(),
90        ));
91    }
92
93    // next we try read address bytes
94    let address_length =
95        key.next()
96            .ok_or(NeutronError::AccountDenomBalanceKeyDeconstructionError(
97                "invalid key length".to_string(),
98            ))?;
99    let address: AddressBytes = (&mut key).take(address_length as usize).collect();
100    if address.len() != address_length as usize {
101        return Err(NeutronError::AccountDenomBalanceKeyDeconstructionError(
102            "address length in key is invalid".to_string(),
103        ));
104    }
105
106    // and the rest should be denom
107    let denom = String::from_utf8(key.collect::<Vec<u8>>())?;
108    if denom.is_empty() {
109        return Err(NeutronError::AccountDenomBalanceKeyDeconstructionError(
110            "denom in key can't be empty".to_string(),
111        ));
112    }
113
114    Ok((address, denom))
115}
116
117/// Creates **denom** balance Cosmos-SDK storage key for account with **addr**
118pub fn create_denom_balance_key<AddrBytes: AsRef<[u8]>, S: AsRef<str>>(
119    addr: AddrBytes,
120    denom: S,
121) -> NeutronResult<Vec<u8>> {
122    let mut account_balance_key = create_account_balances_prefix(addr)?;
123    account_balance_key.extend_from_slice(denom.as_ref().as_bytes());
124
125    Ok(account_balance_key)
126}
127
128/// Creates **denom** total Cosmos-SDK storage key for bank module
129pub fn create_total_denom_key<S: AsRef<str>>(denom: S) -> NeutronResult<Vec<u8>> {
130    let mut total_supply: Vec<u8> = vec![SUPPLY_PREFIX];
131    total_supply.extend_from_slice(denom.as_ref().as_bytes());
132
133    Ok(total_supply)
134}
135
136/// Creates delegations Cosmos-SDK storage prefix for delegator with **delegator_addr**
137/// <https://github.com/cosmos/cosmos-sdk/blob/ad9e5620fb3445c716e9de45cfcdb56e8f1745bf/x/staking/types/keys.go#L181>
138pub fn create_delegations_key<AddrBytes: AsRef<[u8]>>(
139    delegator_address: AddrBytes,
140) -> NeutronResult<Vec<u8>> {
141    let mut key: Vec<u8> = vec![DELEGATION_KEY];
142    key.extend_from_slice(length_prefix(delegator_address)?.as_slice());
143
144    Ok(key)
145}
146
147/// Creates Cosmos-SDK storage key for delegation between delegator with **delegator_addr** and validator with **validator_addr**
148/// <https://github.com/cosmos/cosmos-sdk/blob/ad9e5620fb3445c716e9de45cfcdb56e8f1745bf/x/staking/types/keys.go#L176>
149pub fn create_delegation_key<AddrBytes: AsRef<[u8]>>(
150    delegator_address: AddrBytes,
151    validator_address: AddrBytes,
152) -> NeutronResult<Vec<u8>> {
153    let mut delegations_key: Vec<u8> = create_delegations_key(delegator_address)?;
154    delegations_key.extend_from_slice(length_prefix(validator_address)?.as_slice());
155
156    Ok(delegations_key)
157}
158
159/// Creates unbonding delegations Cosmos-SDK storage prefix for delegator with **delegator_addr**
160/// <https://github.com/cosmos/cosmos-sdk/blob/ad9e5620fb3445c716e9de45cfcdb56e8f1745bf/x/staking/types/keys.go#L209>
161pub fn create_unbonding_delegations_key<AddrBytes: AsRef<[u8]>>(
162    delegator_address: AddrBytes,
163) -> NeutronResult<Vec<u8>> {
164    let mut key: Vec<u8> = vec![UNBONDING_DELEGATION_KEY];
165    key.extend_from_slice(length_prefix(delegator_address)?.as_slice());
166
167    Ok(key)
168}
169
170/// Creates Cosmos-SDK storage key for unbonding delegation between delegator with **delegator_addr** and validator with **validator_addr**
171/// <https://github.com/cosmos/cosmos-sdk/blob/ad9e5620fb3445c716e9de45cfcdb56e8f1745bf/x/staking/types/keys.go#L187>
172pub fn create_unbonding_delegation_key<AddrBytes: AsRef<[u8]>>(
173    delegator_address: AddrBytes,
174    validator_address: AddrBytes,
175) -> NeutronResult<Vec<u8>> {
176    let mut unbonding_delegations_key: Vec<u8> =
177        create_unbonding_delegations_key(delegator_address)?;
178    unbonding_delegations_key.extend_from_slice(length_prefix(validator_address)?.as_slice());
179
180    Ok(unbonding_delegations_key)
181}
182
183/// Creates Cosmos-SDK storage key for validator with **operator_address**
184/// <https://github.com/cosmos/cosmos-sdk/blob/f2d94445c0f5f52cf5ed999b81048b575de94964/x/staking/types/keys.go#L55>
185pub fn create_validator_key<AddrBytes: AsRef<[u8]>>(
186    operator_address: AddrBytes,
187) -> NeutronResult<Vec<u8>> {
188    let mut key: Vec<u8> = vec![VALIDATORS_KEY];
189    key.extend_from_slice(length_prefix(operator_address)?.as_slice());
190
191    Ok(key)
192}
193
194/// Creates Cosmos-SDK storage key for validator with **valcons_addr**
195/// <https://github.com/cosmos/cosmos-sdk/blob/35ae2c4c72d4aeb33447d5a7af23ca47f786606e/x/slashing/types/keys.go#L34>
196pub fn create_validator_signing_info_key<AddrBytes: AsRef<[u8]>>(
197    valcons_addr: AddrBytes,
198) -> NeutronResult<Vec<u8>> {
199    let mut key: Vec<u8> = vec![VALIDATOR_SIGNING_INFO_KEY];
200    key.extend_from_slice(length_prefix(valcons_addr)?.as_slice());
201
202    Ok(key)
203}
204
205/// Creates Wasm key for contract state.
206/// This function is similar to
207/// <https://github.com/CosmWasm/wasmd/blob/e6d451bf9dd96a555b10e72aa3c0f6b820d34684/x/wasm/types/keys.go#L59>,
208/// but it also concatenates resulting contract store prefix with contract's storage key,
209/// resulting in a complete storage key.
210pub fn create_wasm_contract_store_key<AddrBytes: AsRef<[u8]>, Key: AsRef<[u8]>>(
211    contract_address: AddrBytes,
212    key: Key,
213) -> NeutronResult<Vec<u8>> {
214    let mut prefix: Vec<u8> = vec![WASM_CONTRACT_STORE_PREFIX];
215    prefix.extend_from_slice(contract_address.as_ref());
216    prefix.extend_from_slice(key.as_ref());
217
218    Ok(prefix)
219}
220
221/// Creates Cosmos-SDK distribution key for fee pool
222/// <https://github.com/cosmos/cosmos-sdk/blob/35ae2c4c72d4aeb33447d5a7af23ca47f786606e/x/distribution/types/keys.go#L46>
223pub fn create_fee_pool_key() -> NeutronResult<Vec<u8>> {
224    let key: Vec<u8> = vec![FEE_POOL_KEY];
225
226    Ok(key)
227}
228
229/// Creates Cosmos-SDK governance key for proposal with specific id
230/// <https://github.com/cosmos/cosmos-sdk/blob/35ae2c4c72d4aeb33447d5a7af23ca47f786606e/x/gov/types/keys.go#L41>
231pub fn create_gov_proposal_key(proposal_id: u64) -> NeutronResult<Vec<u8>> {
232    let mut key: Vec<u8> = vec![PROPOSALS_KEY_PREFIX];
233    key.extend_from_slice(proposal_id.to_be_bytes().as_slice());
234
235    Ok(key)
236}
237
238/// Creates Cosmos-SDK storage keys for list of proposals
239pub fn create_gov_proposal_keys(proposals_ids: Vec<u64>) -> NeutronResult<Vec<KVKey>> {
240    let mut kv_keys: Vec<KVKey> = Vec::with_capacity(proposals_ids.len());
241
242    for id in proposals_ids {
243        let kv_key = KVKey {
244            path: GOV_STORE_KEY.to_string(),
245            key: Binary::new(create_gov_proposal_key(id)?),
246        };
247
248        kv_keys.push(kv_key)
249    }
250
251    Ok(kv_keys)
252}
253
254/// Creates Cosmos-SDK governance key for votes for proposal with specific id
255/// <https://github.com/cosmos/cosmos-sdk/blob/35ae2c4c72d4aeb33447d5a7af23ca47f786606e/x/gov/types/keys.go#L48>
256pub fn create_gov_proposal_votes_key(proposal_id: u64) -> NeutronResult<Vec<u8>> {
257    let mut key: Vec<u8> = vec![VOTES_KEY_PREFIX];
258    key.extend_from_slice(proposal_id.to_be_bytes().as_slice());
259
260    Ok(key)
261}
262
263/// Creates Cosmos-SDK storage key for specific voter on specific proposal
264/// <https://github.com/cosmos/cosmos-sdk/blob/35ae2c4c72d4aeb33447d5a7af23ca47f786606e/x/gov/types/keys.go#L106>
265pub fn create_gov_proposal_voter_votes_key<AddrBytes: AsRef<[u8]>>(
266    proposal_id: u64,
267    voter_address: AddrBytes,
268) -> NeutronResult<Vec<u8>> {
269    let mut votes_key: Vec<u8> = create_gov_proposal_votes_key(proposal_id)?;
270    votes_key.extend_from_slice(length_prefix(voter_address)?.as_slice());
271
272    Ok(votes_key)
273}
274
275/// Creates Cosmos-SDK storage keys for list of voters on list of proposals
276pub fn create_gov_proposals_voters_votes_keys(
277    proposals_ids: Vec<u64>,
278    voters: Vec<String>,
279) -> NeutronResult<Vec<KVKey>> {
280    let mut kv_keys: Vec<KVKey> = Vec::with_capacity(voters.len() * proposals_ids.len());
281
282    for voter in voters {
283        let voter_addr = decode_and_convert(&voter)?;
284
285        for proposal_id in proposals_ids.clone() {
286            let kv_key = KVKey {
287                path: GOV_STORE_KEY.to_string(),
288                key: Binary::new(create_gov_proposal_voter_votes_key(
289                    proposal_id,
290                    &voter_addr,
291                )?),
292            };
293
294            kv_keys.push(kv_key)
295        }
296    }
297
298    Ok(kv_keys)
299}
300
301/// Returns validator max change rate
302pub fn get_max_change_rate(commission: &Option<ValidatorCommission>) -> Option<Decimal> {
303    let commission_rates = commission.as_ref().map(|v| v.commission_rates.as_ref())?;
304    commission_rates
305        .map(|v| Decimal::new(Uint128::from_str(v.max_change_rate.as_str()).unwrap_or_default()))
306}
307
308/// Returns validator max rate
309pub fn get_max_rate(commission: &Option<ValidatorCommission>) -> Option<Decimal> {
310    let commission_rates = commission.as_ref().map(|v| v.commission_rates.as_ref())?;
311    commission_rates
312        .map(|v| Decimal::new(Uint128::from_str(v.max_rate.as_str()).unwrap_or_default()))
313}
314
315/// Returns current validator rate
316pub fn get_rate(commission: &Option<ValidatorCommission>) -> Option<Decimal> {
317    let commission_rates = commission.as_ref().map(|v| v.commission_rates.as_ref())?;
318    commission_rates.map(|v| Decimal::new(Uint128::from_str(v.rate.as_str()).unwrap_or_default()))
319}
320
321/// Returns current validator rate
322pub fn get_update_time(commission: &Option<ValidatorCommission>) -> Option<u64> {
323    let commission_rates = commission.as_ref().map(|v| v.update_time.as_ref())?;
324    commission_rates.map(|v| v.seconds as u64)
325}
326
327/// Returns denom for total supply from StorageValue key
328pub fn get_total_supply_denom(denom: &Binary) -> Option<String> {
329    if denom.len() < 2 {
330        return None;
331    }
332    if denom[0] == SUPPLY_PREFIX {
333        // We need to cut off first byte because it contains storage key following by denom.
334        return from_utf8(&denom[1..]).ok().map(|d| d.to_string());
335    }
336
337    None
338}
339
340/// Returns total supply amount from StorageValue key
341pub fn get_total_supply_amount(amount: &Binary) -> Option<Uint128> {
342    from_utf8(amount).ok().map(|a| Uint128::from_str(a).ok())?
343}