Skip to content

Commit

Permalink
Merge pull request #6 from StreamSwapProtocol/sudo-permissions-update
Browse files Browse the repository at this point in the history
Sudo and admin permissions reworked
  • Loading branch information
MightOfOaks authored Apr 8, 2023
2 parents a9bcf60 + d78a166 commit 4e8e096
Show file tree
Hide file tree
Showing 4 changed files with 601 additions and 268 deletions.
128 changes: 64 additions & 64 deletions src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,12 @@ pub fn execute(
ExecuteMsg::PauseStream { stream_id } => {
killswitch::execute_pause_stream(deps, env, info, stream_id)
}
ExecuteMsg::ResumeStream { stream_id } => {
killswitch::execute_resume_stream(deps, env, info, stream_id)
}
ExecuteMsg::CancelStream { stream_id } => {
killswitch::execute_cancel_stream(deps, env, info, stream_id)
}
ExecuteMsg::WithdrawPaused {
stream_id,
cap,
Expand All @@ -173,12 +179,29 @@ pub fn execute(
stream_id,
operator_target,
} => killswitch::execute_exit_cancelled(deps, env, info, stream_id, operator_target),
ExecuteMsg::UpdateFeeCollector { fee_collector } => {
execute_update_fee_collector(deps, info, fee_collector)
}
ExecuteMsg::UpdateProtocolAdmin {
new_protocol_admin: new_admin,
} => execute_update_protocol_admin(deps, env, info, new_admin),
ExecuteMsg::UpdateConfig {
min_stream_duration,
min_duration_until_start_time,
stream_creation_denom,
stream_creation_fee,
fee_collector,
accepted_in_denom,
exit_fee_percent,
} => execute_update_config(
deps,
env,
info,
min_stream_duration,
min_duration_until_start_time,
stream_creation_denom,
stream_creation_fee,
fee_collector,
accepted_in_denom,
exit_fee_percent,
),
}
}
#[allow(clippy::too_many_arguments)]
Expand Down Expand Up @@ -742,7 +765,6 @@ pub fn execute_withdraw_pending(
operator_target: Option<String>,
) -> Result<Response, ContractError> {
// check if stream is paused

let operator_target =
maybe_addr(deps.api, operator_target)?.unwrap_or_else(|| info.sender.clone());
let mut position = POSITIONS.load(deps.storage, (stream_id, &operator_target))?;
Expand Down Expand Up @@ -976,69 +998,11 @@ pub fn execute_exit_stream(
}
}

pub fn execute_update_fee_collector(
deps: DepsMut,
info: MessageInfo,
fee_collector: String,
) -> Result<Response, ContractError> {
let mut config = CONFIG.load(deps.storage)?;
if info.sender != config.protocol_admin {
return Err(ContractError::Unauthorized {});
}
config.fee_collector = deps.api.addr_validate(&fee_collector)?;
CONFIG.save(deps.storage, &config)?;
Ok(Response::new().add_attributes(vec![
attr("action", "update_fee_collector"),
attr("fee_collector", fee_collector),
]))
}

fn check_access(
info: &MessageInfo,
position_owner: &Addr,
position_operator: &Option<Addr>,
) -> Result<(), ContractError> {
if position_owner.as_ref() != info.sender
&& position_operator
.as_ref()
.map_or(true, |o| o != &info.sender)
{
return Err(ContractError::Unauthorized {});
}
Ok(())
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn sudo(deps: DepsMut, env: Env, msg: SudoMsg) -> Result<Response, ContractError> {
match msg {
SudoMsg::UpdateConfig {
min_stream_duration,
min_duration_until_start_time,
stream_creation_denom,
stream_creation_fee,
fee_collector,
accepted_in_denom,
exit_fee_percent,
} => sudo_update_config(
deps,
env,
min_stream_duration,
min_duration_until_start_time,
stream_creation_denom,
stream_creation_fee,
fee_collector,
accepted_in_denom,
exit_fee_percent,
),
SudoMsg::PauseStream { stream_id } => killswitch::sudo_pause_stream(deps, env, stream_id),
SudoMsg::CancelStream { stream_id } => killswitch::sudo_cancel_stream(deps, env, stream_id),
SudoMsg::ResumeStream { stream_id } => killswitch::sudo_resume_stream(deps, env, stream_id),
}
}
#[allow(clippy::too_many_arguments)]
pub fn sudo_update_config(
pub fn execute_update_config(
deps: DepsMut,
_env: Env,
info: MessageInfo,
min_stream_duration: Option<Uint64>,
min_duration_until_start_time: Option<Uint64>,
stream_creation_denom: Option<String>,
Expand All @@ -1049,11 +1013,21 @@ pub fn sudo_update_config(
) -> Result<Response, ContractError> {
let mut cfg = CONFIG.load(deps.storage)?;

if info.sender != cfg.protocol_admin {
return Err(ContractError::Unauthorized {});
}

if let Some(stream_creation_fee) = stream_creation_fee {
if stream_creation_fee.is_zero() {
return Err(ContractError::InvalidStreamCreationFee {});
}
}
// exit fee percent can not be equal to or greater than 1, or smaller than 0
if let Some(exit_fee_percent) = exit_fee_percent {
if exit_fee_percent >= Decimal::one() || exit_fee_percent < Decimal::zero() {
return Err(ContractError::InvalidExitFeePercent {});
}
}

cfg.min_stream_seconds = min_stream_duration.unwrap_or(cfg.min_stream_seconds);
cfg.min_seconds_until_start_time =
Expand Down Expand Up @@ -1082,6 +1056,30 @@ pub fn sudo_update_config(
Ok(Response::default().add_attributes(attributes))
}

fn check_access(
info: &MessageInfo,
position_owner: &Addr,
position_operator: &Option<Addr>,
) -> Result<(), ContractError> {
if position_owner.as_ref() != info.sender
&& position_operator
.as_ref()
.map_or(true, |o| o != &info.sender)
{
return Err(ContractError::Unauthorized {});
}
Ok(())
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn sudo(deps: DepsMut, env: Env, msg: SudoMsg) -> Result<Response, ContractError> {
match msg {
SudoMsg::PauseStream { stream_id } => killswitch::sudo_pause_stream(deps, env, stream_id),
SudoMsg::CancelStream { stream_id } => killswitch::sudo_cancel_stream(deps, env, stream_id),
SudoMsg::ResumeStream { stream_id } => killswitch::sudo_resume_stream(deps, env, stream_id),
}
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
let contract_info = get_contract_version(deps.storage)?;
Expand Down Expand Up @@ -1160,6 +1158,7 @@ pub fn query_stream(deps: Deps, _env: Env, stream_id: u64) -> StdResult<StreamRe
url: stream.url,
current_streamed_price: stream.current_streamed_price,
exit_fee_percent: stream.stream_exit_fee_percent,
stream_creation_fee: stream.stream_creation_fee,
};
Ok(stream)
}
Expand Down Expand Up @@ -1199,6 +1198,7 @@ pub fn list_streams(
url: stream.url,
current_streamed_price: stream.current_streamed_price,
exit_fee_percent: stream.stream_exit_fee_percent,
stream_creation_fee: stream.stream_creation_fee,
};
Ok(stream)
})
Expand Down
98 changes: 91 additions & 7 deletions src/killswitch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,90 @@ pub fn pause_stream(now: Timestamp, stream: &mut Stream) -> StdResult<()> {
Ok(())
}

pub fn execute_resume_stream(
deps: DepsMut,
env: Env,
info: MessageInfo,
stream_id: u64,
) -> Result<Response, ContractError> {
let mut stream = STREAMS.load(deps.storage, stream_id)?;
let cfg = CONFIG.load(deps.storage)?;
//Cancelled can't be resumed
if stream.is_cancelled() {
return Err(ContractError::StreamIsCancelled {});
}
if stream.status != Status::Paused {
return Err(ContractError::StreamNotPaused {});
}
if cfg.protocol_admin != info.sender {
return Err(ContractError::Unauthorized {});
}

let pause_date = stream.pause_date.unwrap();
//postpone stream times with respect to pause duration
stream.end_time = stream
.end_time
.plus_nanos(env.block.time.nanos() - pause_date.nanos());
stream.last_updated = stream
.last_updated
.plus_nanos(env.block.time.nanos() - pause_date.nanos());

stream.status = Status::Active;
STREAMS.save(deps.storage, stream_id, &stream)?;

let attributes = vec![
attr("action", "resume_stream"),
attr("stream_id", stream_id.to_string()),
];
Ok(Response::default().add_attributes(attributes))
}

pub fn execute_cancel_stream(
deps: DepsMut,
_env: Env,
info: MessageInfo,
stream_id: u64,
) -> Result<Response, ContractError> {
let cfg = CONFIG.load(deps.storage)?;
if cfg.protocol_admin != info.sender {
return Err(ContractError::Unauthorized {});
}
let mut stream = STREAMS.load(deps.storage, stream_id)?;
if stream.is_cancelled() {
return Err(ContractError::StreamIsCancelled {});
}
if !stream.is_paused() {
return Err(ContractError::StreamNotPaused {});
}
stream.status = Status::Cancelled;
STREAMS.save(deps.storage, stream_id, &stream)?;

//Refund all out tokens to stream creator(treasury)
let messages: Vec<CosmosMsg> = vec![
CosmosMsg::Bank(BankMsg::Send {
to_address: stream.treasury.to_string(),
amount: vec![Coin {
denom: stream.out_denom,
amount: stream.out_supply,
}],
}),
//Refund stream creation fee to stream creator
CosmosMsg::Bank(BankMsg::Send {
to_address: stream.treasury.to_string(),
amount: vec![Coin {
denom: stream.stream_creation_denom,
amount: stream.stream_creation_fee,
}],
}),
];

Ok(Response::new()
.add_attribute("action", "cancel_stream")
.add_messages(messages)
.add_attribute("stream_id", stream_id.to_string())
.add_attribute("status", "cancelled"))
}

pub fn sudo_pause_stream(
deps: DepsMut,
env: Env,
Expand Down Expand Up @@ -216,14 +300,14 @@ pub fn sudo_resume_stream(
stream_id: u64,
) -> Result<Response, ContractError> {
let mut stream = STREAMS.load(deps.storage, stream_id)?;
//Cancelled can't be resumed
if stream.is_cancelled() {
return Err(ContractError::StreamIsCancelled {});
}
//Only paused can be resumed
if !stream.is_paused() {
return Err(ContractError::StreamNotPaused {});
}
//Canceled can't be resumed
if stream.is_cancelled() {
return Err(ContractError::StreamIsCancelled {});
}
// ok to use unwrap here
let pause_date = stream.pause_date.unwrap();
//postpone stream times with respect to pause duration
Expand Down Expand Up @@ -251,12 +335,12 @@ pub fn sudo_cancel_stream(
stream_id: u64,
) -> Result<Response, ContractError> {
let mut stream = STREAMS.load(deps.storage, stream_id)?;
if !stream.is_paused() {
return Err(ContractError::StreamNotPaused {});
}
if stream.is_cancelled() {
return Err(ContractError::StreamIsCancelled {});
}
if !stream.is_paused() {
return Err(ContractError::StreamNotPaused {});
}
stream.status = Status::Cancelled;
STREAMS.save(deps.storage, stream_id, &stream)?;

Expand Down
43 changes: 19 additions & 24 deletions src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,20 @@ pub enum ExecuteMsg {
operator_target: Option<String>,
},

/// Update fee collector address
/// Only protocol admin can update fee collector address
/// Fee collector address is used to collect exit fees
/// Fee collector address can also be updated by governance
UpdateFeeCollector {
fee_collector: String,
UpdateConfig {
min_stream_duration: Option<Uint64>,
min_duration_until_start_time: Option<Uint64>,
stream_creation_denom: Option<String>,
stream_creation_fee: Option<Uint128>,
fee_collector: Option<String>,
accepted_in_denom: Option<String>,
exit_fee_percent: Option<Decimal>,
},
ResumeStream {
stream_id: u64,
},
CancelStream {
stream_id: u64,
},
}

Expand Down Expand Up @@ -219,6 +227,8 @@ pub struct StreamResponse {
pub pause_date: Option<Timestamp>,
/// Exit fee percent.
pub exit_fee_percent: Decimal,
/// Creation fee amount.
pub stream_creation_fee: Uint128,
}

#[cw_serde]
Expand Down Expand Up @@ -264,24 +274,9 @@ pub struct LatestStreamedPriceResponse {

#[cw_serde]
pub enum SudoMsg {
UpdateConfig {
min_stream_duration: Option<Uint64>,
min_duration_until_start_time: Option<Uint64>,
stream_creation_denom: Option<String>,
stream_creation_fee: Option<Uint128>,
fee_collector: Option<String>,
accepted_in_denom: Option<String>,
exit_fee_percent: Option<Decimal>,
},
PauseStream {
stream_id: u64,
},
CancelStream {
stream_id: u64,
},
ResumeStream {
stream_id: u64,
},
PauseStream { stream_id: u64 },
CancelStream { stream_id: u64 },
ResumeStream { stream_id: u64 },
}

#[cw_serde]
Expand Down
Loading

0 comments on commit 4e8e096

Please sign in to comment.