Skip to content

Commit

Permalink
feat: add cw-vault-standard-test-helpers crate
Browse files Browse the repository at this point in the history
  • Loading branch information
pacmanifold committed Aug 12, 2023
1 parent f8a6a16 commit 2248bd7
Show file tree
Hide file tree
Showing 10 changed files with 378 additions and 129 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

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

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[workspace]
members = [
"cw-vault-standard",
"test-helpers",
"mock-vault",
]

Expand All @@ -25,9 +26,10 @@ cw2 = "1.1.0"
mars-owner = "2.0.0"
osmosis-std = "0.16.1"
cw-vault-standard = { path = "./cw-vault-standard" }
cw-vault-standard-test-helpers = { path = "./test-helpers" }

# dev dependencies
cw-it = "0.1.0"
cw-it = "0.1"
proptest = "1.2.0"


Expand Down
1 change: 1 addition & 0 deletions mock-vault/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ cw-vault-standard = { workspace = true }
cw-storage-plus = { workspace = true }
cosmwasm-schema = { workspace = true }
cw-it = { workspace = true, features = ["multi-test"] }
cw-vault-standard-test-helpers = { workspace = true }

[dev-dependencies]
proptest = { workspace = true }
143 changes: 22 additions & 121 deletions mock-vault/src/test_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use cw_it::robot::TestRobot;
use cw_it::test_tube::{Account, Module, SigningAccount, Wasm};
use cw_it::traits::CwItRunner;
use cw_it::{Artifact, ContractType, TestRunner};
use cw_vault_standard_test_helpers::traits::CwVaultStandardRobot;

pub const MOCK_VAULT_TOKEN_SUBDENOM: &str = "vault-token";

Expand Down Expand Up @@ -70,44 +71,32 @@ pub fn assert_almost_eq(left: Decimal, right: Decimal, max_rel_diff: &str) {
}
}

/// A trait implementing common methods for testing vault contracts.
pub trait VaultRobot<'a, R>: TestRobot<'a, R>
where
R: CwItRunner<'a> + 'a,
{
/// Create a new default instance of the robot.
fn default_vault_robot(
runner: &'a R,
admin: &'a SigningAccount,
base_token: String,
vault_token: String,
vault_addr: String,
) -> DefaultVaultRobot<'a, R> {
DefaultVaultRobot {
runner,
admin,
base_token,
vault_token,
vault_addr,
}
}

/// Returns the base token.
fn base_token(&self) -> &str;
/// A simple testing robot for testing vault contracts.
pub struct MockVaultRobot<'a, R: CwItRunner<'a>> {
pub runner: &'a R,
pub admin: &'a SigningAccount,
pub vault_addr: String,
}

/// Returns the vault token.
fn vault_token(&self) -> &str;
impl<'a, R: CwItRunner<'a>> CwVaultStandardRobot<'a, R> for MockVaultRobot<'a, R> {
fn vault_addr(&self) -> String {
self.vault_addr.clone()
}

/// Returns the vault address.
fn vault_addr(&self) -> &str;
fn query_base_token_balance(&self, address: impl Into<String>) -> Uint128 {
let base_token_denom = self.base_token();
self.query_native_token_balance(address, base_token_denom)
}
}

impl<'a, R: CwItRunner<'a>> MockVaultRobot<'a, R> {
/// Uploads and instantiates the vault contract and returns a new instance of the robot.
fn instantiate(
pub fn instantiate(
runner: &'a R,
admin: &'a SigningAccount,
base_token: &str,
denom_creation_fee: Option<Coin>,
) -> DefaultVaultRobot<'a, R>
) -> MockVaultRobot<'a, R>
where
Self: Sized,
{
Expand All @@ -132,104 +121,16 @@ where
.data
.address;

let vault_token = format!("factory/{}/{}", vault_addr, MOCK_VAULT_TOKEN_SUBDENOM);

Self::default_vault_robot(
MockVaultRobot {
runner,
admin,
base_token.to_string(),
vault_token,
vault_addr,
)
}

/// Deposit base tokens into the vault and return a reference to the robot.
fn deposit_to_vault(&self, amount: impl Into<Uint128>, signer: &SigningAccount) -> &Self {
let amount: Uint128 = amount.into();

let msg = crate::msg::ExecuteMsg::Deposit {
amount,
recipient: None,
};
self.wasm()
.execute(
self.vault_addr(),
&msg,
&[coin(amount.u128(), self.base_token())],
signer,
)
.unwrap();

self
}

/// Deposit base tokens into the vault without filling the native token funds field and return
/// a reference to the robot. This is useful for depositing cw20 tokens.
fn deposit_cw20_to_vault(&self, amount: impl Into<Uint128>, signer: &SigningAccount) -> &Self {
let amount: Uint128 = amount.into();

let msg = crate::msg::ExecuteMsg::Deposit {
amount,
recipient: None,
};
self.wasm()
.execute(self.vault_addr(), &msg, &[], signer)
.unwrap();

self
}

/// Redeem vault tokens from the vault and return a reference to the robot.
fn redeem_from_vault(&self, amount: impl Into<Uint128>, signer: &SigningAccount) -> &Self {
let amount: Uint128 = amount.into();

let msg = crate::msg::ExecuteMsg::Redeem {
amount,
recipient: None,
};
self.wasm()
.execute(
self.vault_addr(),
&msg,
&[coin(amount.u128(), self.vault_token())],
signer,
)
.unwrap();

self
}

/// Query the vault token balance of the given account.
fn query_vault_token_balance(&self, account: impl Into<String>) -> Uint128 {
self.query_native_token_balance(account, self.vault_token())
}
}
}

/// A simple testing robot for testing vault contracts.
pub struct DefaultVaultRobot<'a, R: CwItRunner<'a>> {
pub runner: &'a R,
pub admin: &'a SigningAccount,
pub vault_addr: String,
pub base_token: String,
pub vault_token: String,
}

impl<'a, R: CwItRunner<'a>> TestRobot<'a, R> for DefaultVaultRobot<'a, R> {
impl<'a, R: CwItRunner<'a>> TestRobot<'a, R> for MockVaultRobot<'a, R> {
fn runner(&self) -> &'a R {
self.runner
}
}

impl<'a, R: CwItRunner<'a>> VaultRobot<'a, R> for DefaultVaultRobot<'a, R> {
fn base_token(&self) -> &str {
&self.base_token
}

fn vault_token(&self) -> &str {
&self.vault_token
}

fn vault_addr(&self) -> &str {
&self.vault_addr
}
}
13 changes: 6 additions & 7 deletions mock-vault/tests/property_tests.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use cosmwasm_std::coin;
use cosmwasm_std::Decimal;
use cw_it::robot::TestRobot;
use cw_it::test_tube::Account;
use cw_it::traits::CwItRunner;
use cw_mock_vault::test_helpers;
use cw_mock_vault::test_helpers::VaultRobot;
use cw_vault_standard_test_helpers::traits::CwVaultStandardRobot;
use proptest::prelude::*;
use proptest::proptest;

Expand All @@ -30,17 +29,17 @@ proptest! {
let admin = &accs[0];
let user1 = &accs[1];
let user2 = &accs[2];
let robot = test_helpers::DefaultVaultRobot::instantiate(&runner, admin, "uosmo", Some(coin(10000000, "uosmo")));
let base_token = "uosmo";
let robot = test_helpers::MockVaultRobot::instantiate(&runner, admin, base_token, Some(coin(10000000, "uosmo")));

if init_amount != 0 {
robot
.send_native_tokens(admin, &robot.vault_addr, init_amount, "uosmo")
.deposit_to_vault(init_amount, admin);
.deposit(init_amount, None, &[coin(init_amount, base_token)], &admin);
}

robot
.deposit_to_vault(amount1, user1)
.deposit_to_vault(amount2, user2);
.deposit(amount1, None, &[coin(amount1, base_token)], user1)
.deposit(amount2, None, &[coin(amount2, base_token)], user2);

let user1_vault_token_balance = robot.query_vault_token_balance(user1.address());
let user2_vault_token_balance = robot.query_vault_token_balance(user2.address());
Expand Down
17 changes: 17 additions & 0 deletions test-helpers/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "cw-vault-standard-test-helpers"
version = { workspace = true }
edition = "2018"

[features]
default = ["lockup", "force-unlock"]
lockup = ["cw-vault-standard/lockup"]
force-unlock = ["cw-vault-standard/force-unlock"]



[dependencies]
cosmwasm-std = { workspace = true }
cw-vault-standard = { workspace = true }
cw-utils = { workspace = true }
cw-it = { workspace = true }
1 change: 1 addition & 0 deletions test-helpers/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod traits;
78 changes: 78 additions & 0 deletions test-helpers/src/traits/force_unlock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use cosmwasm_std::Uint128;
use cw_it::test_tube::{Runner, SigningAccount};

use cw_vault_standard::extensions::force_unlock::ForceUnlockExecuteMsg;
use cw_vault_standard::msg::VaultStandardExecuteMsg as ExecuteMsg;
use cw_vault_standard::ExtensionExecuteMsg;

use super::CwVaultStandardRobot;

pub trait ForceUnlockVaultRobot<'a, R: Runner<'a> + 'a>: CwVaultStandardRobot<'a, R> {
fn force_redeem(
&self,
amount: impl Into<Uint128>,
recipient: Option<String>,
signer: &SigningAccount,
) -> &Self {
self.wasm()
.execute(
&self.vault_addr(),
&ExecuteMsg::VaultExtension(ExtensionExecuteMsg::ForceUnlock(
ForceUnlockExecuteMsg::ForceRedeem {
recipient,
amount: amount.into(),
},
)),
&[],
signer,
)
.unwrap();
self
}

fn force_withdraw_unlocking(
&self,
lockup_id: u64,
amount: Option<impl Into<Uint128>>,
recipient: Option<String>,
signer: &SigningAccount,
) -> &Self {
self.wasm()
.execute(
&self.vault_addr(),
&ExecuteMsg::VaultExtension(ExtensionExecuteMsg::ForceUnlock(
ForceUnlockExecuteMsg::ForceWithdrawUnlocking {
amount: amount.map(Into::into),
lockup_id,
recipient,
},
)),
&[],
signer,
)
.unwrap();
self
}

fn update_force_withdraw_whitelist(
&self,
signer: &SigningAccount,
add_addresses: Vec<String>,
remove_addresses: Vec<String>,
) -> &Self {
self.wasm()
.execute(
&self.vault_addr(),
&ExecuteMsg::VaultExtension(ExtensionExecuteMsg::ForceUnlock(
ForceUnlockExecuteMsg::UpdateForceWithdrawWhitelist {
add_addresses,
remove_addresses,
},
)),
&[],
signer,
)
.unwrap();
self
}
}
Loading

0 comments on commit 2248bd7

Please sign in to comment.