Skip to content

Commit

Permalink
feat: add optional allowlist for registering DRE
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesondh committed Mar 27, 2024
1 parent dab942e commit f8303a6
Show file tree
Hide file tree
Showing 14 changed files with 245 additions and 49 deletions.
2 changes: 2 additions & 0 deletions packages/common/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ pub enum ContractError {
NotPendingOwner,
#[error("NoPendingOwnerFound: No pending owner found")]
NoPendingOwnerFound,
#[error("NotOnAllowlist: Address is not on the allowlist")]
NotOnAllowlist,

// DR contract errors
#[error("InsufficientFunds: Insufficient funds. Required: {0}, available: {1}")]
Expand Down
10 changes: 9 additions & 1 deletion packages/common/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub enum DataRequestsExecuteMsg {
#[cw_serde]
pub enum StakingExecuteMsg {
RegisterDataRequestExecutor {
p2p_multi_address: Option<String>,
memo: Option<String>,
sender: Option<String>,
},
UnregisterDataRequestExecutor {
Expand All @@ -67,6 +67,14 @@ pub enum StakingExecuteMsg {
SetStakingConfig {
config: StakingConfig,
},
AddToAllowlist {
sender: Option<String>,
address: Addr,
},
RemoveFromAllowlist {
sender: Option<String>,
address: Addr,
},
}

#[cw_serde]
Expand Down
4 changes: 3 additions & 1 deletion packages/common/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ pub struct Reveal {
/// A data request executor with staking info and optional p2p multi address
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, JsonSchema)]
pub struct DataRequestExecutor {
pub p2p_multi_address: Option<String>,
pub memo: Option<String>,
pub tokens_staked: u128,
pub tokens_pending_withdrawal: u128,
}
Expand All @@ -91,4 +91,6 @@ pub struct StakingConfig {
pub minimum_stake_to_register: u128,
/// Minimum amount of SEDA tokens required to be eligible for committee inclusion
pub minimum_stake_for_committee_eligibility: u128,
/// Whether the allowlist is enabled
pub allowlist_enabled: bool,
}
4 changes: 2 additions & 2 deletions packages/integration-tests/src/data_result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn commit_reveal_result() {
send_tokens(&mut app, USER, EXECUTOR_2, 1);
send_tokens(&mut app, USER, EXECUTOR_3, 1);
let msg = ProxyExecuteMsg::RegisterDataRequestExecutor {
p2p_multi_address: Some("address".to_string()),
memo: Some("address".to_string()),
};
let cosmos_msg = proxy_contract
.call_with_deposit(msg, INITIAL_MINIMUM_STAKE_TO_REGISTER)
Expand Down Expand Up @@ -286,7 +286,7 @@ fn pop_and_swap_in_pool() {
send_tokens(&mut app, USER, EXECUTOR_1, 1);
send_tokens(&mut app, USER, EXECUTOR_2, 1);
let msg = ProxyExecuteMsg::RegisterDataRequestExecutor {
p2p_multi_address: Some("address".to_string()),
memo: Some("address".to_string()),
};
let cosmos_msg = proxy_contract
.call_with_deposit(msg, INITIAL_MINIMUM_STAKE_TO_REGISTER)
Expand Down
10 changes: 5 additions & 5 deletions packages/integration-tests/src/staking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fn deposit_stake_withdraw() {
send_tokens(&mut app, USER, EXECUTOR_1, 3);

let msg = ProxyExecuteMsg::RegisterDataRequestExecutor {
p2p_multi_address: Some("address".to_string()),
memo: Some("address".to_string()),
};
let cosmos_msg = proxy_contract
.call_with_deposit(msg, INITIAL_MINIMUM_STAKE_TO_REGISTER)
Expand All @@ -36,7 +36,7 @@ fn deposit_stake_withdraw() {
res,
GetDataRequestExecutorResponse {
value: Some(DataRequestExecutor {
p2p_multi_address: Some("address".to_string()),
memo: Some("address".to_string()),
tokens_staked: 1,
tokens_pending_withdrawal: 0
})
Expand All @@ -61,7 +61,7 @@ fn deposit_stake_withdraw() {
res,
GetDataRequestExecutorResponse {
value: Some(DataRequestExecutor {
p2p_multi_address: Some("address".to_string()),
memo: Some("address".to_string()),
tokens_staked: 3,
tokens_pending_withdrawal: 0
})
Expand All @@ -86,7 +86,7 @@ fn deposit_stake_withdraw() {
res,
GetDataRequestExecutorResponse {
value: Some(DataRequestExecutor {
p2p_multi_address: Some("address".to_string()),
memo: Some("address".to_string()),
tokens_staked: 1,
tokens_pending_withdrawal: 2
})
Expand Down Expand Up @@ -119,7 +119,7 @@ fn deposit_stake_withdraw() {
res,
GetDataRequestExecutorResponse {
value: Some(DataRequestExecutor {
p2p_multi_address: Some("address".to_string()),
memo: Some("address".to_string()),
tokens_staked: 1,
tokens_pending_withdrawal: 0
})
Expand Down
24 changes: 22 additions & 2 deletions packages/proxy/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ pub fn execute(
.add_attribute("action", "reveal_data_result")),

// Staking
ProxyExecuteMsg::RegisterDataRequestExecutor { p2p_multi_address } => {
ProxyExecuteMsg::RegisterDataRequestExecutor { memo } => {
// require token deposit
let token = TOKEN.load(deps.storage)?;
let amount = get_attached_funds(&info.funds, &token)?;
Expand All @@ -139,7 +139,7 @@ pub fn execute(
.add_message(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: STAKING.load(deps.storage)?.to_string(),
msg: to_json_binary(&StakingExecuteMsg::RegisterDataRequestExecutor {
p2p_multi_address,
memo,
sender: Some(info.sender.to_string()),
})?,
funds: vec![Coin {
Expand Down Expand Up @@ -196,6 +196,26 @@ pub fn execute(
funds: vec![],
}))
.add_attribute("action", "withdraw")),
ProxyExecuteMsg::AddToAllowlist { address } => Ok(Response::new()
.add_message(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: STAKING.load(deps.storage)?.to_string(),
msg: to_json_binary(&StakingExecuteMsg::AddToAllowlist {
sender: Some(info.sender.to_string()),
address,
})?,
funds: vec![],
}))
.add_attribute("action", "add_to_allowlist")),
ProxyExecuteMsg::RemoveFromAllowlist { address } => Ok(Response::new()
.add_message(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: STAKING.load(deps.storage)?.to_string(),
msg: to_json_binary(&StakingExecuteMsg::RemoveFromAllowlist {
sender: Some(info.sender.to_string()),
address,
})?,
funds: vec![],
}))
.add_attribute("action", "remove_from_allowlist")),
}
}

Expand Down
4 changes: 3 additions & 1 deletion packages/proxy/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@ pub enum ProxyExecuteMsg {
CommitDataResult { dr_id: Hash, commitment: Hash },
RevealDataResult { dr_id: Hash, reveal: Reveal },
// Staking
RegisterDataRequestExecutor { p2p_multi_address: Option<String> },
RegisterDataRequestExecutor { memo: Option<String> },
UnregisterDataRequestExecutor {},
DepositAndStake,
Unstake { amount: u128 },
Withdraw { amount: u128 },
AddToAllowlist { address: Addr },
RemoveFromAllowlist { address: Addr },
}

#[cw_serde]
Expand Down
131 changes: 131 additions & 0 deletions packages/staking/src/allowlist.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
pub mod allow_list {
use crate::state::{ALLOWLIST, OWNER};
use crate::utils::validate_sender;
use common::error::ContractError;
#[cfg(not(feature = "library"))]
use cosmwasm_std::{Addr, DepsMut, MessageInfo, Response};

pub fn add_to_allowlist(
deps: DepsMut,
info: MessageInfo,
sender: Option<String>,
address: Addr,
) -> Result<Response, ContractError> {
let sender = validate_sender(&deps, info.sender, sender)?;

// require the sender to be the OWNER
let owner = OWNER.load(deps.storage)?;
if sender != owner {
return Err(ContractError::NotOwner);
}

// add the address to the allowlist
ALLOWLIST.save(deps.storage, address, &true)?;

Ok(Response::new())
}

pub fn remove_from_allowlist(
deps: DepsMut,
info: MessageInfo,
sender: Option<String>,
address: Addr,
) -> Result<Response, ContractError> {
let sender = validate_sender(&deps, info.sender, sender)?;

// require the sender to be the OWNER
let owner = OWNER.load(deps.storage)?;
if sender != owner {
return Err(ContractError::NotOwner);
}

// remove the address from the allowlist
ALLOWLIST.remove(deps.storage, address);

Ok(Response::new())
}
}

#[cfg(test)]
mod executers_tests {
use crate::helpers::helper_add_to_allowlist;
use crate::helpers::helper_register_executor;
use crate::helpers::helper_remove_from_allowlist;
use crate::helpers::helper_set_staking_config;
use crate::helpers::helper_unregister_executor;
use crate::helpers::helper_unstake;
use crate::helpers::helper_withdraw;
use crate::helpers::instantiate_staking_contract;
use common::error::ContractError;
use common::state::StakingConfig;
use cosmwasm_std::coins;
use cosmwasm_std::testing::{mock_dependencies, mock_info};

#[test]
pub fn allowlist_works() {
let mut deps = mock_dependencies();

let info = mock_info("creator", &coins(2, "token"));
let _res = instantiate_staking_contract(deps.as_mut(), info).unwrap();

// update the config with allowlist enabled
let info = mock_info("owner", &coins(0, "token"));
let new_config = StakingConfig {
minimum_stake_to_register: 100,
minimum_stake_for_committee_eligibility: 200,
allowlist_enabled: true,
};
let res = helper_set_staking_config(deps.as_mut(), info, new_config);
assert!(res.is_ok());

// alice tries to register a data request executor, but she's not on the allowlist
let info = mock_info("alice", &coins(100, "token"));
let res = helper_register_executor(deps.as_mut(), info, Some("address".to_string()), None);
assert_eq!(res.is_err_and(|x| x == ContractError::NotOnAllowlist), true);

// add alice to the allowlist
let info = mock_info("owner", &coins(0, "token"));
let res = helper_add_to_allowlist(deps.as_mut(), info, "alice".to_string(), None);
assert!(res.is_ok());

// now alice can register a data request executor
let info = mock_info("alice", &coins(100, "token"));
let res = helper_register_executor(deps.as_mut(), info, Some("address".to_string()), None);
assert!(res.is_ok());

// alice unstakes, withdraws, then unregisters herself
let info = mock_info("alice", &coins(0, "token"));
let _res = helper_unstake(deps.as_mut(), info.clone(), 100, None);
let info = mock_info("alice", &coins(0, "token"));
let _res = helper_withdraw(deps.as_mut(), info.clone(), 100, None);
let info = mock_info("alice", &coins(0, "token"));
let res = helper_unregister_executor(deps.as_mut(), info, None);
println!("{:?}", res);
assert!(res.is_ok());

// remove alice from the allowlist
let info = mock_info("owner", &coins(0, "token"));
let res = helper_remove_from_allowlist(deps.as_mut(), info, "alice".to_string(), None);
assert!(res.is_ok());

// now alice can't register a data request executor
let info = mock_info("alice", &coins(2, "token"));
let res = helper_register_executor(deps.as_mut(), info, Some("address".to_string()), None);
assert_eq!(res.is_err_and(|x| x == ContractError::NotOnAllowlist), true);

// update the config to disable the allowlist
let info = mock_info("owner", &coins(0, "token"));
let new_config = StakingConfig {
minimum_stake_to_register: 100,
minimum_stake_for_committee_eligibility: 200,
allowlist_enabled: false,
};
let res = helper_set_staking_config(deps.as_mut(), info, new_config);
assert!(res.is_ok());

// now alice can register a data request executor
let info = mock_info("alice", &coins(100, "token"));
let res = helper_register_executor(deps.as_mut(), info, Some("address".to_string()), None);
assert!(res.is_ok());
}
}
21 changes: 12 additions & 9 deletions packages/staking/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::allowlist::allow_list;
use crate::executors_registry::data_request_executors;
use crate::staking::staking;
use crate::state::{CONFIG, OWNER, PENDING_OWNER, PROXY_CONTRACT, TOKEN};
Expand Down Expand Up @@ -37,6 +38,7 @@ pub fn instantiate(
let init_config = StakingConfig {
minimum_stake_to_register: INITIAL_MINIMUM_STAKE_TO_REGISTER,
minimum_stake_for_committee_eligibility: INITIAL_MINIMUM_STAKE_FOR_COMMITTEE_ELIGIBILITY,
allowlist_enabled: false,
};
CONFIG.save(deps.storage, &init_config)?;

Expand All @@ -51,15 +53,9 @@ pub fn execute(
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
match msg {
ExecuteMsg::RegisterDataRequestExecutor {
p2p_multi_address,
sender,
} => data_request_executors::register_data_request_executor(
deps,
info,
p2p_multi_address,
sender,
),
ExecuteMsg::RegisterDataRequestExecutor { memo, sender } => {
data_request_executors::register_data_request_executor(deps, info, memo, sender)
}
ExecuteMsg::UnregisterDataRequestExecutor { sender } => {
data_request_executors::unregister_data_request_executor(deps, info, sender)
}
Expand All @@ -77,6 +73,12 @@ pub fn execute(
ExecuteMsg::SetStakingConfig { config } => {
staking::set_staking_config(deps, env, info, config)
}
ExecuteMsg::AddToAllowlist { address, sender } => {
allow_list::add_to_allowlist(deps, info, sender, address)
}
ExecuteMsg::RemoveFromAllowlist { address, sender } => {
allow_list::remove_from_allowlist(deps, info, sender, address)
}
}
}

Expand Down Expand Up @@ -225,6 +227,7 @@ mod init_tests {
let new_config = StakingConfig {
minimum_stake_to_register: 100,
minimum_stake_for_committee_eligibility: 200,
allowlist_enabled: false,
};

// non-owner sets staking config
Expand Down
Loading

0 comments on commit f8303a6

Please sign in to comment.