Skip to content

Commit

Permalink
Merge pull request #2 from InjectiveLabs/no_regex
Browse files Browse the repository at this point in the history
Removed regex
  • Loading branch information
albertchon authored Nov 25, 2022
2 parents 6ea5015 + 873e13f commit dad0b1e
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 84 deletions.
33 changes: 0 additions & 33 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion contracts/cw20-adapter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,5 @@ cw20 = { workspace = true }
cw-storage-plus = { workspace = true }
thiserror = { workspace = true }
cw-item-set = { workspace = true }
regex = { workspace = true }
injective-cosmwasm = { workspace = true }
serde = { workspace = true }
138 changes: 100 additions & 38 deletions contracts/cw20-adapter/src/common.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,78 @@
use crate::error::ContractError;
use crate::state::CW20_CONTRACTS;
use cosmwasm_std::{Addr, Coin, CosmosMsg, DepsMut, Env, QuerierWrapper, StdResult};
use cosmwasm_std::{Addr, Coin, CosmosMsg, DepsMut, Env, QuerierWrapper, StdResult, Uint128};
use cw20::{Cw20QueryMsg, TokenInfoResponse};

use injective_cosmwasm::{create_new_denom_msg, InjectiveMsgWrapper, InjectiveQuerier, InjectiveQueryWrapper};
use regex::Regex;
use serde::{Deserialize, Serialize};

use crate::error::ContractError;
use crate::state::CW20_CONTRACTS;

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AdapterDenom {
pub adapter_addr: String,
pub cw20_addr: String,
}

const FACTORY_PREFIX: &str = "factory/";

impl AdapterDenom {
pub fn new<S>(denom: S) -> Result<Self, ContractError>
where
S: Into<String>,
{
let denom = denom.into();

if denom.len() != 93 {
return Err(ContractError::NotCw20Address);
}
if !denom.starts_with(FACTORY_PREFIX) {
return Err(ContractError::NotCw20Address);
}
// adapter address starts from index 8 and ends at 50 since "factory/" is 8 characters
// and inj addresses have 42 characters
let adapter_part = &denom[8..50];
// remaining portion is the cw20 address
let cw20_part = &denom[51..];
Ok::<Result<AdapterDenom, ContractError>, ContractError>(AdapterDenom::from_components(adapter_part, cw20_part))?
}

pub fn from_components<S>(adapter_addr: S, cw20_addr: S) -> Result<Self, ContractError>
where
S: Into<String>,
{
let adapter_addr = adapter_addr.into();
let cw20_addr = cw20_addr.into();
if !adapter_addr.chars().all(char::is_alphanumeric) {
return Err(ContractError::NotCw20Address);
}
if !cw20_addr.chars().all(char::is_alphanumeric) {
return Err(ContractError::NotCw20Address);
}
Ok(AdapterDenom { adapter_addr, cw20_addr })
}

pub fn as_string(&self) -> String {
get_denom_from_str(&self.adapter_addr, &self.cw20_addr)
}
}

// 42 since the string length of inj addresses is 42, e.g. "inj1mtl2fykeceen4c74ddldrtdkq6fvnz79n8c592"
pub fn denom_parser() -> Regex {
Regex::new(r"factory/(\w{42})/(\w{42})").unwrap()
pub struct AdapterCoin {
pub amount: Uint128,
pub denom: AdapterDenom,
}

pub fn get_cw20_address_from_denom(parser: &Regex, denom: &str) -> Option<String> {
let captures = parser.captures(denom)?;
let cw20addr = captures.get(2)?;
Some(cw20addr.as_str().to_string())
impl AdapterCoin {
pub fn as_coin(&self) -> Coin {
Coin::new(self.amount.u128(), self.denom.as_string())
}
}

pub fn get_denom(adapter_address: &Addr, cw20addr: &Addr) -> String {
format!("factory/{}/{}", adapter_address, cw20addr)
get_denom_from_str(adapter_address.as_str(), cw20addr.as_str())
}

fn get_denom_from_str(adapter_address: &str, cw20addr: &str) -> String {
format!("{}{}/{}", FACTORY_PREFIX, adapter_address, cw20addr)
}

pub fn query_denom_creation_fee(querier_wrapper: &QuerierWrapper<InjectiveQueryWrapper>) -> StdResult<Vec<Coin>> {
Expand Down Expand Up @@ -74,52 +129,59 @@ mod tests {

#[test]
fn it_returns_true_on_correct_token_factory_denom() {
assert!(
denom_parser().is_match("factory/inj1pvrwmjuusn9wh34j7y520g8gumuy9xtlt6xtzw/inj1n0qvel0zfmsxu3q8q23xzjvuwfxn0ydlhgyh7h"),
"input was not treated as token factory denom"
)
AdapterDenom::new("factory/inj1pvrwmjuusn9wh34j7y520g8gumuy9xtlt6xtzw/inj1n0qvel0zfmsxu3q8q23xzjvuwfxn0ydlhgyh7h")
.expect("input was not treated as token factory denom");
}

#[test]
fn it_returns_false_for_non_token_factory_denom() {
assert!(
!denom_parser().is_match(".factory/inj1pvrwmjuusn9wh34j7y520g8gumuy9xtlt6xtzw/inj1n0qvel0zfmsxu3q8q23xzjvuwfxn0ydlhgyh7"),
"input was treated as token factory denom"
)
AdapterDenom::new(".factory/inj1pvrwmjuusn9wh34j7y520g8gumuy9xtlt6xtzw/inj1n0qvel0zfmsxu3q8q23xzjvuwfxn0ydlhgyh7")
.expect_err("input was treated as token factory denom");
}

#[test]
fn it_returns_false_for_non_token_factory_denom_2() {
AdapterDenom::new("factory/inj1pvrwmjuusn9wh34j7y520g8gumuy9xtlt6xtz/winj1n0qvel0zfmsxu3q8q23xzjvuwfxn0ydlhgyh7h")
.expect_err("input was treated as token factory denom");
}

#[test]
fn it_returns_false_for_non_token_factory_denom_3() {
AdapterDenom::new("factory/inj1pvrwm_uusn9wh34j7y520g8gumuy9xtlt6xtzw/inj1n0qvel0zfmsxu3q8q23xzjvuwfxn0ydlhgyh7")
.expect_err("input was treated as token factory denom");
}

#[test]
fn it_returns_false_for_non_token_factory_denom_4() {
AdapterDenom::new("factory/inj1pvrwmuusn9wh34j7y520g8gumuy9xtlt6xtzw/inj1n0qvel0zfmsxu3q8q23xzjvuwfxn0ydlhgyh7/sddsjsdk")
.expect_err("input was treated as token factory denom");
}

#[test]
fn it_returns_cw_20_address_for_token_factory_denom() {
let denom = AdapterDenom::new("factory/inj1pvrwmjuusn9wh34j7y520g8gumuy9xtlt6xtzw/inj1n0qvel0zfmsxu3q8q23xzjvuwfxn0ydlhgyh7h").unwrap();
assert_eq!(
denom.adapter_addr, "inj1pvrwmjuusn9wh34j7y520g8gumuy9xtlt6xtzw",
"wrong cw20 address returned"
);
assert_eq!(
get_cw20_address_from_denom(
&denom_parser(),
"factory/inj1pvrwmjuusn9wh34j7y520g8gumuy9xtlt6xtzw/inj1n0qvel0zfmsxu3q8q23xzjvuwfxn0ydlhgyh7h",
)
.unwrap(),
"inj1n0qvel0zfmsxu3q8q23xzjvuwfxn0ydlhgyh7h",
denom.cw20_addr, "inj1n0qvel0zfmsxu3q8q23xzjvuwfxn0ydlhgyh7h",
"wrong cw20 address returned"
)
}

#[test]
fn it_returns_none_cw_20_address_for_non_token_factory_denom() {
assert!(
get_cw20_address_from_denom(
&denom_parser(),
"factory/inj1pvrwmjuusn9wh34j7y520g8gumuy9xtlt6xtzw/inj1n0qvel0zfmsxu3q8q23xzjvuwfxn0ydlhgyh7",
)
.is_none(),
"cw20 address returned"
)
let denom = AdapterDenom::new("factory/inj1pvrwmjuusn9wh34j7y520g8gumuy9xtlt6xtzw/inj1n0qvel0zfmsxu3q8q23xzjvuwfxn0ydlhgyh7").unwrap_err();
assert_eq!(denom, ContractError::NotCw20Address, "cw20 address returned")
}

#[test]
fn it_returns_denom() {
let denom =
AdapterDenom::from_components("inj1pvrwmjuusn9wh34j7y520g8gumuy9xtlt6xtzw", "inj1n0qvel0zfmsxu3q8q23xzjvuwfxn0ydlhgyh7h").unwrap();
assert_eq!(
get_denom(
&Addr::unchecked("inj1pvrwmjuusn9wh34j7y520g8gumuy9xtlt6xtzw".to_string()),
&Addr::unchecked("inj1n0qvel0zfmsxu3q8q23xzjvuwfxn0ydlhgyh7h".to_string()),
),
denom.as_string(),
"factory/inj1pvrwmjuusn9wh34j7y520g8gumuy9xtlt6xtzw/inj1n0qvel0zfmsxu3q8q23xzjvuwfxn0ydlhgyh7h",
"wrong denom returned"
)
Expand Down
26 changes: 15 additions & 11 deletions contracts/cw20-adapter/src/execute_redeem.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use cosmwasm_std::{to_binary, Binary, Coin, DepsMut, Env, MessageInfo, Response, WasmMsg};
use cosmwasm_std::{to_binary, Binary, DepsMut, Env, MessageInfo, Response, WasmMsg};
use cw20::Cw20ExecuteMsg;
use injective_cosmwasm::{create_burn_tokens_msg, InjectiveMsgWrapper, InjectiveQueryWrapper};

use crate::common::{denom_parser, get_cw20_address_from_denom};
use crate::common::{AdapterCoin, AdapterDenom};
use crate::error::ContractError;
use crate::state::CW20_CONTRACTS;

Expand All @@ -18,26 +18,30 @@ pub fn handle_redeem_msg(
if info.funds.len() > 1 {
return Err(ContractError::SuperfluousFundsProvided);
}
let denom_parser = denom_parser();
let tokens_to_exchange = info
.funds
.iter()
.find_map(|c| -> Option<Coin> {
if denom_parser.is_match(&c.denom) {
Some(c.clone())
} else {
None
.find_map(|c| -> Option<AdapterCoin> {
match AdapterDenom::new(&c.denom) {
Ok(denom) => Some(AdapterCoin { amount: c.amount, denom }),
Err(_) => None,
}
// if denom_parser.is_match(&c.denom) {
// Some(c.clone())
// } else {
// None
// }
})
.ok_or(ContractError::NoRegisteredTokensProvided)?;

let cw20_addr = get_cw20_address_from_denom(&denom_parser, &tokens_to_exchange.denom).ok_or(ContractError::NoRegisteredTokensProvided)?;
let is_contract_registered = CW20_CONTRACTS.contains(deps.storage, cw20_addr.as_str());
let cw20_addr = tokens_to_exchange.denom.cw20_addr.clone();
// let cw20_addr = get_cw20_address_from_denom(&denom_parser, &tokens_to_exchange.denom).ok_or(ContractError::NoRegisteredTokensProvided)?;
let is_contract_registered = CW20_CONTRACTS.contains(deps.storage, &tokens_to_exchange.denom.cw20_addr);
if !is_contract_registered {
return Err(ContractError::NoRegisteredTokensProvided);
}

let burn_tf_tokens_message = create_burn_tokens_msg(env.contract.address, tokens_to_exchange.clone());
let burn_tf_tokens_message = create_burn_tokens_msg(env.contract.address, tokens_to_exchange.as_coin());

let cw20_message: WasmMsg = match submessage {
None => WasmMsg::Execute {
Expand Down
3 changes: 2 additions & 1 deletion contracts/cw20-adapter/src/execute_register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ pub fn handle_register_msg(
}

let mut provided_funds = info.funds.iter();
for required_coin in required_funds {

for required_coin in &required_funds {
let pf = provided_funds
.find(|c| -> bool { c.denom == required_coin.denom })
.ok_or(ContractError::NotEnoughBalanceToPayDenomCreationFee)?;
Expand Down

0 comments on commit dad0b1e

Please sign in to comment.