use cosmwasm_std::{Coin, StdError, StdResult, Uint128};
use regex::Regex;
pub fn coin_from_str(s: &str) -> Coin {
let idx = s
.char_indices()
.find(|(_, c)| !c.is_digit(10))
.map(|(idx, _)| idx)
.unwrap_or(s.len());
let amount: Uint128 = s[..idx].parse::<u128>().unwrap().into();
let denom = s[idx..].to_string();
Coin { denom, amount }
}
pub fn validate_denom(input: &str) -> StdResult<()> {
let re = Regex::new(r"^[a-zA-Z][a-zA-Z0-9/:._-]{2,127}$").unwrap();
if re.is_match(input) {
Ok(())
} else {
Err(StdError::generic_err(
"Provided string is not a valid CosmosSDK denom.",
))
}
}
#[cfg(test)]
mod tests {
use test_case::test_case;
use super::*;
#[test]
fn test_coin_from_sdk_str() {
let coin = coin_from_str("100000000000000000000gamm/pool/1");
assert_eq!(coin.amount, Uint128::from(100000000000000000000u128));
assert_eq!(coin.denom, "gamm/pool/1");
}
#[test_case("gamm/pool/1" => Ok(()); "valid osmosis LP denom")]
#[test_case("uatom" => Ok(()); "valid uatom denom")]
#[test_case("ibc/C140AFD542AE77BD7DCC83F13FDD8C5E5BB8C4929785E6EC2F4C636F98F17901" => Ok(()); "valid IBC denom")]
#[test_case("IBC/C140AFD542AE77BD7DCC83F13FDD8C5E5BB8C4929785E6EC2F4C636F98F17901" => Ok(()); "valid IBC denom capital IBC")]
#[test_case("factory/osmo1g3kmqpp8608szfp0pdag3r6z85npph7wmccat8lgl3mp407kv73qlj7qwp/VaultToken/1/14d/ATOM/OSMO" => Ok(()); "valid token factory denom")]
#[test_case("test:test/test-test.test_test" => Ok(()); "all valid separators")]
#[test_case("test test" => Err(StdError::generic_err("Provided string is not a valid CosmosSDK denom.")); "invalid separator space")]
#[test_case("test/test " => Err(StdError::generic_err("Provided string is not a valid CosmosSDK denom.")); "trailing space")]
#[test_case(" test/test" => Err(StdError::generic_err("Provided string is not a valid CosmosSDK denom.")); "leading space")]
#[test_case("/test/test" => Err(StdError::generic_err("Provided string is not a valid CosmosSDK denom.")); "leading separator")]
#[test_case("2test/test" => Err(StdError::generic_err("Provided string is not a valid CosmosSDK denom.")); "leading number")]
#[test_case("te" => Err(StdError::generic_err("Provided string is not a valid CosmosSDK denom.")); "too short")]
#[test_case("tes" => Ok(()); "min length")]
#[test_case("t//" => Ok(()); "min length with two consecutive separators")]
#[test_case("testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest" => Ok(()); "max length")]
#[test_case("testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttestt" => Err(StdError::generic_err("Provided string is not a valid CosmosSDK denom.")); "too long")]
fn test_validate_denom(input: &str) -> StdResult<()> {
validate_denom(input)
}
}