827c13b69e
dont build netstack in CI additional rust 2024 fixes fixes removed temp.rs first round of cleanup removed duplicated NS types moved gateway probe to the monorepo
208 lines
5.6 KiB
Rust
208 lines
5.6 KiB
Rust
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
use cosmwasm_std::testing::{MockApi, MockQuerier, MockStorage, message_info};
|
|
use cosmwasm_std::{
|
|
Addr, BankMsg, CosmosMsg, Decimal, Empty, Env, MemoryStorage, MessageInfo, Order, OwnedDeps,
|
|
Response, StdResult, Storage, coins,
|
|
};
|
|
use cw_storage_plus::{KeyDeserialize, Map, Prefix, PrimaryKey};
|
|
use nym_contracts_common::events::may_find_attribute;
|
|
use rand::{RngCore, SeedableRng};
|
|
use rand_chacha::ChaCha20Rng;
|
|
use serde::Serialize;
|
|
use serde::de::DeserializeOwned;
|
|
use std::fmt::Debug;
|
|
use std::str::FromStr;
|
|
|
|
pub const TEST_DENOM: &str = "unym";
|
|
pub const TEST_PREFIX: &str = "n";
|
|
|
|
pub trait FindAttribute {
|
|
fn attribute<E, S>(&self, event_type: E, attribute: &str) -> String
|
|
where
|
|
E: Into<Option<S>>,
|
|
S: Into<String>;
|
|
|
|
fn any_attribute(&self, attribute: &str) -> String {
|
|
self.attribute::<_, String>(None, attribute)
|
|
}
|
|
|
|
fn any_parsed_attribute<T>(&self, attribute: &str) -> T
|
|
where
|
|
T: FromStr,
|
|
<T as FromStr>::Err: Debug,
|
|
{
|
|
self.parsed_attribute::<_, String, T>(None, attribute)
|
|
}
|
|
|
|
fn parsed_attribute<E, S, T>(&self, event_type: E, attribute: &str) -> T
|
|
where
|
|
E: Into<Option<S>>,
|
|
S: Into<String>,
|
|
T: FromStr,
|
|
<T as FromStr>::Err: Debug;
|
|
|
|
fn decimal<E, S>(&self, event_type: E, attribute: &str) -> Decimal
|
|
where
|
|
E: Into<Option<S>>,
|
|
S: Into<String>,
|
|
{
|
|
self.parsed_attribute(event_type, attribute)
|
|
}
|
|
}
|
|
|
|
#[track_caller]
|
|
pub fn find_attribute<S: Into<String>>(
|
|
event_type: Option<S>,
|
|
attribute: &str,
|
|
response: &Response,
|
|
) -> String {
|
|
let event_type = event_type.map(Into::into);
|
|
for event in &response.events {
|
|
if let Some(typ) = &event_type {
|
|
if &event.ty != typ {
|
|
continue;
|
|
}
|
|
}
|
|
if let Some(attr) = may_find_attribute(event, attribute) {
|
|
return attr;
|
|
}
|
|
}
|
|
// this is only used in tests so panic here is fine
|
|
panic!("did not find the attribute")
|
|
}
|
|
|
|
impl FindAttribute for Response {
|
|
fn attribute<E, S>(&self, event_type: E, attribute: &str) -> String
|
|
where
|
|
E: Into<Option<S>>,
|
|
S: Into<String>,
|
|
{
|
|
find_attribute(event_type.into(), attribute, self)
|
|
}
|
|
|
|
fn parsed_attribute<E, S, T>(&self, event_type: E, attribute: &str) -> T
|
|
where
|
|
E: Into<Option<S>>,
|
|
S: Into<String>,
|
|
T: FromStr,
|
|
<T as FromStr>::Err: Debug,
|
|
{
|
|
find_attribute(event_type.into(), attribute, self)
|
|
.parse()
|
|
.unwrap()
|
|
}
|
|
}
|
|
|
|
pub fn mock_api() -> MockApi {
|
|
MockApi::default().with_prefix(TEST_PREFIX)
|
|
}
|
|
|
|
pub fn mock_dependencies() -> OwnedDeps<MemoryStorage, MockApi, MockQuerier<Empty>> {
|
|
OwnedDeps {
|
|
storage: MockStorage::default(),
|
|
api: mock_api(),
|
|
querier: MockQuerier::default(),
|
|
custom_query_type: Default::default(),
|
|
}
|
|
}
|
|
|
|
pub fn test_rng() -> ChaCha20Rng {
|
|
let dummy_seed = [42u8; 32];
|
|
rand_chacha::ChaCha20Rng::from_seed(dummy_seed)
|
|
}
|
|
|
|
pub fn deps_with_balance(env: &Env) -> OwnedDeps<MemoryStorage, MockApi, MockQuerier<Empty>> {
|
|
let mut deps = mock_dependencies();
|
|
deps.querier = MockQuerier::<Empty>::new(&[(
|
|
env.contract.address.as_str(),
|
|
coins(100000000000, TEST_DENOM).as_slice(),
|
|
)]);
|
|
deps
|
|
}
|
|
|
|
pub fn generate_sorted_addresses(n: usize) -> Vec<Addr> {
|
|
let mut rng = test_rng();
|
|
let mut addrs = Vec::with_capacity(n);
|
|
for i in 0..n {
|
|
addrs.push(mock_api().addr_make(&format!("addr{i}{}", rng.next_u64())));
|
|
}
|
|
addrs.sort();
|
|
addrs
|
|
}
|
|
|
|
pub fn addr<S: AsRef<str>>(raw: S) -> Addr {
|
|
mock_api().addr_make(raw.as_ref())
|
|
}
|
|
|
|
pub fn sender<S: AsRef<str>>(raw: S) -> MessageInfo {
|
|
message_info(&addr(raw), &[])
|
|
}
|
|
|
|
pub trait ExtractBankMsg {
|
|
fn unwrap_bank_msg(self) -> Option<BankMsg>;
|
|
}
|
|
|
|
impl ExtractBankMsg for Response {
|
|
fn unwrap_bank_msg(self) -> Option<BankMsg> {
|
|
for msg in self.messages {
|
|
match msg.msg {
|
|
CosmosMsg::Bank(bank_msg) => return Some(bank_msg),
|
|
_ => continue,
|
|
}
|
|
}
|
|
|
|
None
|
|
}
|
|
}
|
|
|
|
pub trait FullReader<'a> {
|
|
type Key;
|
|
type Value: Serialize + DeserializeOwned;
|
|
|
|
fn all_values(&self, store: &dyn Storage) -> StdResult<Vec<Self::Value>>;
|
|
|
|
fn all_key_values(&self, store: &dyn Storage) -> StdResult<Vec<(Self::Key, Self::Value)>>;
|
|
}
|
|
|
|
impl<'a, K, T> FullReader<'a> for Map<K, T>
|
|
where
|
|
T: Serialize + DeserializeOwned,
|
|
K: PrimaryKey<'a> + KeyDeserialize,
|
|
K::Output: 'static,
|
|
{
|
|
type Key = K::Output;
|
|
type Value = T;
|
|
|
|
fn all_values(&self, store: &dyn Storage) -> StdResult<Vec<Self::Value>> {
|
|
self.range(store, None, None, Order::Ascending)
|
|
.map(|record| record.map(|r| r.1))
|
|
.collect()
|
|
}
|
|
|
|
fn all_key_values(&self, store: &dyn Storage) -> StdResult<Vec<(Self::Key, Self::Value)>> {
|
|
self.range(store, None, None, Order::Ascending).collect()
|
|
}
|
|
}
|
|
|
|
impl<'a, K, T, B> FullReader<'a> for Prefix<K, T, B>
|
|
where
|
|
K: KeyDeserialize + 'static,
|
|
T: Serialize + DeserializeOwned,
|
|
B: PrimaryKey<'a>,
|
|
{
|
|
type Key = K::Output;
|
|
type Value = T;
|
|
|
|
fn all_values(&self, store: &dyn Storage) -> StdResult<Vec<Self::Value>> {
|
|
self.range(store, None, None, Order::Ascending)
|
|
.map(|record| record.map(|r| r.1))
|
|
.collect()
|
|
}
|
|
|
|
fn all_key_values(&self, store: &dyn Storage) -> StdResult<Vec<(Self::Key, Self::Value)>> {
|
|
self.range(store, None, None, Order::Ascending).collect()
|
|
}
|
|
}
|