Feature/configure profit (#1008)
* Introduce a method to update mixnode configuration Right now, only for profit_margin_percent * Check that the new profit margin is valid * Extend a bit the test coverage of mixnode update * Create validator client function * [ci skip] Generate TS types * Update wallet * Update the bond height as well, as if a rebond was made Co-authored-by: neacsu <neacsu@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
ec4955f814
commit
30e93c33bb
@@ -20,6 +20,7 @@ pub enum Operation {
|
||||
BondMixnodeOnBehalf,
|
||||
UnbondMixnode,
|
||||
UnbondMixnodeOnBehalf,
|
||||
UpdateMixnodeConfig,
|
||||
DelegateToMixnode,
|
||||
DelegateToMixnodeOnBehalf,
|
||||
UndelegateFromMixnode,
|
||||
@@ -57,6 +58,7 @@ impl fmt::Display for Operation {
|
||||
Operation::BondMixnode => f.write_str("BondMixnode"),
|
||||
Operation::BondMixnodeOnBehalf => f.write_str("BondMixnodeOnBehalf"),
|
||||
Operation::UnbondMixnode => f.write_str("UnbondMixnode"),
|
||||
Operation::UpdateMixnodeConfig => f.write_str("UpdateMixnodeConfig"),
|
||||
Operation::UnbondMixnodeOnBehalf => f.write_str("UnbondMixnodeOnBehalf"),
|
||||
Operation::BondGateway => f.write_str("BondGateway"),
|
||||
Operation::BondGatewayOnBehalf => f.write_str("BondGatewayOnBehalf"),
|
||||
@@ -94,6 +96,7 @@ impl Operation {
|
||||
Operation::BondMixnodeOnBehalf => 200_000u64.into(),
|
||||
Operation::UnbondMixnode => 175_000u64.into(),
|
||||
Operation::UnbondMixnodeOnBehalf => 175_000u64.into(),
|
||||
Operation::UpdateMixnodeConfig => 175_000u64.into(),
|
||||
Operation::DelegateToMixnode => 175_000u64.into(),
|
||||
Operation::DelegateToMixnodeOnBehalf => 175_000u64.into(),
|
||||
Operation::UndelegateFromMixnode => 175_000u64.into(),
|
||||
|
||||
@@ -773,6 +773,31 @@ impl<C> NymdClient<C> {
|
||||
.await
|
||||
}
|
||||
|
||||
/// Update the configuration of a mixnode. Right now, only possible for profit margin.
|
||||
pub async fn update_mixnode_config(
|
||||
&self,
|
||||
profit_margin_percent: u8,
|
||||
) -> Result<ExecuteResult, NymdError>
|
||||
where
|
||||
C: SigningCosmWasmClient + Sync,
|
||||
{
|
||||
let fee = self.operation_fee(Operation::UpdateMixnodeConfig);
|
||||
|
||||
let req = ExecuteMsg::UpdateMixnodeConfig {
|
||||
profit_margin_percent,
|
||||
};
|
||||
self.client
|
||||
.execute(
|
||||
self.address(),
|
||||
self.mixnet_contract_address()?,
|
||||
&req,
|
||||
fee,
|
||||
"Updating mixnode configuration from rust!",
|
||||
Vec::new(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Delegates specified amount of stake to particular mixnode.
|
||||
pub async fn delegate_to_mixnode(
|
||||
&self,
|
||||
|
||||
@@ -20,6 +20,9 @@ pub enum ExecuteMsg {
|
||||
owner_signature: String,
|
||||
},
|
||||
UnbondMixnode {},
|
||||
UpdateMixnodeConfig {
|
||||
profit_margin_percent: u8,
|
||||
},
|
||||
BondGateway {
|
||||
gateway: Gateway,
|
||||
owner_signature: String,
|
||||
|
||||
@@ -104,6 +104,14 @@ pub fn execute(
|
||||
ExecuteMsg::UnbondMixnode {} => {
|
||||
crate::mixnodes::transactions::try_remove_mixnode(deps, info)
|
||||
}
|
||||
ExecuteMsg::UpdateMixnodeConfig {
|
||||
profit_margin_percent,
|
||||
} => crate::mixnodes::transactions::try_update_mixnode_config(
|
||||
deps,
|
||||
env,
|
||||
info,
|
||||
profit_margin_percent,
|
||||
),
|
||||
ExecuteMsg::BondGateway {
|
||||
gateway,
|
||||
owner_signature,
|
||||
|
||||
@@ -204,6 +204,42 @@ pub(crate) fn _try_remove_mixnode(
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
pub(crate) fn try_update_mixnode_config(
|
||||
deps: DepsMut,
|
||||
env: Env,
|
||||
info: MessageInfo,
|
||||
profit_margin_percent: u8,
|
||||
) -> Result<Response, ContractError> {
|
||||
let owner = deps.api.addr_validate(info.sender.as_ref())?;
|
||||
let mix_identity = storage::mixnodes()
|
||||
.idx
|
||||
.owner
|
||||
.item(deps.storage, owner.clone())?
|
||||
.ok_or(ContractError::NoAssociatedMixNodeBond { owner })?
|
||||
.1
|
||||
.identity()
|
||||
.clone();
|
||||
|
||||
// We don't have to check lower bound as its an u8
|
||||
if profit_margin_percent > 100 {
|
||||
return Err(ContractError::InvalidProfitMarginPercent(
|
||||
profit_margin_percent,
|
||||
));
|
||||
}
|
||||
|
||||
storage::mixnodes().update(deps.storage, &mix_identity, |mixnode_bond_opt| {
|
||||
mixnode_bond_opt
|
||||
.map(|mut mixnode_bond| {
|
||||
mixnode_bond.mix_node.profit_margin_percent = profit_margin_percent;
|
||||
mixnode_bond.block_height = env.block.height;
|
||||
mixnode_bond
|
||||
})
|
||||
.ok_or(ContractError::NoBondFound)
|
||||
})?;
|
||||
|
||||
Ok(Response::new())
|
||||
}
|
||||
|
||||
fn validate_mixnode_pledge(
|
||||
mut pledge: Vec<Coin>,
|
||||
minimum_pledge: Uint128,
|
||||
@@ -587,6 +623,77 @@ pub mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn updating_mixnode_config() {
|
||||
let sender = "bob";
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let info = mock_info(sender, &[]);
|
||||
|
||||
// try updating a non existing mixnode bond
|
||||
let msg = ExecuteMsg::UpdateMixnodeConfig {
|
||||
profit_margin_percent: 10,
|
||||
};
|
||||
let ret = execute(deps.as_mut(), mock_env(), info.clone(), msg);
|
||||
assert_eq!(
|
||||
ret,
|
||||
Err(ContractError::NoAssociatedMixNodeBond {
|
||||
owner: Addr::unchecked(sender)
|
||||
})
|
||||
);
|
||||
|
||||
test_helpers::add_mixnode(
|
||||
sender,
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
|
||||
// check the initial profit margin is set to the fixture value
|
||||
let fixture_profit_margin = tests::fixtures::mix_node_fixture().profit_margin_percent;
|
||||
assert_eq!(
|
||||
fixture_profit_margin,
|
||||
storage::mixnodes()
|
||||
.idx
|
||||
.owner
|
||||
.item(deps.as_ref().storage, Addr::unchecked("bob"))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.1
|
||||
.mix_node
|
||||
.profit_margin_percent
|
||||
);
|
||||
|
||||
// try updating with an invalid value
|
||||
let profit_margin_percent = 101;
|
||||
let msg = ExecuteMsg::UpdateMixnodeConfig {
|
||||
profit_margin_percent,
|
||||
};
|
||||
let ret = execute(deps.as_mut(), mock_env(), info.clone(), msg);
|
||||
assert_eq!(
|
||||
ret,
|
||||
Err(ContractError::InvalidProfitMarginPercent(
|
||||
profit_margin_percent
|
||||
))
|
||||
);
|
||||
|
||||
let profit_margin_percent = fixture_profit_margin + 10;
|
||||
let msg = ExecuteMsg::UpdateMixnodeConfig {
|
||||
profit_margin_percent,
|
||||
};
|
||||
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
|
||||
assert_eq!(
|
||||
profit_margin_percent,
|
||||
storage::mixnodes()
|
||||
.idx
|
||||
.owner
|
||||
.item(deps.as_ref().storage, Addr::unchecked("bob"))
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.1
|
||||
.mix_node
|
||||
.profit_margin_percent
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validating_mixnode_bond() {
|
||||
// you must send SOME funds
|
||||
|
||||
@@ -36,6 +36,7 @@ fn main() {
|
||||
mixnet::bond::bond_mixnode,
|
||||
mixnet::bond::unbond_gateway,
|
||||
mixnet::bond::unbond_mixnode,
|
||||
mixnet::bond::update_mixnode,
|
||||
mixnet::bond::mixnode_bond_details,
|
||||
mixnet::bond::gateway_bond_details,
|
||||
mixnet::delegate::delegate_to_mixnode,
|
||||
|
||||
@@ -50,6 +50,17 @@ pub async fn bond_mixnode(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn update_mixnode(
|
||||
profit_margin_percent: u8,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<(), BackendError> {
|
||||
client!(state)
|
||||
.update_mixnode_config(profit_margin_percent)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn mixnode_bond_details(
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
|
||||
@@ -8,6 +8,7 @@ export type Operation =
|
||||
| "BondMixnodeOnBehalf"
|
||||
| "UnbondMixnode"
|
||||
| "UnbondMixnodeOnBehalf"
|
||||
| "UpdateMixnodeConfig"
|
||||
| "DelegateToMixnode"
|
||||
| "DelegateToMixnodeOnBehalf"
|
||||
| "UndelegateFromMixnode"
|
||||
|
||||
Reference in New Issue
Block a user