Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fabo/delay ownership #82

Merged
merged 2 commits into from
Dec 3, 2023
Merged
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
1 change: 1 addition & 0 deletions contracts/staking/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ pub fn instantiate(
total_fees: Uint128::zero(),
ibc_id_counter: 0,
rate: 1u128.into(),
owner_transfer_min_time: None,
};

STATE.save(deps.storage, &state)?;
Expand Down
5 changes: 4 additions & 1 deletion contracts/staking/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use cosmwasm_std::{StdError, Uint128};
use cosmwasm_std::{StdError, Timestamp, Uint128};
use cw_controllers::AdminError;
use cw_utils::PaymentError;
use milky_way::staking::BatchStatus;
Expand All @@ -21,6 +21,9 @@ pub enum ContractError {
#[error("No pending owner")]
NoPendingOwner {},

#[error("Ownership transfer not ready")]
OwnershipTransferNotReady { time_to_claim: Timestamp },

#[error("Payment error: {0}")]
Payment(#[from] PaymentError),

Expand Down
19 changes: 17 additions & 2 deletions contracts/staking/src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ pub fn execute_remove_validator(
// Transfer ownership to another account; callable by the owner
// This will require the new owner to accept to take effect.
// No need to handle case of overwriting the pending owner
// Ownership can only be claimed after 7 days to mitigate fat finger errors
pub fn execute_transfer_ownership(
deps: DepsMut,
_env: Env,
Expand All @@ -476,8 +477,11 @@ pub fn execute_transfer_ownership(
) -> ContractResult<Response> {
ADMIN.assert_admin(deps.as_ref(), &info.sender)?;

let mut state = STATE.load(deps.storage)?;
let mut state: State = STATE.load(deps.storage)?;
state.pending_owner = Some(deps.api.addr_validate(&new_owner)?);
state.owner_transfer_min_time = Some(Timestamp::from_seconds(
_env.block.time.seconds() + 60 * 60 * 24 * 7,
)); // 7 days

STATE.save(deps.storage, &state)?;

Expand All @@ -497,6 +501,7 @@ pub fn execute_revoke_ownership_transfer(

let mut state = STATE.load(deps.storage)?;
state.pending_owner = None;
state.owner_transfer_min_time = None;

STATE.save(deps.storage, &state)?;

Expand All @@ -508,8 +513,18 @@ pub fn execute_accept_ownership(
_env: Env,
info: MessageInfo,
) -> ContractResult<Response> {
let mut state: State = STATE.load(deps.storage)?;
if state.owner_transfer_min_time.is_some()
&& state.owner_transfer_min_time.unwrap().seconds() > _env.block.time.seconds()
{
return Err(ContractError::OwnershipTransferNotReady {
time_to_claim: Timestamp::from_seconds(
state.owner_transfer_min_time.unwrap().seconds(),
),
});
}

let new_owner = {
let mut state = STATE.load(deps.storage)?;
match state.pending_owner {
Some(pending_owner) if pending_owner == info.sender => {
state.pending_owner = None;
Expand Down
1 change: 1 addition & 0 deletions contracts/staking/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub struct State {
pub total_native_token: Uint128,
pub total_liquid_stake_token: Uint128,
pub pending_owner: Option<Addr>,
pub owner_transfer_min_time: Option<Timestamp>,
pub total_reward_amount: Uint128,
pub rate: Uint128,
pub total_fees: Uint128,
Expand Down
14 changes: 11 additions & 3 deletions contracts/staking/src/tests/ownership_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,23 @@ mod ownership_tests {
new_owner: "new_owner".to_string(),
};

let res = execute(deps.as_mut(), mock_env(), info, msg);
let mut env = mock_env();

let res = execute(deps.as_mut(), env.clone(), info, msg);
assert!(res.is_ok());

let info = mock_info("new_owner", &coins(1000, "uosmo"));
let msg = ExecuteMsg::AcceptOwnership {};

let res2 = execute(deps.as_mut(), mock_env(), info, msg);
let res = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone());
assert!(res.is_err()); // no time yet

let attrs = res2.unwrap().attributes;
env.block.time = mock_env().block.time.plus_seconds(60 * 60 * 24 * 7);

let res = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone());
assert!(res.is_ok());

let attrs = res.unwrap().attributes;
assert_eq!(attrs[0].value, "accept_ownership");
assert_eq!(attrs[1].value, "new_owner");
}
Expand Down