Skip to content

Commit

Permalink
Add out asset refund case (#108)
Browse files Browse the repository at this point in the history
* add out asset refund case

* fix refund out amount test
  • Loading branch information
Ninjatosba authored Dec 8, 2024
1 parent 9be6b71 commit ce21081
Show file tree
Hide file tree
Showing 3 changed files with 234 additions and 6 deletions.
6 changes: 0 additions & 6 deletions packages/types/src/stream/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,6 @@ pub enum QueryMsg {
/// Returns a stream's current state.
#[returns(StreamResponse)]
Stream {},
/// Returns list of streams paginated by `start_after` and `limit`.
// #[returns(StreamsResponse)]
// ListStreams {
// start_after: Option<u64>,
// limit: Option<u32>,
// },
/// Returns current state of a position.
#[returns(PositionResponse)]
Position { owner: String },
Expand Down
136 changes: 136 additions & 0 deletions tests/src/tests/streamswap_tests/finalize_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -652,4 +652,140 @@ mod finalize_stream_tests {
.unwrap();
assert_eq!(contract_balance.len(), 0);
}

#[test]
fn out_amount_refund() {
let Suite {
mut app,
test_accounts,
stream_swap_code_id,
stream_swap_controller_code_id,
vesting_code_id,
} = SuiteBuilder::default().build();
let start_time = app.block_info().time.plus_seconds(100);
let end_time = app.block_info().time.plus_seconds(200);
let bootstrapping_start_time = app.block_info().time.plus_seconds(50);
let msg = get_controller_inst_msg(stream_swap_code_id, vesting_code_id, &test_accounts);
let controller_address = app
.instantiate_contract(
stream_swap_controller_code_id,
test_accounts.admin.clone(),
&msg,
&[],
"Controller".to_string(),
None,
)
.unwrap();
let create_stream_msg = CreateStreamMsgBuilder::new(
"Stream Swap tests",
test_accounts.creator_1.as_ref(),
coin(1_000_000, "out_denom"),
"in_denom",
bootstrapping_start_time,
start_time,
end_time,
)
.build();

// This case handles the scenario where the `out_amount` is refunded to the creator.
// For this to happen, the allocated amount for the stream must remain unspent during the stream's lifetime.
// If, at any point during the stream phase, no subscribers are active,
// a portion of the `out_amount` may remain unused and will be left in the contract.
// This unspent amount should be refunded separately to the creator.

let res = app
.execute_contract(
test_accounts.creator_1.clone(),
controller_address.clone(),
&create_stream_msg,
&[coin(100, "fee_denom"), coin(1_000_000, "out_denom")],
)
.unwrap();
let stream_swap_contract_address: String = get_contract_address_from_res(res);
let subscribe_msg = StreamSwapExecuteMsg::Subscribe {};

app.set_block(BlockInfo {
height: 1_100,
time: start_time,
chain_id: "test".to_string(),
});

// First subscription
let _res = app
.execute_contract(
test_accounts.subscriber_1.clone(),
Addr::unchecked(stream_swap_contract_address.clone()),
&subscribe_msg,
&[coin(200, "in_denom")],
)
.unwrap();

// Update environment time to end_time
app.set_block(BlockInfo {
height: 1_100,
time: end_time.minus_seconds(1),
chain_id: "test".to_string(),
});

// Subscriber 1 withdraws from the stream
let withdraw_msg = StreamSwapExecuteMsg::Withdraw { cap: None };
let _res = app
.execute_contract(
test_accounts.subscriber_1.clone(),
Addr::unchecked(stream_swap_contract_address.clone()),
&withdraw_msg,
&[],
)
.unwrap();

//Update environment time to end_time
app.set_block(BlockInfo {
height: 1_100,
time: end_time,
chain_id: "test".to_string(),
});

// Finalize the stream
let finalized_msg = StreamSwapExecuteMsg::FinalizeStream {
new_treasury: None,
create_pool: None,
salt: None,
};
let res = app
.execute_contract(
test_accounts.creator_1.clone(),
Addr::unchecked(stream_swap_contract_address.clone()),
&finalized_msg,
&[],
)
.unwrap();

let stream_swap_funds = get_funds_from_res(res);
assert_eq!(
stream_swap_funds,
vec![
(
String::from(test_accounts.creator_1.clone()),
Coin {
denom: "out_denom".to_string(),
amount: Uint128::new(10000)
},
),
(
String::from(test_accounts.creator_1.clone()),
Coin {
denom: "in_denom".to_string(),
amount: Uint128::new(197)
},
),
(
String::from(test_accounts.admin.clone()),
Coin {
denom: "in_denom".to_string(),
amount: Uint128::new(1)
},
)
]
);
}
}
98 changes: 98 additions & 0 deletions tests/src/tests/streamswap_tests/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod pool {
use cosmwasm_std::{coin, Addr, BlockInfo, Coin, Uint256};
use cw_multi_test::Executor;
use cw_utils::NativeBalance;
use streamswap_controller::error::ContractError as ControllerError;
use streamswap_types::controller::{CreatePool, PoolConfig};
use streamswap_types::stream::ExecuteMsg as StreamSwapExecuteMsg;
use streamswap_types::stream::QueryMsg as StreamSwapQueryMsg;
Expand Down Expand Up @@ -486,4 +487,101 @@ mod pool {
.collect();
assert_eq!(res_funds, expected_res);
}

#[test]
fn pool_validations() {
let Suite {
mut app,
test_accounts,
stream_swap_code_id,
stream_swap_controller_code_id,
vesting_code_id,
} = SuiteBuilder::default().build();

let msg = get_controller_inst_msg(stream_swap_code_id, vesting_code_id, &test_accounts);
let controller_address = app
.instantiate_contract(
stream_swap_controller_code_id,
test_accounts.admin.clone(),
&msg,
&[],
"Controller".to_string(),
None,
)
.unwrap();

let start_time = app.block_info().time.plus_seconds(100);
let end_time = app.block_info().time.plus_seconds(200);
let bootstrapping_start_time = app.block_info().time.plus_seconds(50);
let out_supply = 1_000_000u128;
let out_denom = "out_denom";

let out_coin = coin(out_supply, out_denom);
let pool_creation_fee = coin(1000000, "fee_denom");
let stream_creation_fee = coin(100, "fee_denom");
let in_denom = "in_denom";

// Pool amount 0 case
let create_stream_msg = CreateStreamMsgBuilder::new(
"stream",
test_accounts.creator_1.as_ref(),
out_coin.clone(),
in_denom,
bootstrapping_start_time,
start_time,
end_time,
)
.threshold(Uint256::from(100u128))
.pool_config(PoolConfig::ConcentratedLiquidity {
out_amount_clp: Uint256::zero(),
})
.build();

let res = app
.execute_contract(
test_accounts.creator_1.clone(),
controller_address.clone(),
&create_stream_msg,
&[
pool_creation_fee.clone(),
out_coin.clone(),
stream_creation_fee.clone(),
],
)
.unwrap_err();
let err = res.downcast::<ControllerError>().unwrap();
assert_eq!(err, ControllerError::InvalidPoolOutAmount {});

// Pool amount greater than out supply case
let create_stream_msg = CreateStreamMsgBuilder::new(
"stream",
test_accounts.creator_1.as_ref(),
out_coin.clone(),
in_denom,
bootstrapping_start_time,
start_time,
end_time,
)
.threshold(Uint256::from(100u128))
.pool_config(PoolConfig::ConcentratedLiquidity {
out_amount_clp: Uint256::from(out_supply + 1),
})
.build();

let res = app
.execute_contract(
test_accounts.creator_1.clone(),
controller_address.clone(),
&create_stream_msg,
&[
pool_creation_fee.clone(),
out_coin.clone(),
stream_creation_fee,
],
)
.unwrap_err();

let err = res.downcast::<ControllerError>().unwrap();
assert_eq!(err, ControllerError::InvalidPoolOutAmount {});
}
}

0 comments on commit ce21081

Please sign in to comment.