From 2225efd5be034a0cb323c54da426e0e24a45fc82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Orkun=20K=C3=BCl=C3=A7e?= Date: Tue, 3 Dec 2024 20:17:06 +0300 Subject: [PATCH] Seperate stream data into chunks (#100) * Stream deconstruct WIP * Minimize stream storage load * Fix comment --- contracts/stream/src/circuit_ops.rs | 66 ++- contracts/stream/src/contract.rs | 443 ++++++++---------- contracts/stream/src/lib.rs | 1 + contracts/stream/src/pool.rs | 71 ++- contracts/stream/src/state.rs | 18 +- contracts/stream/src/stream.rs | 8 +- contracts/stream/src/vesting.rs | 58 +++ packages/types/src/stream/stream.rs | 178 ++++--- packages/types/src/stream/threshold.rs | 10 +- tests/src/tests/streamswap_tests/shares.rs | 14 +- tests/src/tests/streamswap_tests/threshold.rs | 14 +- tests/src/tests/streamswap_tests/vesting.rs | 8 +- 12 files changed, 503 insertions(+), 386 deletions(-) create mode 100644 contracts/stream/src/vesting.rs diff --git a/contracts/stream/src/circuit_ops.rs b/contracts/stream/src/circuit_ops.rs index f0130cd..f4d373e 100644 --- a/contracts/stream/src/circuit_ops.rs +++ b/contracts/stream/src/circuit_ops.rs @@ -1,6 +1,6 @@ use crate::helpers::build_u128_bank_send_msg; use crate::pool::pool_refund; -use crate::state::{CONTROLLER_PARAMS, POSITIONS, STREAM}; +use crate::state::{CONTROLLER_PARAMS, POSITIONS, POST_STREAM, STREAM_INFO, STREAM_STATE}; use crate::stream::{sync_stream, sync_stream_status}; use crate::ContractError; use cosmwasm_std::{attr, BankMsg, CosmosMsg, DepsMut, Env, MessageInfo, Response, Timestamp}; @@ -13,7 +13,7 @@ pub fn execute_exit_cancelled( env: Env, info: MessageInfo, ) -> Result { - let mut stream = STREAM.load(deps.storage)?; + let mut stream = STREAM_STATE.load(deps.storage)?; let mut position = POSITIONS.load(deps.storage, &info.sender)?; if position.owner != info.sender { @@ -82,7 +82,7 @@ pub fn execute_cancel_stream( if controller_params.protocol_admin != info.sender { return Err(ContractError::Unauthorized {}); } - let mut stream = STREAM.load(deps.storage)?; + let mut stream = STREAM_STATE.load(deps.storage)?; sync_stream_status(&mut stream, env.block.time); if stream.is_finalized() || stream.is_cancelled() { @@ -93,19 +93,28 @@ pub fn execute_cancel_stream( stream.status_info.status = Status::Cancelled; sync_stream(&mut stream, env.block.time); - STREAM.save(deps.storage, &stream)?; + STREAM_STATE.save(deps.storage, &stream)?; // Refund all out tokens to stream creator(treasury) let mut refund_coins = vec![stream.out_asset.clone()]; - let pool_refund_coins = pool_refund(&deps, stream.pool_config, stream.out_asset.denom.clone())?; - refund_coins.extend(pool_refund_coins); + // refund pool creation if any + let post_stream_ops = POST_STREAM.may_load(deps.storage)?; + if let Some(post_stream_ops) = post_stream_ops { + let pool_refund_coins = pool_refund( + &deps, + post_stream_ops.pool_config, + stream.out_asset.denom.clone(), + )?; + refund_coins.extend(pool_refund_coins); + } + let stream_info = STREAM_INFO.load(deps.storage)?; let funds_msgs: Vec = refund_coins .iter() .map(|coin| { CosmosMsg::Bank(BankMsg::Send { - to_address: stream.treasury.to_string(), + to_address: stream_info.treasury.to_string(), amount: vec![coin.clone()], }) }) @@ -122,9 +131,10 @@ pub fn execute_cancel_stream_with_threshold( env: Env, info: MessageInfo, ) -> Result { - let mut stream = STREAM.load(deps.storage)?; + let mut stream = STREAM_STATE.load(deps.storage)?; + let stream_info = STREAM_INFO.load(deps.storage)?; // Only stream creator can cancel the stream with threshold not reached - if info.sender != stream.stream_admin { + if info.sender != stream_info.stream_admin { return Err(ContractError::Unauthorized {}); } sync_stream_status(&mut stream, env.block.time); @@ -150,19 +160,27 @@ pub fn execute_cancel_stream_with_threshold( stream.status_info.status = Status::Cancelled; - STREAM.save(deps.storage, &stream)?; + STREAM_STATE.save(deps.storage, &stream)?; // Refund all out tokens to stream creator(treasury) let mut refund_coins = vec![stream.out_asset.clone()]; - let pool_refund_coins = pool_refund(&deps, stream.pool_config, stream.out_asset.denom.clone())?; - refund_coins.extend(pool_refund_coins); + // refund pool creation if any + let post_stream_ops = POST_STREAM.may_load(deps.storage)?; + if let Some(post_stream_ops) = post_stream_ops { + let pool_refund_coins = pool_refund( + &deps, + post_stream_ops.pool_config, + stream.out_asset.denom.clone(), + )?; + refund_coins.extend(pool_refund_coins); + } let funds_msgs: Vec = refund_coins .iter() .map(|coin| { CosmosMsg::Bank(BankMsg::Send { - to_address: stream.treasury.to_string(), + to_address: stream_info.treasury.to_string(), amount: vec![coin.clone()], }) }) @@ -178,9 +196,10 @@ pub fn execute_stream_admin_cancel( env: Env, info: MessageInfo, ) -> Result { - let mut stream = STREAM.load(deps.storage)?; + let mut stream = STREAM_STATE.load(deps.storage)?; + let stream_info = STREAM_INFO.load(deps.storage)?; // Only stream admin can cancel the stream with this method - if info.sender != stream.stream_admin { + if info.sender != stream_info.stream_admin { return Err(ContractError::Unauthorized {}); } @@ -194,18 +213,27 @@ pub fn execute_stream_admin_cancel( } stream.status_info.status = Status::Cancelled; sync_stream(&mut stream, env.block.time); - STREAM.save(deps.storage, &stream)?; + STREAM_STATE.save(deps.storage, &stream)?; // Refund all out tokens to stream creator(treasury) let mut refund_coins = vec![stream.out_asset.clone()]; - let pool_refund_coins = pool_refund(&deps, stream.pool_config, stream.out_asset.denom.clone())?; - refund_coins.extend(pool_refund_coins); + // refund pool creation if any + let post_stream_ops = POST_STREAM.may_load(deps.storage)?; + if let Some(post_stream_ops) = post_stream_ops { + let pool_refund_coins = pool_refund( + &deps, + post_stream_ops.pool_config, + stream.out_asset.denom.clone(), + )?; + refund_coins.extend(pool_refund_coins); + } + let funds_msgs: Vec = refund_coins .iter() .map(|coin| { CosmosMsg::Bank(BankMsg::Send { - to_address: stream.treasury.to_string(), + to_address: stream_info.treasury.to_string(), amount: vec![coin.clone()], }) }) diff --git a/contracts/stream/src/contract.rs b/contracts/stream/src/contract.rs index abf4e30..853273f 100644 --- a/contracts/stream/src/contract.rs +++ b/contracts/stream/src/contract.rs @@ -6,29 +6,30 @@ use crate::stream::{compute_shares_amount, sync_stream, sync_stream_status}; use crate::{circuit_ops, ContractError}; use core::str; use cosmwasm_std::{ - attr, coin, entry_point, to_json_binary, Attribute, BankMsg, Binary, CodeInfoResponse, Coin, - CosmosMsg, Decimal256, Deps, DepsMut, Env, MessageInfo, Order, Response, StdError, StdResult, - Timestamp, Uint128, Uint256, WasmMsg, + attr, entry_point, to_json_binary, Attribute, BankMsg, Binary, Coin, CosmosMsg, Decimal256, + Deps, DepsMut, Env, MessageInfo, Order, Response, StdError, StdResult, Timestamp, Uint128, + Uint256, }; use cw2::{ensure_from_older_version, set_contract_version}; use cw_storage_plus::Bound; use cw_utils::{maybe_addr, must_pay}; use std::env; -use streamswap_types::stream::ThresholdState; use streamswap_types::stream::{ AveragePriceResponse, ExecuteMsg, LatestStreamedPriceResponse, PositionResponse, PositionsResponse, QueryMsg, StreamResponse, }; +use streamswap_types::stream::{PostStreamActions, StreamInfo, StreamState, ThresholdState}; use streamswap_utils::to_uint256; -use crate::pool::{build_create_initial_position_msg, calculate_in_amount_clp, next_pool_id}; -use crate::state::{CONTROLLER_PARAMS, CREATOR_VESTING, POSITIONS, STREAM, SUBSCRIBER_VESTING}; -use cw_vesting::msg::InstantiateMsg as VestingInstantiateMsg; -use cw_vesting::UncheckedDenom; -use osmosis_std::types::osmosis::concentratedliquidity::poolmodel::concentrated::v1beta1::MsgCreateConcentratedPool; +use crate::pool::pool_operations; +use crate::state::{ + CONTROLLER_PARAMS, CREATOR_VESTING, POSITIONS, POST_STREAM, STREAM_INFO, STREAM_STATE, + SUBSCRIBER_VESTING, +}; +use crate::vesting::vesting_operations; use streamswap_types::controller::{CreatePool, Params as ControllerParams, PoolConfig}; use streamswap_types::controller::{CreateStreamMsg, MigrateMsg}; -use streamswap_types::stream::{Position, Status, Stream}; +use streamswap_types::stream::{Position, Status}; // Version and contract info for migration const CONTRACT_NAME: &str = "crates.io:streamswap-stream"; @@ -84,23 +85,28 @@ pub fn instantiate( check_name_and_url(&name, &url)?; - let stream = Stream::new( + let stream_state = StreamState::new( env.block.time, - name.clone(), - treasury.clone(), - stream_admin.clone(), - url.clone(), out_asset.clone(), in_denom.clone(), bootstraping_start_time, start_time, end_time, - pool_config.clone(), - subscriber_vesting, - creator_vesting, + ); + STREAM_STATE.save(deps.storage, &stream_state)?; + + let stream_info = StreamInfo::new( + stream_admin.clone(), + name.clone(), + treasury.clone(), + url, tos_version, ); - STREAM.save(deps.storage, &stream)?; + STREAM_INFO.save(deps.storage, &stream_info)?; + + let post_stream_actions = + PostStreamActions::new(pool_config.clone(), subscriber_vesting, creator_vesting); + POST_STREAM.save(deps.storage, &post_stream_actions)?; let threshold_state = ThresholdState::new(); threshold_state.set_threshold_if_any(threshold, deps.storage)?; @@ -148,11 +154,11 @@ pub fn execute( ExecuteMsg::SyncPosition {} => execute_sync_position(deps, env, info), ExecuteMsg::SyncStream {} => execute_sync_stream(deps, env), ExecuteMsg::Subscribe {} => { - let stream = STREAM.load(deps.storage)?; + let stream = STREAM_STATE.load(deps.storage)?; execute_subscribe(deps, env, info, stream) } ExecuteMsg::Withdraw { cap } => { - let stream = STREAM.load(deps.storage)?; + let stream = STREAM_STATE.load(deps.storage)?; execute_withdraw(deps, env, info, stream, cap) } ExecuteMsg::FinalizeStream { @@ -174,7 +180,7 @@ pub fn execute( /// Syncs stream to calculate released distribution and spent amount pub fn execute_sync_stream(deps: DepsMut, env: Env) -> Result { - let mut stream = STREAM.load(deps.storage)?; + let mut stream = STREAM_STATE.load(deps.storage)?; sync_stream_status(&mut stream, env.block.time); if stream.is_cancelled() { return Err(ContractError::OperationNotAllowed { @@ -182,7 +188,7 @@ pub fn execute_sync_stream(deps: DepsMut, env: Env) -> Result Result { let mut position = POSITIONS.load(deps.storage, &info.sender)?; - let mut stream = STREAM.load(deps.storage)?; + let mut stream = STREAM_STATE.load(deps.storage)?; sync_stream_status(&mut stream, env.block.time); // check and return error if stream is cancelled if stream.is_cancelled() { @@ -219,7 +225,7 @@ pub fn execute_sync_position( // sync stream sync_stream(&mut stream, env.block.time); - STREAM.save(deps.storage, &stream)?; + STREAM_STATE.save(deps.storage, &stream)?; // updates position to latest distribution. Returns the amount of out tokens that has been purchased // and in tokens that has been spent. @@ -294,18 +300,18 @@ pub fn execute_subscribe( deps: DepsMut, env: Env, info: MessageInfo, - mut stream: Stream, + mut stream_state: StreamState, ) -> Result { // Update stream status - sync_stream_status(&mut stream, env.block.time); + sync_stream_status(&mut stream_state, env.block.time); - if !(stream.is_active() || stream.is_bootstrapping()) { + if !(stream_state.is_active() || stream_state.is_bootstrapping()) { return Err(ContractError::OperationNotAllowed { - current_status: stream.status_info.status.to_string(), + current_status: stream_state.status_info.status.to_string(), }); } - let in_amount = must_pay(&info, &stream.in_denom)?; + let in_amount = must_pay(&info, &stream_state.in_denom)?; let uint256_in_amount = Uint256::from(in_amount.u128()); let new_shares; @@ -313,16 +319,17 @@ pub fn execute_subscribe( match position { None => { // incoming tokens should not participate in prev distribution - sync_stream(&mut stream, env.block.time); - new_shares = compute_shares_amount(&stream, uint256_in_amount, false); + sync_stream(&mut stream_state, env.block.time); + new_shares = compute_shares_amount(&stream_state, uint256_in_amount, false); // new positions do not update purchase as it has no effect on distribution + let stream_info = STREAM_INFO.load(deps.storage)?; let new_position = Position::new( info.sender.clone(), uint256_in_amount, new_shares, - Some(stream.dist_index), + Some(stream_state.dist_index), env.block.time, - stream.tos_version.clone(), + stream_info.tos_version.clone(), ); POSITIONS.save(deps.storage, &info.sender, &new_position)?; } @@ -331,13 +338,13 @@ pub fn execute_subscribe( return Err(ContractError::Unauthorized {}); } // incoming tokens should not participate in prev distribution - sync_stream(&mut stream, env.block.time); - new_shares = compute_shares_amount(&stream, uint256_in_amount, false); + sync_stream(&mut stream_state, env.block.time); + new_shares = compute_shares_amount(&stream_state, uint256_in_amount, false); sync_position( - stream.dist_index, - stream.shares, - stream.status_info.last_updated, - stream.in_supply, + stream_state.dist_index, + stream_state.shares, + stream_state.status_info.last_updated, + stream_state.in_supply, &mut position, )?; @@ -348,18 +355,18 @@ pub fn execute_subscribe( } // increase in supply and shares - stream.in_supply = stream.in_supply.checked_add(uint256_in_amount)?; - stream.shares = stream.shares.checked_add(new_shares)?; - STREAM.save(deps.storage, &stream)?; + stream_state.in_supply = stream_state.in_supply.checked_add(uint256_in_amount)?; + stream_state.shares = stream_state.shares.checked_add(new_shares)?; + STREAM_STATE.save(deps.storage, &stream_state)?; let res = Response::new() .add_attribute("action", "subscribe") - .add_attribute("status info", stream.status_info.status.to_string()) - .add_attribute("in_supply", stream.in_supply) + .add_attribute("status info", stream_state.status_info.status.to_string()) + .add_attribute("in_supply", stream_state.in_supply) .add_attribute("in_amount", in_amount) .add_attribute("subscriber_shares", new_shares) - .add_attribute("total_shares", stream.shares) - .add_attribute("dist_index", stream.dist_index.to_string()); + .add_attribute("total_shares", stream_state.shares) + .add_attribute("dist_index", stream_state.dist_index.to_string()); Ok(res) } @@ -368,7 +375,7 @@ pub fn execute_withdraw( deps: DepsMut, env: Env, info: MessageInfo, - mut stream: Stream, + mut stream: StreamState, cap: Option, ) -> Result { sync_stream_status(&mut stream, env.block.time); @@ -411,7 +418,7 @@ pub fn execute_withdraw( position.in_balance = position.in_balance.checked_sub(withdraw_amount)?; position.shares = position.shares.checked_sub(shares_amount)?; - STREAM.save(deps.storage, &stream)?; + STREAM_STATE.save(deps.storage, &stream)?; POSITIONS.save(deps.storage, &position.owner, &position)?; let uint128_withdraw_amount = Uint128::try_from(withdraw_amount)?; @@ -440,40 +447,43 @@ pub fn execute_finalize_stream( create_pool: Option, salt: Option, ) -> Result { - let mut stream = STREAM.load(deps.storage)?; - if stream.stream_admin != info.sender { + let stream_info = STREAM_INFO.load(deps.storage)?; + if stream_info.stream_admin != info.sender { return Err(ContractError::Unauthorized {}); } - sync_stream_status(&mut stream, env.block.time); - if stream.is_finalized() || stream.is_cancelled() || !stream.is_ended() { + let mut stream_state = STREAM_STATE.load(deps.storage)?; + sync_stream_status(&mut stream_state, env.block.time); + + if stream_state.is_finalized() || stream_state.is_cancelled() || !stream_state.is_ended() { return Err(ContractError::OperationNotAllowed { - current_status: stream.status_info.status.to_string(), + current_status: stream_state.status_info.status.to_string(), }); } - sync_stream(&mut stream, env.block.time); + sync_stream(&mut stream_state, env.block.time); - stream.status_info.status = Status::Finalized; + stream_state.status_info.status = Status::Finalized; // If threshold is set and not reached, finalize will fail // Creator should execute cancel_stream_with_threshold to cancel the stream // Only returns error if threshold is set and not reached let thresholds_state = ThresholdState::new(); - thresholds_state.error_if_not_reached(deps.storage, &stream)?; + thresholds_state.error_if_not_reached(deps.storage, &stream_state)?; - STREAM.save(deps.storage, &stream)?; + STREAM_STATE.save(deps.storage, &stream_state)?; let controller_params = CONTROLLER_PARAMS.load(deps.storage)?; - let treasury = maybe_addr(deps.api, new_treasury)?.unwrap_or_else(|| stream.treasury.clone()); + let treasury = + maybe_addr(deps.api, new_treasury)?.unwrap_or_else(|| stream_info.treasury.clone()); let mut messages = vec![]; let mut attributes = vec![]; // last creator revenue = spent_in - swap_fee - in_clp; - let mut creator_revenue = stream.spent_in; + let mut creator_revenue = stream_state.spent_in; // Stream's swap fee collected at fixed rate from accumulated spent_in of positions(ie stream.spent_in) - let swap_fee = Decimal256::from_ratio(stream.spent_in, Uint128::one()) + let swap_fee = Decimal256::from_ratio(stream_state.spent_in, Uint128::one()) .checked_mul(controller_params.exit_fee_percent)? * Uint256::one(); @@ -483,132 +493,80 @@ pub fn execute_finalize_stream( // In case the stream is ended without any shares in it. We need to refund the remaining // out tokens although that is unlikely to happen. - if stream.out_remaining > Uint256::zero() { - let remaining_out = stream.out_remaining; + if stream_state.out_remaining > Uint256::zero() { + let remaining_out = stream_state.out_remaining; let uint128_remaining_out = Uint128::try_from(remaining_out)?; // Sub remaining out tokens from out_asset - stream.out_asset.amount = stream.out_asset.amount.checked_sub(uint128_remaining_out)?; + stream_state.out_asset.amount = stream_state + .out_asset + .amount + .checked_sub(uint128_remaining_out)?; let remaining_msg = CosmosMsg::Bank(BankMsg::Send { to_address: treasury.to_string(), amount: vec![Coin { - denom: stream.out_asset.denom.clone(), + denom: stream_state.out_asset.denom.clone(), amount: uint128_remaining_out, }], }); messages.push(remaining_msg); } - // if create_pool is set, create a pool for the stream and send initial position - match (stream.pool_config, create_pool) { - ( - Some(PoolConfig::ConcentratedLiquidity { out_amount_clp }), - Some(CreatePool::ConcentratedLiquidity { - lower_tick, - upper_tick, - tick_spacing, - spread_factor, - }), - ) => { - let pool_id = next_pool_id(&deps)?; - - // amount of in tokens allocated for clp - let in_clp = calculate_in_amount_clp( - to_uint256(stream.out_asset.amount), - out_amount_clp, - creator_revenue, - ); - - // extract in_clp from last revenue - creator_revenue = creator_revenue.checked_sub(in_clp)?; - - // Create initial position message - let create_initial_position_msg = build_create_initial_position_msg( - pool_id, - env.contract.address.to_string(), - stream.in_denom.clone(), - in_clp, - stream.out_asset.denom.clone(), - out_amount_clp, - lower_tick, - upper_tick, - ); - - // convert msg create pool to osmosis create clp pool msg - let osmosis_create_clp_pool_msg = MsgCreateConcentratedPool { - sender: env.contract.address.to_string(), - denom0: stream.out_asset.denom.clone(), - denom1: stream.in_denom.clone(), - tick_spacing, - spread_factor: spread_factor.clone(), - }; - - messages.push(osmosis_create_clp_pool_msg.into()); - messages.push(create_initial_position_msg.into()); - - attributes.push(attr("pool_id", pool_id.clone().to_string())); - attributes.push(attr("pool_type", "clp".to_string())); - attributes.push(attr("pool_out_amount", out_amount_clp)); - attributes.push(attr("pool_in_amount", in_clp)); - attributes.push(attr("pool_lower_tick", lower_tick.to_string())); - attributes.push(attr("pool_upper_tick", upper_tick.to_string())); - attributes.push(attr("pool_spread_factor", spread_factor.to_string())); - attributes.push(attr("pool_tick_spacing", tick_spacing.to_string())); - Ok(()) + // if vesting is not set we need to send the creator revenue to the treasury in outer scope + let mut vesting_flag = false; + // execute post stream actions + let post_stream_actions = POST_STREAM.may_load(deps.storage)?; + if let Some(post_stream_actions) = post_stream_actions { + // if pool config and create pool is set, create a pool for the stream + creator_revenue = match (post_stream_actions.pool_config, create_pool) { + (Some(pool_config), Some(create_pool)) => { + let (msgs, attrs, creator_revenue) = pool_operations( + &deps, + create_pool, + env.contract.address.clone(), + stream_state.in_denom.clone(), + stream_state.out_asset.denom.clone(), + stream_state.out_asset.amount, + creator_revenue, + pool_config, + )?; + messages.extend(msgs); + attributes.extend(attrs); + Ok(creator_revenue) + } + (None, None) => Ok(creator_revenue), + _ => Err(ContractError::InvalidPoolConfig {}), + }?; + + // if subscriber vesting is set, instantiate a vested release contract for user and send + if let Some(creator_vesting) = post_stream_actions.creator_vesting { + let vesting_checksum = deps + .querier + .query_wasm_code_info(controller_params.vesting_code_id)? + .checksum; + let (vesting_msgs, vesting_attributes, vesting_addr) = vesting_operations( + &deps, + env.contract.address, + vesting_checksum, + treasury.clone(), + salt, + stream_state.status_info.end_time, + controller_params.vesting_code_id, + creator_revenue_u128, + stream_state.in_denom.clone(), + creator_vesting, + )?; + messages.extend(vesting_msgs); + attributes.extend(vesting_attributes); + CREATOR_VESTING.save(deps.storage, &vesting_addr)?; + vesting_flag = true; } - (None, None) => Ok(()), - // If either pool_config or create_pool is not set, return error - _ => Err(ContractError::InvalidPoolConfig {}), - }?; - - if let Some(creator_vesting) = stream.creator_vesting { - let salt = salt.ok_or(ContractError::InvalidSalt {})?; - - let vesting_title = format!( - "Stream addr {} released to {}", - env.contract.address, info.sender - ); - let creator_vesting_instantiate_msg = VestingInstantiateMsg { - owner: None, - title: vesting_title, - recipient: info.sender.to_string(), - description: None, - total: creator_revenue_u128, - denom: UncheckedDenom::Native(stream.out_asset.denom.clone()), - schedule: creator_vesting.schedule, - start_time: Some(stream.status_info.end_time), - vesting_duration_seconds: creator_vesting.vesting_duration_seconds, - unbonding_duration_seconds: creator_vesting.unbonding_duration_seconds, - }; - - // prepare instantiate msg msg - let CodeInfoResponse { checksum, .. } = deps - .querier - .query_wasm_code_info(controller_params.vesting_code_id)?; - let creator = deps.api.addr_canonicalize(env.contract.address.as_str())?; - - // Calculate the address of the new contract - let creator_vesting_address = deps.api.addr_humanize( - &cosmwasm_std::instantiate2_address(checksum.as_ref(), &creator, &salt)?, - )?; - - CREATOR_VESTING.save(deps.storage, treasury.clone(), &creator_vesting_address)?; - - let vesting_instantiate_msg = WasmMsg::Instantiate2 { - admin: None, - code_id: controller_params.vesting_code_id, - label: format!("{}-{}", stream.in_denom, treasury), - msg: to_json_binary(&creator_vesting_instantiate_msg)?, - funds: vec![coin(creator_revenue_u128.u128(), stream.out_asset.denom)], - salt, - }; + } - messages.push(vesting_instantiate_msg.into()); - attributes.push(attr("creator_vesting_address", creator_vesting_address)); - } else { + if !vesting_flag { let send_msg = CosmosMsg::Bank(BankMsg::Send { to_address: treasury.to_string(), amount: vec![Coin { - denom: stream.in_denom.clone(), + denom: stream_state.in_denom.clone(), amount: creator_revenue_u128, }], }); @@ -616,11 +574,10 @@ pub fn execute_finalize_stream( } let swap_fee_msg = build_u128_bank_send_msg( - stream.in_denom.clone(), + stream_state.in_denom.clone(), controller_params.fee_collector.to_string(), swap_fee, )?; - messages.push(swap_fee_msg); attributes.extend(vec![ @@ -628,11 +585,14 @@ pub fn execute_finalize_stream( attr("treasury", treasury.to_string()), attr("fee_collector", controller_params.fee_collector.to_string()), attr("creators_revenue", creator_revenue), - attr("refunded_out_remaining", stream.out_remaining.to_string()), + attr( + "refunded_out_remaining", + stream_state.out_remaining.to_string(), + ), attr( "total_sold", - to_uint256(stream.out_asset.amount) - .checked_sub(stream.out_remaining)? + to_uint256(stream_state.out_asset.amount) + .checked_sub(stream_state.out_remaining)? .to_string(), ), attr("swap_fee", swap_fee), @@ -653,22 +613,22 @@ pub fn execute_exit_stream( info: MessageInfo, salt: Option, ) -> Result { - let mut stream = STREAM.load(deps.storage)?; + let mut stream_state = STREAM_STATE.load(deps.storage)?; let controller_params = CONTROLLER_PARAMS.load(deps.storage)?; // check if stream is paused - sync_stream_status(&mut stream, env.block.time); + sync_stream_status(&mut stream_state, env.block.time); - if stream.is_cancelled() || !(stream.is_ended() || stream.is_finalized()) { + if stream_state.is_cancelled() || !(stream_state.is_ended() || stream_state.is_finalized()) { return Err(ContractError::OperationNotAllowed { - current_status: stream.status_info.status.to_string(), + current_status: stream_state.status_info.status.to_string(), }); } - sync_stream(&mut stream, env.block.time); + sync_stream(&mut stream_state, env.block.time); let threshold_state = ThresholdState::new(); - threshold_state.error_if_not_reached(deps.storage, &stream)?; + threshold_state.error_if_not_reached(deps.storage, &stream_state)?; let mut position = POSITIONS.load(deps.storage, &info.sender)?; if position.exit_date != Timestamp::from_seconds(0) { @@ -677,15 +637,15 @@ pub fn execute_exit_stream( // sync position before exit sync_position( - stream.dist_index, - stream.shares, - stream.status_info.last_updated, - stream.in_supply, + stream_state.dist_index, + stream_state.shares, + stream_state.status_info.last_updated, + stream_state.in_supply, &mut position, )?; - stream.shares = stream.shares.checked_sub(position.shares)?; + stream_state.shares = stream_state.shares.checked_sub(position.shares)?; - STREAM.save(deps.storage, &stream)?; + STREAM_STATE.save(deps.storage, &stream_state)?; // sync position exit date position.exit_date = env.block.time; POSITIONS.save(deps.storage, &position.owner, &position)?; @@ -695,69 +655,53 @@ pub fn execute_exit_stream( .checked_mul(controller_params.exit_fee_percent)? * Uint256::one(); - let mut msgs: Vec = vec![]; - let mut attrs: Vec = vec![]; + let mut messages: Vec = vec![]; + let mut attributes: Vec = vec![]; // if vesting is set, instantiate a vested release contract for user and send // the out tokens to the contract let uint128_purchased = Uint128::try_from(position.purchased)?; - if let Some(sub_vesting) = stream.subscriber_vesting { - let salt = salt.ok_or(ContractError::InvalidSalt {})?; - - let vesting_title = format!( - "Stream addr {} released to {}", - env.contract.address, info.sender - ); - let sub_vesting_instantiate_msg = VestingInstantiateMsg { - owner: None, - title: vesting_title, - recipient: info.sender.to_string(), - description: None, - total: uint128_purchased, - denom: UncheckedDenom::Native(stream.out_asset.denom.clone()), - schedule: sub_vesting.schedule, - start_time: Some(stream.status_info.end_time), - vesting_duration_seconds: sub_vesting.vesting_duration_seconds, - unbonding_duration_seconds: sub_vesting.unbonding_duration_seconds, - }; - - // prepare instantiate msg msg - let CodeInfoResponse { checksum, .. } = deps - .querier - .query_wasm_code_info(controller_params.vesting_code_id)?; - let creator = deps.api.addr_canonicalize(env.contract.address.as_str())?; - - // Calculate the address of the new contract - let address = deps.api.addr_humanize(&cosmwasm_std::instantiate2_address( - checksum.as_ref(), - &creator, - &salt, - )?)?; - - SUBSCRIBER_VESTING.save(deps.storage, info.sender.clone(), &address)?; - - let vesting_instantiate_msg = WasmMsg::Instantiate2 { - admin: None, - code_id: controller_params.vesting_code_id, - label: format!("{}-{}", stream.out_asset.denom, info.sender), - msg: to_json_binary(&sub_vesting_instantiate_msg)?, - funds: vec![coin(uint128_purchased.u128(), stream.out_asset.denom)], - salt, - }; + let mut vesting_flag = false; + + let post_stream_actions = POST_STREAM.may_load(deps.storage)?; + if let Some(post_stream_actions) = post_stream_actions { + if let Some(vesting_config) = post_stream_actions.subscriber_vesting { + let vesting_checksum = deps + .querier + .query_wasm_code_info(controller_params.vesting_code_id)? + .checksum; + let (vesting_msgs, vesting_attributes, vesting_addr) = vesting_operations( + &deps, + env.contract.address, + vesting_checksum, + info.sender.clone(), + salt, + stream_state.status_info.end_time, + controller_params.vesting_code_id, + uint128_purchased, + stream_state.out_asset.denom.clone(), + vesting_config, + )?; + messages.extend(vesting_msgs); + attributes.extend(vesting_attributes); + SUBSCRIBER_VESTING.save(deps.storage, info.sender.clone(), &vesting_addr)?; + vesting_flag = true; + } + } - msgs.push(vesting_instantiate_msg.into()); - attrs.push(attr("subscriber_vesting_address", address)); - } else { + // if vesting is not set we need to send the out tokens to the user + if !vesting_flag { let send_msg = CosmosMsg::Bank(BankMsg::Send { to_address: info.sender.to_string(), amount: vec![Coin { - denom: stream.out_asset.denom.to_string(), + denom: stream_state.out_asset.denom.to_string(), amount: uint128_purchased, }], }); - msgs.push(send_msg); + messages.push(send_msg); } + // if there is any unspent in balance, send it back to the user if !position.in_balance.is_zero() { let unspent = position.in_balance; @@ -765,21 +709,23 @@ pub fn execute_exit_stream( let unspent_msg = CosmosMsg::Bank(BankMsg::Send { to_address: info.sender.to_string(), amount: vec![Coin { - denom: stream.in_denom, + denom: stream_state.in_denom, amount: uint128_unspent, }], }); - msgs.push(unspent_msg); + messages.push(unspent_msg); } - attrs.extend(vec![ + attributes.extend(vec![ attr("action", "exit_stream"), attr("spent", position.spent.checked_sub(swap_fee)?), attr("purchased", position.purchased), attr("swap_fee_paid", swap_fee), ]); - Ok(Response::new().add_messages(msgs).add_attributes(attrs)) + Ok(Response::new() + .add_messages(messages) + .add_attributes(attributes)) } #[cfg_attr(not(feature = "library"), entry_point)] @@ -808,9 +754,10 @@ pub fn query_params(deps: Deps) -> StdResult { } pub fn query_stream(deps: Deps, _env: Env) -> StdResult { - let stream = STREAM.load(deps.storage)?; + let stream = STREAM_STATE.load(deps.storage)?; + let stream_info = STREAM_INFO.load(deps.storage)?; let stream = StreamResponse { - treasury: stream.treasury.to_string(), + treasury: stream_info.treasury.to_string(), in_denom: stream.in_denom, out_asset: stream.out_asset, start_time: stream.status_info.start_time, @@ -822,9 +769,9 @@ pub fn query_stream(deps: Deps, _env: Env) -> StdResult { in_supply: stream.in_supply, shares: stream.shares, status: stream.status_info.status, - url: stream.url, + url: stream_info.url, current_streamed_price: stream.current_streamed_price, - stream_admin: stream.stream_admin.into_string(), + stream_admin: stream_info.stream_admin.into_string(), }; Ok(stream) } @@ -879,14 +826,14 @@ pub fn list_positions( } pub fn query_average_price(deps: Deps, _env: Env) -> StdResult { - let stream = STREAM.load(deps.storage)?; + let stream = STREAM_STATE.load(deps.storage)?; let total_purchased = to_uint256(stream.out_asset.amount) - stream.out_remaining; let average_price = Decimal256::from_ratio(stream.spent_in, total_purchased); Ok(AveragePriceResponse { average_price }) } pub fn query_last_streamed_price(deps: Deps, _env: Env) -> StdResult { - let stream = STREAM.load(deps.storage)?; + let stream = STREAM_STATE.load(deps.storage)?; Ok(LatestStreamedPriceResponse { current_streamed_price: stream.current_streamed_price, }) diff --git a/contracts/stream/src/lib.rs b/contracts/stream/src/lib.rs index 40bf079..15e6b56 100644 --- a/contracts/stream/src/lib.rs +++ b/contracts/stream/src/lib.rs @@ -8,3 +8,4 @@ mod helpers; mod pool; pub mod state; pub mod stream; +mod vesting; diff --git a/contracts/stream/src/pool.rs b/contracts/stream/src/pool.rs index b8f4ecf..1691835 100644 --- a/contracts/stream/src/pool.rs +++ b/contracts/stream/src/pool.rs @@ -1,10 +1,77 @@ use std::str::FromStr; use crate::ContractError; -use cosmwasm_std::{Coin, Decimal256, DepsMut, Uint128, Uint256}; +use cosmwasm_std::{attr, Addr, Attribute, Coin, CosmosMsg, Decimal256, DepsMut, Uint128, Uint256}; +use osmosis_std::types::osmosis::concentratedliquidity::poolmodel::concentrated::v1beta1::MsgCreateConcentratedPool; use osmosis_std::types::osmosis::concentratedliquidity::v1beta1::MsgCreatePosition; use osmosis_std::types::osmosis::poolmanager::v1beta1::PoolmanagerQuerier; -use streamswap_types::controller::PoolConfig; +use streamswap_types::controller::{CreatePool, PoolConfig}; +use streamswap_utils::to_uint256; + +pub fn pool_operations( + deps: &DepsMut, + create_pool: CreatePool, + stream_addr: Addr, + in_denom: String, + out_denom: String, + out_amount: Uint128, + mut creator_revenue: Uint256, + pool_config: PoolConfig, +) -> Result<(Vec, Vec, Uint256), ContractError> { + let PoolConfig::ConcentratedLiquidity { out_amount_clp } = pool_config; + let CreatePool::ConcentratedLiquidity { + lower_tick, + upper_tick, + tick_spacing, + spread_factor, + } = create_pool; + + let pool_id = next_pool_id(deps)?; + + // amount of in tokens allocated for clp + let in_clp = calculate_in_amount_clp(to_uint256(out_amount), out_amount_clp, creator_revenue); + + // extract in_clp from last revenue + creator_revenue = creator_revenue.checked_sub(in_clp)?; + + // Create initial position message + let create_initial_position_msg = build_create_initial_position_msg( + pool_id, + stream_addr.to_string(), + in_denom.clone(), + creator_revenue, + out_denom.clone(), + out_amount_clp, + lower_tick, + upper_tick, + ); + + // convert msg create pool to osmosis create clp pool msg + let osmosis_create_clp_pool_msg = MsgCreateConcentratedPool { + sender: stream_addr.to_string(), + denom0: out_denom, + denom1: in_denom, + tick_spacing, + spread_factor: spread_factor.clone(), + }; + + let mut messages: Vec = Vec::new(); + let mut attributes: Vec = Vec::new(); + + messages.push(osmosis_create_clp_pool_msg.into()); + messages.push(create_initial_position_msg.into()); + + attributes.push(attr("pool_id", pool_id.clone().to_string())); + attributes.push(attr("pool_type", "clp".to_string())); + attributes.push(attr("pool_out_amount", out_amount_clp)); + attributes.push(attr("pool_in_amount", creator_revenue)); + attributes.push(attr("pool_lower_tick", lower_tick.to_string())); + attributes.push(attr("pool_upper_tick", upper_tick.to_string())); + attributes.push(attr("pool_spread_factor", spread_factor.to_string())); + attributes.push(attr("pool_tick_spacing", tick_spacing.to_string())); + + Ok((messages, attributes, creator_revenue)) +} /// This function is used to calculate the in amount of the pool pub fn calculate_in_amount_clp( diff --git a/contracts/stream/src/state.rs b/contracts/stream/src/state.rs index 182bdac..46f339e 100644 --- a/contracts/stream/src/state.rs +++ b/contracts/stream/src/state.rs @@ -1,16 +1,26 @@ use cosmwasm_std::Addr; use cw_storage_plus::{Item, Map}; use streamswap_types::controller::Params; -use streamswap_types::stream::{Position, Stream}; +use streamswap_types::stream::{Position, PostStreamActions, StreamInfo, StreamState}; pub const CONTROLLER_PARAMS: Item = Item::new("params"); -pub const STREAM: Item = Item::new("stream"); +// Stream State Related data +pub const STREAM_STATE: Item = Item::new("ss"); + +// Stream information +pub const STREAM_INFO: Item = Item::new("si"); + +// Post Stream Action Related Information +pub const POST_STREAM: Item = Item::new("ps"); + +pub const TOS: Item = Item::new("tos"); // Subscriber Vesting (owner_addr) -> (contract_addr) pub const SUBSCRIBER_VESTING: Map = Map::new("sub_vest"); -// Creator Vesting (owner_addr) -> (contract_addr) -pub const CREATOR_VESTING: Map = Map::new("cr_vest"); + +// Creator Vesting adrress +pub const CREATOR_VESTING: Item = Item::new("cr_vest"); // Position (stream_id, owner_addr) -> Position pub const POSITIONS: Map<&Addr, Position> = Map::new("positions"); diff --git a/contracts/stream/src/stream.rs b/contracts/stream/src/stream.rs index 126bdd8..5206e17 100644 --- a/contracts/stream/src/stream.rs +++ b/contracts/stream/src/stream.rs @@ -1,8 +1,8 @@ use cosmwasm_std::{Decimal, Decimal256, Fraction, Timestamp, Uint256}; use std::ops::Mul; -use streamswap_types::stream::{Status, Stream}; +use streamswap_types::stream::{Status, StreamState}; -pub fn sync_stream_status(stream: &mut Stream, now: Timestamp) { +pub fn sync_stream_status(stream: &mut StreamState, now: Timestamp) { if matches!( stream.status_info.status, Status::Finalized | Status::Cancelled @@ -24,7 +24,7 @@ pub fn sync_stream_status(stream: &mut Stream, now: Timestamp) { }; } -pub fn compute_shares_amount(stream: &Stream, amount_in: Uint256, round_up: bool) -> Uint256 { +pub fn compute_shares_amount(stream: &StreamState, amount_in: Uint256, round_up: bool) -> Uint256 { if stream.shares.is_zero() || amount_in.is_zero() { return amount_in; } @@ -35,7 +35,7 @@ pub fn compute_shares_amount(stream: &Stream, amount_in: Uint256, round_up: bool shares / stream.in_supply } } -pub fn sync_stream(stream: &mut Stream, now: Timestamp) { +pub fn sync_stream(stream: &mut StreamState, now: Timestamp) { let diff = calculate_diff( stream.status_info.start_time, stream.status_info.end_time, diff --git a/contracts/stream/src/vesting.rs b/contracts/stream/src/vesting.rs new file mode 100644 index 0000000..89b4cd0 --- /dev/null +++ b/contracts/stream/src/vesting.rs @@ -0,0 +1,58 @@ +use crate::ContractError; +use cosmwasm_std::{ + attr, coin, to_json_binary, Addr, Attribute, Binary, CosmosMsg, DepsMut, HexBinary, Timestamp, + Uint128, WasmMsg, +}; +use cw_vesting::msg::InstantiateMsg as VestingInstantiateMsg; +use cw_vesting::UncheckedDenom; +use streamswap_types::controller::VestingConfig; + +pub fn vesting_operations( + deps: &DepsMut, + stream_addr: Addr, + vesting_checksum: HexBinary, + recipient: Addr, + salt: Option, + start_time: Timestamp, + vesting_code_id: u64, + amount: Uint128, + denom: String, + vesting_config: VestingConfig, +) -> Result<(Vec, Vec, Addr), ContractError> { + let salt = salt.ok_or(ContractError::InvalidSalt {})?; + + let vesting_title = format!("Stream addr {} released to {}", stream_addr, recipient); + let vesting_instantiate_msg = VestingInstantiateMsg { + owner: None, + title: vesting_title, + recipient: recipient.to_string(), + description: None, + total: amount, + denom: UncheckedDenom::Native(denom.clone()), + schedule: vesting_config.schedule, + start_time: Some(start_time), + vesting_duration_seconds: vesting_config.vesting_duration_seconds, + unbonding_duration_seconds: vesting_config.unbonding_duration_seconds, + }; + + // Calculate the address of the new contract + let vesting_address = deps.api.addr_humanize(&cosmwasm_std::instantiate2_address( + vesting_checksum.as_ref(), + &deps.api.addr_canonicalize(stream_addr.as_str())?, + &salt, + )?)?; + + let vesting_instantiate_msg = WasmMsg::Instantiate2 { + admin: None, + code_id: vesting_code_id, + label: format!("{}-{}", denom.clone(), recipient), + msg: to_json_binary(&vesting_instantiate_msg)?, + funds: vec![coin(amount.u128(), denom.clone())], + salt, + }; + + let messages = vec![vesting_instantiate_msg.into()]; + let attributes = vec![attr("vesting_address", vesting_address.clone())]; + + Ok((messages, attributes, vesting_address)) +} diff --git a/packages/types/src/stream/stream.rs b/packages/types/src/stream/stream.rs index d2883b1..d3a6c1e 100644 --- a/packages/types/src/stream/stream.rs +++ b/packages/types/src/stream/stream.rs @@ -3,21 +3,11 @@ use cosmwasm_schema::cw_serde; use cosmwasm_std::{Addr, Coin, Decimal256, Timestamp, Uint256}; use streamswap_utils::to_uint256; +/// Active stream status information #[cw_serde] -pub struct Stream { - /// Name of the stream - pub name: String, - /// Treasury address, where the stream creator can withdraw the in assets at the end of the stream - pub treasury: Addr, - /// Stream admin address, where the stream creator can manage the stream, like canceling it in waiting status - /// or finalizing it in ended status - pub stream_admin: Addr, - /// URL of the stream - pub url: Option, +pub struct StreamState { /// Distribution index, used to calculate the amount of out assets to be distributed pub dist_index: Decimal256, - /// Out asset of the stream - pub out_asset: Coin, /// Remaining out asset to be distributed pub out_remaining: Uint256, /// In denom of the stream @@ -31,16 +21,113 @@ pub struct Stream { pub shares: Uint256, /// Current streamed price, the price of in asset in out asset pub current_streamed_price: Decimal256, + /// Out asset of the stream + pub out_asset: Coin, /// Status info of the stream pub status_info: StatusInfo, +} + +impl StreamState { + pub fn new( + now: Timestamp, + out_asset: Coin, + in_denom: String, + bootstrapping_start_time: Timestamp, + start_time: Timestamp, + end_time: Timestamp, + ) -> Self { + StreamState { + dist_index: Decimal256::zero(), + out_asset: out_asset.clone(), + out_remaining: to_uint256(out_asset.amount), + in_denom, + in_supply: Uint256::zero(), + spent_in: Uint256::zero(), + shares: Uint256::zero(), + current_streamed_price: Decimal256::zero(), + status_info: StatusInfo::new(now, bootstrapping_start_time, start_time, end_time), + } + } + + pub fn is_active(&self) -> bool { + self.status_info.status == Status::Active + } + + pub fn is_finalized(&self) -> bool { + self.status_info.status == Status::Finalized + } + + pub fn is_waiting(&self) -> bool { + self.status_info.status == Status::Waiting + } + + pub fn is_cancelled(&self) -> bool { + self.status_info.status == Status::Cancelled + } + + pub fn is_bootstrapping(&self) -> bool { + self.status_info.status == Status::Bootstrapping + } + + pub fn is_ended(&self) -> bool { + self.status_info.status == Status::Ended + } +} + +#[cw_serde] +pub struct StreamInfo { + pub stream_admin: Addr, + /// Name of the stream + pub name: String, + /// Treasury address, where the stream creator can withdraw the in assets at the end of the stream + pub treasury: Addr, + /// Stream admin address, where the stream creator can manage the stream, like canceling it in waiting status + /// or finalizing it in ended status + pub url: Option, + // Tos version + pub tos_version: String, +} + +impl StreamInfo { + pub fn new( + stream_admin: Addr, + name: String, + treasury: Addr, + url: Option, + tos_version: String, + ) -> Self { + StreamInfo { + stream_admin, + name, + treasury, + url, + tos_version, + } + } +} + +#[cw_serde] +pub struct PostStreamActions { /// Pool Configuration for the pre stream pub pool_config: Option, /// Subscriber Vesting configuration, used to create a vesting contract for subscribers once the stream ends pub subscriber_vesting: Option, /// Creator Vesting configuration, used to create a vesting contract for creator once the stream ends pub creator_vesting: Option, - // Tos version - pub tos_version: String, +} + +impl PostStreamActions { + pub fn new( + pool_config: Option, + subscriber_vesting: Option, + creator_vesting: Option, + ) -> Self { + PostStreamActions { + pool_config, + subscriber_vesting, + creator_vesting, + } + } } #[cw_serde] @@ -106,66 +193,3 @@ impl StatusInfo { } } } - -impl Stream { - pub fn new( - now: Timestamp, - name: String, - treasury: Addr, - stream_admin: Addr, - url: Option, - out_asset: Coin, - in_denom: String, - bootstrapping_start_time: Timestamp, - start_time: Timestamp, - end_time: Timestamp, - pool_config: Option, - subscriber_vesting: Option, - creator_vesting: Option, - tos_version: String, - ) -> Self { - Stream { - name, - treasury, - stream_admin, - url, - dist_index: Decimal256::zero(), - out_asset: out_asset.clone(), - out_remaining: to_uint256(out_asset.amount), - in_denom, - in_supply: Uint256::zero(), - spent_in: Uint256::zero(), - shares: Uint256::zero(), - current_streamed_price: Decimal256::zero(), - status_info: StatusInfo::new(now, bootstrapping_start_time, start_time, end_time), - pool_config, - subscriber_vesting, - creator_vesting, - tos_version, - } - } - - pub fn is_active(&self) -> bool { - self.status_info.status == Status::Active - } - - pub fn is_finalized(&self) -> bool { - self.status_info.status == Status::Finalized - } - - pub fn is_waiting(&self) -> bool { - self.status_info.status == Status::Waiting - } - - pub fn is_cancelled(&self) -> bool { - self.status_info.status == Status::Cancelled - } - - pub fn is_bootstrapping(&self) -> bool { - self.status_info.status == Status::Bootstrapping - } - - pub fn is_ended(&self) -> bool { - self.status_info.status == Status::Ended - } -} diff --git a/packages/types/src/stream/threshold.rs b/packages/types/src/stream/threshold.rs index a37193e..7e3a63e 100644 --- a/packages/types/src/stream/threshold.rs +++ b/packages/types/src/stream/threshold.rs @@ -1,4 +1,4 @@ -use crate::stream::{Stream, ThresholdError}; +use crate::stream::{StreamState, ThresholdError}; use cosmwasm_std::{StdError, Storage, Uint256}; use cw_storage_plus::Item; @@ -32,13 +32,13 @@ impl<'a> ThresholdState<'a> { pub fn error_if_not_reached( &self, storage: &dyn Storage, - stream: &Stream, + state: &StreamState, ) -> Result<(), ThresholdError> { // If threshold is not set, It returns ok // If threshold is set, It returns error if threshold is not reached let threshold = self.0.may_load(storage)?; if let Some(threshold) = threshold { - if stream.spent_in < threshold { + if state.spent_in < threshold { Err(ThresholdError::ThresholdNotReached {}) } else { Ok(()) @@ -51,11 +51,11 @@ impl<'a> ThresholdState<'a> { pub fn error_if_reached( &self, storage: &dyn Storage, - stream: &Stream, + state: &StreamState, ) -> Result<(), ThresholdError> { let threshold = self.0.may_load(storage)?; if let Some(threshold) = threshold { - if stream.spent_in >= threshold { + if state.spent_in >= threshold { Err(ThresholdError::ThresholdReached {}) } else { Ok(()) diff --git a/tests/src/tests/streamswap_tests/shares.rs b/tests/src/tests/streamswap_tests/shares.rs index c87f429..95953b4 100644 --- a/tests/src/tests/streamswap_tests/shares.rs +++ b/tests/src/tests/streamswap_tests/shares.rs @@ -1,17 +1,13 @@ #[cfg(test)] mod shares { - use cosmwasm_std::{Addr, Coin, Timestamp, Uint128, Uint256}; + use cosmwasm_std::{Coin, Timestamp, Uint128, Uint256}; use streamswap_stream::stream::compute_shares_amount; - use streamswap_types::stream::Stream; + use streamswap_types::stream::StreamState; #[test] fn test_compute_shares_amount() { - let mut stream = Stream::new( + let mut stream = StreamState::new( Timestamp::from_seconds(0), - "test".to_string(), - Addr::unchecked("treasury"), - Addr::unchecked("stream_admin"), - Some("url".to_string()), Coin { denom: "out_denom".to_string(), amount: Uint128::from(100u128), @@ -20,10 +16,6 @@ mod shares { Timestamp::from_seconds(0), Timestamp::from_seconds(100), Timestamp::from_seconds(0), - None, - None, - None, - "v1".to_string(), ); // add new shares diff --git a/tests/src/tests/streamswap_tests/threshold.rs b/tests/src/tests/streamswap_tests/threshold.rs index c640589..2635986 100644 --- a/tests/src/tests/streamswap_tests/threshold.rs +++ b/tests/src/tests/streamswap_tests/threshold.rs @@ -11,20 +11,16 @@ mod threshold { use streamswap_stream::ContractError as StreamSwapError; use streamswap_types::stream::{ ExecuteMsg as StreamSwapExecuteMsg, QueryMsg as StreamSwapQueryMsg, StreamResponse, - ThresholdError, + StreamState, ThresholdError, }; - use streamswap_types::stream::{Status, Stream, ThresholdState}; + use streamswap_types::stream::{Status, ThresholdState}; #[test] fn thresholds_state() { let mut storage = MockStorage::new(); let thresholds = ThresholdState::new(); - let mut stream = Stream::new( + let mut stream = StreamState::new( Timestamp::from_seconds(0), - "test".to_string(), - Addr::unchecked("treasury"), - Addr::unchecked("stream_admin"), - Some("url".to_string()), Coin { denom: "out_denom".to_string(), amount: Uint128::from(100u128), @@ -33,10 +29,6 @@ mod threshold { Timestamp::from_seconds(0), Timestamp::from_seconds(100), Timestamp::from_seconds(0), - None, - None, - None, - "v1".to_string(), ); let threshold = Uint256::from(1_500_000_000_000u128); diff --git a/tests/src/tests/streamswap_tests/vesting.rs b/tests/src/tests/streamswap_tests/vesting.rs index d7c40eb..b64ac05 100644 --- a/tests/src/tests/streamswap_tests/vesting.rs +++ b/tests/src/tests/streamswap_tests/vesting.rs @@ -147,8 +147,7 @@ mod vesting { ) .unwrap(); - let vesting_addr = - get_wasm_attribute_with_key(res, "subscriber_vesting_address".to_string()); + let vesting_addr = get_wasm_attribute_with_key(res, "vesting_address".to_string()); let contract_data = app .contract_data(&Addr::unchecked(vesting_addr.clone())) .unwrap(); @@ -280,8 +279,7 @@ mod vesting { assert_eq!(stream.status, Status::Finalized); - let vesting_addr = - get_wasm_attribute_with_key(res.clone(), "creator_vesting_address".to_string()); + let vesting_addr = get_wasm_attribute_with_key(res.clone(), "vesting_address".to_string()); let contract_data = app .contract_data(&Addr::unchecked(vesting_addr.clone())) .unwrap(); @@ -293,7 +291,7 @@ mod vesting { &cw_vesting::msg::QueryMsg::Info {}, ) .unwrap(); - assert_eq!(res.denom, CheckedDenom::Native("out_denom".to_string())); + assert_eq!(res.denom, CheckedDenom::Native("in_denom".to_string())); assert_eq!(res.recipient, test_accounts.creator_1.to_string()); assert_eq!(res.status, cw_vesting::vesting::Status::Funded); assert_eq!(res.title, "Stream addr cosmwasm1kdd9vp4j37tualwzsgdkn6cynmzss508r9n9ru7ngcwhlt2y2e0qyy6pcp released to cosmwasm12gsczjjdz9d73prnx0nvrn23h6x7fqawlrrphv63v0jy7uhegmus0vfkrm" );