Skip to content

Commit

Permalink
move from SudoMsg to executor config
Browse files Browse the repository at this point in the history
  • Loading branch information
codehans committed Mar 11, 2024
1 parent cacc037 commit eaaf81b
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 25 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ Simple smart-contract layer to allow aggregation of reward tokens and swapping i

One contract instance is deployed per revenue token.

Each instance has a set of `Action`s that are stepped through on subsequent executions of `SudoMsg::Run`.
Each instance has a set of `Action`s that are stepped through on subsequent executions of `ExecuteMsg::Run`.
This is designed to keep execution of the contract in fixed time, and also support more complex routing of token swaps.
At the end of each execution, `revenue_token` balance is read and is deposited to the fee_collector address.
116 changes: 97 additions & 19 deletions src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ use cosmwasm_std::{
to_json_binary, Addr, Binary, CosmosMsg, Deps, DepsMut, Env, Event, MessageInfo, Reply,
Response, StdResult, SubMsg,
};
use kujira::{fee_address, Denom};
use kujira::Denom;

use crate::error::ContractError;
use crate::msg::{
ActionResponse, ActionsResponse, ConfigResponse, ExecuteMsg, InstantiateMsg, QueryMsg,
StatusResponse, SudoMsg,
StatusResponse,
};
use crate::state::{Action, Config};

Expand All @@ -33,35 +33,51 @@ pub fn instantiate(
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
deps: DepsMut,
_env: Env,
env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
let mut config = Config::load(deps.storage)?;
if info.sender != config.owner.to_string() {
return Err(ContractError::Unauthorized {});
}
match msg {
ExecuteMsg::SetOwner(owner) => {
if info.sender != config.owner.to_string() {
return Err(ContractError::Unauthorized {});
}

config.owner = owner;
config.save(deps.storage)?;
Ok(Response::default())
}
ExecuteMsg::SetAction(action) => {
if info.sender != config.owner.to_string() {
return Err(ContractError::Unauthorized {});
}

Action::set(deps.storage, action)?;
Ok(Response::default())
}
ExecuteMsg::UnsetAction(denom) => {
if info.sender != config.owner.to_string() {
return Err(ContractError::Unauthorized {});
}

Action::unset(deps.storage, denom);
Ok(Response::default())
}
}
}
ExecuteMsg::SetExecutor(executor) => {
if info.sender != config.owner.to_string() {
return Err(ContractError::Unauthorized {});
}

config.executor = executor;
config.save(deps.storage)?;
Ok(Response::default())
}
ExecuteMsg::Run {} => {
if info.sender != config.executor.to_string() {
return Err(ContractError::Unauthorized {});
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn sudo(deps: DepsMut, env: Env, msg: SudoMsg) -> Result<Response, ContractError> {
match msg {
SudoMsg::Run {} => {
if let Some((action, msg)) = get_action_msg(deps, &env.contract.address)? {
let event =
Event::new("revenue/run").add_attribute("denom", action.denom.to_string());
Expand Down Expand Up @@ -127,6 +143,7 @@ mod tests {
testing::{mock_dependencies, mock_dependencies_with_balances, mock_env, mock_info},
Uint128,
};
use kujira::fee_address;

#[test]
fn instantiation() {
Expand All @@ -136,6 +153,7 @@ mod tests {
owner: Addr::unchecked("owner"),
target_denom: Denom::from("ukuji"),
target_address: fee_address(),
executor: Addr::unchecked("executor"),
};
instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
let config: ConfigResponse =
Expand All @@ -157,6 +175,7 @@ mod tests {
owner: Addr::unchecked("owner"),
target_denom: Denom::from("ukuji"),
target_address: fee_address(),
executor: Addr::unchecked("executor"),
};
instantiate(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();

Expand Down Expand Up @@ -229,6 +248,22 @@ mod tests {
let actions: ActionsResponse =
from_json(query(deps.as_ref(), mock_env(), QueryMsg::Actions {}).unwrap()).unwrap();
assert_eq!(actions.actions, vec![]);

execute(
deps.as_mut(),
mock_env(),
mock_info("owner-new", &vec![]),
ExecuteMsg::Run {},
)
.unwrap_err();

execute(
deps.as_mut(),
mock_env(),
mock_info("executor", &vec![]),
ExecuteMsg::Run {},
)
.unwrap();
}

#[test]
Expand All @@ -248,11 +283,18 @@ mod tests {
owner: Addr::unchecked("owner"),
target_denom: Denom::from("ukuji"),
target_address: fee_address(),
executor: Addr::unchecked("executor"),
};
instantiate(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();

// Make sure that execution ends when there are no actions
sudo(deps.as_mut(), mock_env(), SudoMsg::Run {}).unwrap();
execute(
deps.as_mut(),
mock_env(),
mock_info("executor", &vec![]),
ExecuteMsg::Run {},
)
.unwrap();
let status: StatusResponse =
from_json(query(deps.as_ref(), mock_env(), QueryMsg::Status {}).unwrap()).unwrap();
assert_eq!(status.last, None);
Expand All @@ -269,15 +311,27 @@ mod tests {
set_action(deps.as_mut(), "token-d", "contract-d", Uint128::MAX);
set_action(deps.as_mut(), "token-e", "contract-e", Uint128::MAX);

let res = sudo(deps.as_mut(), mock_env(), SudoMsg::Run {}).unwrap();
let res = execute(
deps.as_mut(),
mock_env(),
mock_info("executor", &vec![]),
ExecuteMsg::Run {},
)
.unwrap();
// Nothing done
assert_eq!(res.events.len(), 0);
let status: StatusResponse =
from_json(query(deps.as_ref(), mock_env(), QueryMsg::Status {}).unwrap()).unwrap();
assert_eq!(status.last, Some(Denom::from("token-a")));

// Iterator should start at the beginning again and execute token-a
let res = sudo(deps.as_mut(), mock_env(), SudoMsg::Run {}).unwrap();
let res = execute(
deps.as_mut(),
mock_env(),
mock_info("executor", &vec![]),
ExecuteMsg::Run {},
)
.unwrap();
let status: StatusResponse =
from_json(query(deps.as_ref(), mock_env(), QueryMsg::Status {}).unwrap()).unwrap();
assert_eq!(status.last, Some(Denom::from("token-b")));
Expand All @@ -286,16 +340,40 @@ mod tests {
assert_eq!(res.events[0].clone().attributes[0].clone().value, "token-b");

// Run for c, d, e and then loop back to a
let res = sudo(deps.as_mut(), mock_env(), SudoMsg::Run {}).unwrap();
let res = execute(
deps.as_mut(),
mock_env(),
mock_info("executor", &vec![]),
ExecuteMsg::Run {},
)
.unwrap();
assert_eq!(res.events[0].clone().attributes[0].clone().value, "token-c");

let res = sudo(deps.as_mut(), mock_env(), SudoMsg::Run {}).unwrap();
let res = execute(
deps.as_mut(),
mock_env(),
mock_info("executor", &vec![]),
ExecuteMsg::Run {},
)
.unwrap();
assert_eq!(res.events[0].clone().attributes[0].clone().value, "token-d");

let res = sudo(deps.as_mut(), mock_env(), SudoMsg::Run {}).unwrap();
let res = execute(
deps.as_mut(),
mock_env(),
mock_info("executor", &vec![]),
ExecuteMsg::Run {},
)
.unwrap();
assert_eq!(res.events[0].clone().attributes[0].clone().value, "token-e");

let res = sudo(deps.as_mut(), mock_env(), SudoMsg::Run {}).unwrap();
let res = execute(
deps.as_mut(),
mock_env(),
mock_info("executor", &vec![]),
ExecuteMsg::Run {},
)
.unwrap();

assert_eq!(res.events.len(), 0);
let status: StatusResponse =
Expand Down
9 changes: 4 additions & 5 deletions src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@ use crate::state::Action;
#[cw_serde]
pub struct InstantiateMsg {
pub owner: Addr,
pub executor: Addr,
pub target_denom: Denom,
pub target_address: Addr,
}

#[cw_serde]
pub enum ExecuteMsg {
SetOwner(Addr),
SetExecutor(Addr),
SetAction(Action),
UnsetAction(Denom),
Run {},
}

#[cw_serde]
Expand All @@ -32,6 +35,7 @@ pub enum QueryMsg {
#[cw_serde]
pub struct ConfigResponse {
pub owner: Addr,
pub executor: Addr,
pub target_denom: Denom,
pub target_address: Addr,
}
Expand All @@ -52,8 +56,3 @@ pub struct ActionResponse {
pub struct StatusResponse {
pub last: Option<Denom>,
}

#[cw_serde]
pub enum SudoMsg {
Run {},
}
6 changes: 6 additions & 0 deletions src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ static ACTIONS: Map<String, (Addr, Uint128, Binary)> = Map::new("actions");
pub struct Config {
/// The address permitted to set Actions
pub owner: Addr,

/// The address permitted to execute the crank
pub executor: Addr,

/// The denom that is transferred to the fee_collector at the end of every execution
pub target_denom: Denom,

Expand All @@ -37,6 +41,7 @@ impl From<InstantiateMsg> for Config {
fn from(value: InstantiateMsg) -> Self {
Self {
owner: value.owner,
executor: value.executor,
target_denom: value.target_denom,
target_address: value.target_address,
}
Expand All @@ -47,6 +52,7 @@ impl From<Config> for ConfigResponse {
fn from(value: Config) -> Self {
Self {
owner: value.owner,
executor: value.executor,
target_denom: value.target_denom,
target_address: value.target_address,
}
Expand Down

0 comments on commit eaaf81b

Please sign in to comment.