Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 419782fb16 | |||
| 6026ddebfd |
@@ -1,5 +1,5 @@
|
||||
test-all: test cargo-test-expensive
|
||||
test: build clippy-all cargo-test wasm fmt
|
||||
test-all: test cargo-test-expensive
|
||||
no-clippy: build cargo-test wasm fmt
|
||||
happy: fmt clippy-happy test
|
||||
clippy-all: clippy-all-main clippy-all-contracts clippy-all-wallet clippy-all-connect
|
||||
|
||||
@@ -914,6 +914,29 @@ impl<C> NymdClient<C> {
|
||||
.await
|
||||
}
|
||||
|
||||
#[execute("mixnet")]
|
||||
fn _compound_reward(
|
||||
&self,
|
||||
operator: Option<String>,
|
||||
delegator: Option<String>,
|
||||
mix_identity: Option<IdentityKey>,
|
||||
proxy: Option<String>,
|
||||
fee: Option<Fee>,
|
||||
) -> (ExecuteMsg, Option<Fee>)
|
||||
where
|
||||
C: SigningCosmWasmClient + Sync,
|
||||
{
|
||||
(
|
||||
ExecuteMsg::CompoundReward {
|
||||
operator,
|
||||
delegator,
|
||||
mix_identity,
|
||||
proxy,
|
||||
},
|
||||
fee,
|
||||
)
|
||||
}
|
||||
|
||||
#[execute("mixnet")]
|
||||
fn _compound_operator_reward(&self, fee: Option<Fee>) -> (ExecuteMsg, Option<Fee>)
|
||||
where
|
||||
|
||||
@@ -32,6 +32,12 @@ pub enum ExecuteMsg {
|
||||
CompoundDelegatorReward {
|
||||
mix_identity: IdentityKey,
|
||||
},
|
||||
CompoundReward {
|
||||
operator: Option<String>,
|
||||
delegator: Option<String>,
|
||||
mix_identity: Option<IdentityKey>,
|
||||
proxy: Option<String>,
|
||||
},
|
||||
BondMixnode {
|
||||
mix_node: MixNode,
|
||||
owner_signature: String,
|
||||
|
||||
@@ -107,6 +107,19 @@ pub fn execute(
|
||||
msg: ExecuteMsg,
|
||||
) -> Result<Response, ContractError> {
|
||||
match msg {
|
||||
ExecuteMsg::CompoundReward {
|
||||
operator,
|
||||
delegator,
|
||||
mix_identity,
|
||||
proxy,
|
||||
} => crate::rewards::transactions::try_compound_reward(
|
||||
deps,
|
||||
env,
|
||||
operator,
|
||||
delegator,
|
||||
mix_identity,
|
||||
proxy,
|
||||
),
|
||||
ExecuteMsg::UpdateRewardingValidatorAddress { address } => {
|
||||
try_update_rewarding_validator_address(deps, info, address)
|
||||
}
|
||||
@@ -275,7 +288,7 @@ pub fn execute(
|
||||
)
|
||||
}
|
||||
ExecuteMsg::ReconcileDelegations {} => {
|
||||
crate::delegations::transactions::try_reconcile_all_delegation_events(deps, info)
|
||||
crate::delegations::transactions::try_reconcile_all_delegation_events(deps)
|
||||
}
|
||||
ExecuteMsg::CheckpointMixnodes {} => {
|
||||
crate::mixnodes::transactions::try_checkpoint_mixnodes(
|
||||
@@ -443,62 +456,9 @@ pub fn query(deps: Deps<'_>, env: Env, msg: QueryMsg) -> Result<QueryResponse, C
|
||||
Ok(query_res?)
|
||||
}
|
||||
|
||||
fn update_epoch_duration(deps: DepsMut<'_>) -> Result<(), ContractError> {
|
||||
let mut epoch = crate::interval::storage::current_epoch(deps.storage)?;
|
||||
epoch.update_duration(600);
|
||||
crate::interval::storage::save_epoch(deps.storage, &epoch)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn _migrate_contract_state_params(deps: DepsMut<'_>) -> Result<(), ContractError> {
|
||||
use crate::mixnet_contract_settings::storage::CONTRACT_STATE;
|
||||
use cw_storage_plus::Item;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct OldContractState {
|
||||
pub owner: Addr,
|
||||
pub rewarding_validator_address: Addr,
|
||||
pub params: OldContractStateParams,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct OldContractStateParams {
|
||||
pub minimum_mixnode_pledge: Uint128,
|
||||
pub minimum_gateway_pledge: Uint128,
|
||||
pub mixnode_rewarded_set_size: u32,
|
||||
pub mixnode_active_set_size: u32,
|
||||
}
|
||||
|
||||
const OLD_CONTRACT_STATE: Item<'_, OldContractState> = Item::new("config");
|
||||
|
||||
let old_contract_state = OLD_CONTRACT_STATE.load(deps.storage)?;
|
||||
|
||||
let old_params = old_contract_state.params;
|
||||
|
||||
let new_params = ContractStateParams {
|
||||
minimum_mixnode_pledge: old_params.minimum_mixnode_pledge,
|
||||
minimum_gateway_pledge: old_params.minimum_gateway_pledge,
|
||||
mixnode_rewarded_set_size: old_params.mixnode_rewarded_set_size,
|
||||
mixnode_active_set_size: old_params.mixnode_active_set_size,
|
||||
staking_supply: INITIAL_STAKING_SUPPLY,
|
||||
};
|
||||
|
||||
let new_contract_state = ContractState {
|
||||
owner: old_contract_state.owner,
|
||||
rewarding_validator_address: old_contract_state.rewarding_validator_address,
|
||||
params: new_params,
|
||||
};
|
||||
|
||||
CONTRACT_STATE.save(deps.storage, &new_contract_state)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[entry_point]
|
||||
pub fn migrate(deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||
update_epoch_duration(deps)?;
|
||||
pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||
Ok(Default::default())
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ use super::storage::{self, PENDING_DELEGATION_EVENTS};
|
||||
// use crate::contract::debug_with_visibility;
|
||||
// use crate::contract::debug_with_visibility;
|
||||
use crate::error::ContractError;
|
||||
use crate::mixnet_contract_settings::storage as mixnet_params_storage;
|
||||
use crate::mixnodes::storage as mixnodes_storage;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{
|
||||
@@ -20,16 +19,7 @@ use mixnet_contract_common::{Delegation, IdentityKey};
|
||||
use vesting_contract_common::messages::ExecuteMsg as VestingContractExecuteMsg;
|
||||
use vesting_contract_common::one_ucoin;
|
||||
|
||||
pub fn try_reconcile_all_delegation_events(
|
||||
deps: DepsMut<'_>,
|
||||
info: MessageInfo,
|
||||
) -> Result<Response, ContractError> {
|
||||
let state = mixnet_params_storage::CONTRACT_STATE.load(deps.storage)?;
|
||||
// check if this is executed by the permitted validator, if not reject the transaction
|
||||
if info.sender != state.rewarding_validator_address {
|
||||
return Err(ContractError::Unauthorized);
|
||||
}
|
||||
|
||||
pub fn try_reconcile_all_delegation_events(deps: DepsMut<'_>) -> Result<Response, ContractError> {
|
||||
_try_reconcile_all_delegation_events(deps.storage, deps.api)
|
||||
}
|
||||
|
||||
@@ -1063,182 +1053,14 @@ mod tests {
|
||||
#[cfg(test)]
|
||||
mod removing_mix_stake_delegation {
|
||||
use crate::delegations::queries::query_mixnode_delegation;
|
||||
use super::*;
|
||||
use crate::support::tests;
|
||||
use cosmwasm_std::coin;
|
||||
use cosmwasm_std::testing::mock_env;
|
||||
use cosmwasm_std::testing::mock_info;
|
||||
use cosmwasm_std::Addr;
|
||||
use cosmwasm_std::Uint128;
|
||||
|
||||
use crate::mixnodes::transactions::try_remove_mixnode;
|
||||
use crate::support::tests;
|
||||
|
||||
use super::storage;
|
||||
use super::*;
|
||||
|
||||
// TODO: Probably delete due to reconciliation logic
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn fails_if_delegation_never_existed() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let env = mock_env();
|
||||
let mixnode_owner = "bob";
|
||||
let identity = test_helpers::add_mixnode(
|
||||
mixnode_owner,
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation_owner = Addr::unchecked("sender");
|
||||
assert_eq!(
|
||||
Err(ContractError::NoMixnodeDelegationFound {
|
||||
identity: identity.clone(),
|
||||
address: delegation_owner.to_string(),
|
||||
}),
|
||||
try_remove_delegation_from_mixnode(
|
||||
deps.as_mut(),
|
||||
env,
|
||||
mock_info(delegation_owner.as_str(), &[]),
|
||||
identity,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Update to work with reconciliation
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn succeeds_if_delegation_existed() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let mixnode_owner = "bob";
|
||||
let env = mock_env();
|
||||
let identity = test_helpers::add_mixnode(
|
||||
mixnode_owner,
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation_owner = Addr::unchecked("sender");
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info(delegation_owner.as_str(), &coins(100, DENOM)),
|
||||
identity.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage, &deps.api).unwrap();
|
||||
|
||||
let _delegation = query_mixnode_delegation(
|
||||
&deps.storage,
|
||||
&deps.api,
|
||||
identity.clone(),
|
||||
delegation_owner.clone().into_string(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let expected_response = Response::new()
|
||||
.add_message(BankMsg::Send {
|
||||
to_address: delegation_owner.clone().into(),
|
||||
amount: coins(100, DENOM),
|
||||
})
|
||||
.add_event(new_undelegation_event(
|
||||
&delegation_owner,
|
||||
&None,
|
||||
&identity,
|
||||
Uint128::new(100),
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
Ok(expected_response),
|
||||
try_remove_delegation_from_mixnode(
|
||||
deps.as_mut(),
|
||||
env,
|
||||
mock_info(delegation_owner.as_str(), &[]),
|
||||
identity.clone(),
|
||||
)
|
||||
);
|
||||
assert!(storage::delegations()
|
||||
.may_load(
|
||||
&deps.storage,
|
||||
(identity.clone(), delegation_owner.as_bytes().to_vec(), 0),
|
||||
)
|
||||
.unwrap()
|
||||
.is_none());
|
||||
|
||||
// and total delegation is cleared
|
||||
assert_eq!(
|
||||
Uint128::zero(),
|
||||
mixnodes_storage::TOTAL_DELEGATION
|
||||
.load(&deps.storage, &identity)
|
||||
.unwrap()
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: Update to work with reconciliation
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn succeeds_if_delegation_existed_even_if_node_unbonded() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let mixnode_owner = "bob";
|
||||
let env = mock_env();
|
||||
let identity = test_helpers::add_mixnode(
|
||||
mixnode_owner,
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation_owner = Addr::unchecked("sender");
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info(delegation_owner.as_str(), &coins(100, DENOM)),
|
||||
identity.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage, &deps.api).unwrap();
|
||||
|
||||
let delegation = query_mixnode_delegation(
|
||||
&deps.storage,
|
||||
&deps.api,
|
||||
identity.clone(),
|
||||
delegation_owner.clone().into_string(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let expected_response = Response::new()
|
||||
.add_message(BankMsg::Send {
|
||||
to_address: delegation_owner.clone().into(),
|
||||
amount: coins(100, DENOM),
|
||||
})
|
||||
.add_event(new_undelegation_event(
|
||||
&delegation_owner,
|
||||
&None,
|
||||
&identity,
|
||||
Uint128::new(100),
|
||||
));
|
||||
|
||||
try_remove_mixnode(mock_env(), deps.as_mut(), mock_info(mixnode_owner, &[])).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
Ok(expected_response),
|
||||
try_remove_delegation_from_mixnode(
|
||||
deps.as_mut(),
|
||||
env,
|
||||
mock_info(delegation_owner.as_str(), &[]),
|
||||
identity.clone(),
|
||||
)
|
||||
);
|
||||
|
||||
_try_reconcile_all_delegation_events(&mut deps.storage, &deps.api).unwrap();
|
||||
|
||||
assert!(test_helpers::read_delegation(
|
||||
&deps.storage,
|
||||
identity,
|
||||
delegation_owner.as_bytes(),
|
||||
mock_env().block.height
|
||||
)
|
||||
.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn total_delegation_is_preserved_if_only_some_undelegate() {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
|
||||
@@ -179,4 +179,6 @@ pub enum ContractError {
|
||||
last_update_time: u64,
|
||||
current_block_time: u64,
|
||||
},
|
||||
#[error("`mix_identity` is required when `delegator` is set")]
|
||||
MissingMixIdentity,
|
||||
}
|
||||
|
||||
@@ -370,6 +370,56 @@ pub fn try_compound_delegator_reward_on_behalf(
|
||||
)
|
||||
}
|
||||
|
||||
pub fn try_compound_reward(
|
||||
deps: DepsMut<'_>,
|
||||
env: Env,
|
||||
operator: Option<String>,
|
||||
delegator: Option<String>,
|
||||
mix_identity: Option<IdentityKey>,
|
||||
proxy: Option<String>,
|
||||
) -> Result<Response, ContractError> {
|
||||
let proxy = proxy.and_then(|p| deps.api.addr_validate(&p).ok());
|
||||
if let Some(operator_address) = operator {
|
||||
let operator_address = deps.api.addr_validate(&operator_address)?;
|
||||
let reward = _try_compound_operator_reward(
|
||||
deps.storage,
|
||||
deps.api,
|
||||
env.block.height,
|
||||
&operator_address,
|
||||
proxy,
|
||||
)?;
|
||||
Ok(
|
||||
Response::default().add_event(new_compound_operator_reward_event(
|
||||
&operator_address,
|
||||
reward,
|
||||
)),
|
||||
)
|
||||
} else if let Some(delegator_address) = delegator {
|
||||
if mix_identity.is_none() {
|
||||
return Err(ContractError::MissingMixIdentity);
|
||||
}
|
||||
|
||||
let delegator_address = deps.api.addr_validate(&delegator_address)?;
|
||||
let reward = _try_compound_delegator_reward(
|
||||
env.block.height,
|
||||
deps,
|
||||
delegator_address.as_str(),
|
||||
mix_identity.as_ref().unwrap(),
|
||||
proxy,
|
||||
)?;
|
||||
Ok(
|
||||
Response::default().add_event(new_compound_delegator_reward_event(
|
||||
&delegator_address,
|
||||
&None,
|
||||
reward,
|
||||
&mix_identity.unwrap(),
|
||||
)),
|
||||
)
|
||||
} else {
|
||||
Ok(Response::default())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_compound_delegator_reward(
|
||||
deps: DepsMut<'_>,
|
||||
env: Env,
|
||||
|
||||
Reference in New Issue
Block a user