Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions contracts/yieldaggregator-bonus/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ pub enum ContractError {

#[error("Already staked")]
AlreadyStaked {},

#[error("Insufficient budget to register bonus window")]
InsufficientBudget {},

#[error("Bonus window not ended yet")]
BonusWindowNotEndedYet
}

impl From<FromUtf8Error> for ContractError {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};
#[cfg(not(feature = "library"))]
pub fn execute_delete_bonus_window(
deps: DepsMut,
_env: Env,
env: Env,
info: MessageInfo,
msg: DeleteBonusWindowMsg,
) -> Result<Response, ContractError> {
Expand All @@ -19,6 +19,13 @@ pub fn execute_delete_bonus_window(
return Err(ContractError::Unauthorized {});
}

let bonus_window = BONUS_WINDOWS.load(deps.storage, msg.bonus_window_id)?;

// Check if the bonus window is already ended
if env.block.time < bonus_window.end_at {
return Err(ContractError::BonusWindowNotEndedYet {});
}

BONUS_WINDOWS.remove(deps.storage, msg.bonus_window_id);

response = response.add_attribute("action", "delete_bonus_window");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ pub fn execute_register_bonus_window(
info: MessageInfo,
msg: RegisterBonusWindowMsg,
) -> Result<Response, ContractError> {
use cw_utils::one_coin;

let mut response = Response::new();
let params = PARAMS.load(deps.storage)?;

Expand All @@ -20,17 +22,33 @@ pub fn execute_register_bonus_window(
return Err(ContractError::Unauthorized {});
}

let id = 0u64;
let deposit = one_coin(&info)?;
if deposit.denom != msg.denom {
return Err(ContractError::NoAllowedToken {});
}

if deposit.amount < msg.budget_for_all {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any specific reason keeping deposit.denom, deposit.amount, msg.denom, msg.budget_for_all ? I think only deposit could be used and denom and budget_for_all could be removed on msg struct

return Err(ContractError::InsufficientBudget {});
}

let latest_id = BONUS_WINDOWS.last(deps.storage)
.map(|res|
match res {
Some((_, bw)) => bw.id.checked_add(1).unwrap(),
None => 0,
}
)
.unwrap_or(0);

let bonus_window = BonusWindow {
id: id,
id: latest_id,
denom: msg.denom,
budget_for_all: msg.budget_for_all,
apr_for_winners: msg.apr_for_winners,
start_at: msg.start_at,
end_at: msg.end_at,
};
BONUS_WINDOWS.save(deps.storage, id, &bonus_window)?;
BONUS_WINDOWS.save(deps.storage, latest_id, &bonus_window)?;

response = response.add_attribute("action", "register_bonus_window");

Expand Down
6 changes: 6 additions & 0 deletions contracts/yieldaggregator-bonus/src/query/bonus_windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,9 @@ pub fn query_bonus_windows(deps: Deps) -> StdResult<Vec<BonusWindow>> {
.collect::<StdResult<Vec<_>>>()?;
Ok(bonus_windows)
}

#[cfg(not(feature = "library"))]
pub fn query_bonus_window(deps: Deps, id: u64) -> StdResult<BonusWindow> {
let bonus_window = BONUS_WINDOWS.load(deps.storage, id)?;
Ok(bonus_window)
}
72 changes: 72 additions & 0 deletions contracts/yieldaggregator-bonus/tests/delete_bonus_window.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use crate::helpers::setup;
use cosmwasm_std::{testing::{mock_env, mock_info}, Uint128, Decimal, Timestamp, coins};
use yieldaggregator_bonus::{
error::ContractError, execute::{register_bonus_window::execute_register_bonus_window, vote::execute_vote, delete_bonus_window::execute_delete_bonus_window}, msgs::{UpdateParamsMsg, RegisterBonusWindowMsg, VoteMsg, DeleteBonusWindowMsg},
query::{params::query_params, voted_vaults::query_voted_vaults, bonus_windows::{query_bonus_windows, query_bonus_window}},
};

mod helpers;

#[test]
fn test_delete_bonus_window() {
let mut deps = setup();
// first, register the bonus window
let bw_denom = format!("yieldaggregator/vault/{}", "0");
execute_register_bonus_window(
deps.as_mut(),
mock_env(),
mock_info("authority", &coins(100, bw_denom.clone())),
RegisterBonusWindowMsg{
denom: bw_denom.clone(),
budget_for_all: Uint128::zero(),
apr_for_winners: vec![Decimal::zero()],
start_at: Timestamp::default(),
end_at: Timestamp::default().plus_seconds(1),
},
).unwrap();

// Error due to invalid sender
{
let msg = DeleteBonusWindowMsg {
bonus_window_id: 0,
};

let info = mock_info(
"anyone",
&coins(100, bw_denom.clone())
);
let err = execute_delete_bonus_window(
deps.as_mut(),
mock_env(),
info,
msg,
).unwrap_err();

assert_eq!(ContractError::Unauthorized {}, err);
}

// Success
{
let msg = DeleteBonusWindowMsg {
bonus_window_id: 0,
};

let info = mock_info(
"authority",
&coins(100, bw_denom.clone())
);
let res = execute_delete_bonus_window(
deps.as_mut(),
mock_env(),
info,
msg,
).unwrap();

assert_eq!(0, res.messages.len());

// Assume that the bonus window is deleted and returns err
let bonus_windows = query_bonus_windows(deps.as_ref());
assert_eq!(0, bonus_windows.unwrap().len());
query_bonus_window(deps.as_ref(), 0).unwrap_err();
}
}
103 changes: 103 additions & 0 deletions contracts/yieldaggregator-bonus/tests/register_bonus_window.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
use crate::helpers::setup;
use cosmwasm_std::{testing::{mock_env, mock_info}, Uint128, Decimal, Timestamp, Coin, coins};
use yieldaggregator_bonus::{
error::ContractError, execute::{register_bonus_window::execute_register_bonus_window}, msgs::{UpdateParamsMsg, RegisterBonusWindowMsg, self},
query::{params::query_params, bonus_windows::{query_bonus_windows, query_bonus_window}},
};

mod helpers;

#[test]
fn test_register_bonus_window() {
let mut deps = setup();

// Error due to the permission
{
let invalid_info = mock_info("anyone", &[]);
let msg = RegisterBonusWindowMsg {
denom: "tst".to_string(),
budget_for_all: Uint128::zero(),
apr_for_winners: vec![Decimal::zero()],
start_at: Timestamp::default(),
end_at: Timestamp::default(),
};
let err = execute_register_bonus_window(
deps.as_mut(),
mock_env(),
invalid_info,
msg,
).unwrap_err();
assert_eq!(err, ContractError::Unauthorized {});
}

// Error due to the insufficient budget
{
let info = mock_info("authority", &coins(10, "tst"));
let msg = RegisterBonusWindowMsg {
denom: "tst".to_string(),
budget_for_all: Uint128::new(100),
apr_for_winners: vec![Decimal::zero()],
start_at: Timestamp::default(),
end_at: Timestamp::default(),
};
let err = execute_register_bonus_window(
deps.as_mut(),
mock_env(),
info,
msg,
).unwrap_err();
assert_eq!(err, ContractError::InsufficientBudget {});
}

// Success
{
let info = mock_info("authority", &coins(100, "tst"));
let msg = RegisterBonusWindowMsg {
denom: "tst".to_string(),
budget_for_all: Uint128::new(100),
apr_for_winners: vec![Decimal::zero()],
start_at: Timestamp::default(),
end_at: Timestamp::default(),
};
let res = execute_register_bonus_window(
deps.as_mut(),
mock_env(),
info,
msg,
).unwrap();

assert_eq!(0, res.messages.len());

// meaninng test of the windows query
let bonus_windows = query_bonus_windows(deps.as_ref()).unwrap();
assert_eq!(1, bonus_windows.len());

// meaning test of window query
let bonus_window = query_bonus_window(deps.as_ref(), 0).unwrap();
assert_eq!(bonus_window.id, 0);
}

// Success case to check id sequencing
{
let info = mock_info("authority", &coins(100, "tst"));
let msg = RegisterBonusWindowMsg {
denom: "tst".to_string(),
budget_for_all: Uint128::zero(),
apr_for_winners: vec![Decimal::zero()],
start_at: Timestamp::default(),
end_at: Timestamp::default(),
};
let res = execute_register_bonus_window(
deps.as_mut(),
mock_env(),
info,
msg,
).unwrap();

assert_eq!(0, res.messages.len());

let bonus_window = query_bonus_window(deps.as_ref(), 1).unwrap();
assert_eq!(bonus_window.id, 1);
}

}
117 changes: 117 additions & 0 deletions contracts/yieldaggregator-bonus/tests/stake_vault_share.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
use crate::helpers::setup;
use cosmwasm_std::{testing::{mock_env, mock_info}, Uint128, Decimal, Timestamp, coins};
use yieldaggregator_bonus::{
error::ContractError, execute::{update_params::execute_update_params, register_bonus_window::execute_register_bonus_window, stake_vault_share::execute_stake_vault_share}, msgs::{UpdateParamsMsg, RegisterBonusWindowMsg, self, StakeVaultShareMsg},
query::{params::query_params, bonus_windows::{query_bonus_windows, query_bonus_window}, vault_share_staking::query_vault_share_staking},
};

mod helpers;

#[test]
fn test_stake_vault_share() {
let mut deps = setup();
// first, register the bonus window
let bw_denom = format!("yieldaggregator/vault/{}", "0");
execute_register_bonus_window(
deps.as_mut(),
mock_env(),
mock_info("authority", &coins(100, bw_denom.clone())),
RegisterBonusWindowMsg{
denom: bw_denom.clone(),
budget_for_all: Uint128::zero(),
apr_for_winners: vec![Decimal::zero()],
start_at: Timestamp::default(),
end_at: Timestamp::default().plus_seconds(1),
},
).unwrap();

// Error due to invalid denom
{
let info = mock_info(
"anyone",
&coins(100, "invalid_denom".to_string())
);

let stake_msg = StakeVaultShareMsg {
bonus_window_id: 0,
vault_id: 0,
};
let err = execute_stake_vault_share(
deps.as_mut(),
mock_env(),
info,
stake_msg
).unwrap_err();

assert_eq!(ContractError::NoAllowedToken { }, err);
}

// Error due to invalid time window
{
let info = mock_info("anyone", &coins(100, bw_denom.clone()));
let stake_msg = StakeVaultShareMsg {
bonus_window_id: 0,
vault_id: 0,
};
let err = execute_stake_vault_share(
deps.as_mut(),
mock_env(),
info,
stake_msg
).unwrap_err();

assert_eq!(ContractError::InvalidBonusWindowPeriod { }, err);
}

// Success
{
let bw_denom = format!("yieldaggregator/vault/{}", "0");
execute_register_bonus_window(
deps.as_mut(),
mock_env(),
mock_info("authority", &coins(100, bw_denom.clone())),
RegisterBonusWindowMsg{
denom: bw_denom.clone(),
budget_for_all: Uint128::zero(),
apr_for_winners: vec![Decimal::zero()],
start_at: Timestamp::default(),
end_at: mock_env().block.time.plus_seconds(1000),
},
).unwrap();

let info = mock_info("anyone", &coins(100, bw_denom.clone()));
let stake_msg = StakeVaultShareMsg {
bonus_window_id: 1,
vault_id: 0,
};
let res = execute_stake_vault_share(
deps.as_mut(),
mock_env(),
info.clone(),
stake_msg
).unwrap();

assert_eq!(0, res.messages.len());

// meaning test of the vault share query
let vault_share = query_vault_share_staking(deps.as_ref(), 0, info.clone().sender.into_string()).unwrap();
assert_eq!(vault_share.vault_share, Uint128::new(100));
}

// Error due to already staked
{
let info = mock_info("anyone", &coins(100, bw_denom.clone()));
let stake_msg = StakeVaultShareMsg {
bonus_window_id: 1,
vault_id: 0,
};
let err = execute_stake_vault_share(
deps.as_mut(),
mock_env(),
info,
stake_msg
).unwrap_err();

assert_eq!(err, ContractError::AlreadyStaked { });
}
}
Loading