Skip to content

Commit

Permalink
Slash using the efective slash ratio
Browse files Browse the repository at this point in the history
Filter out unbondings by infraction time
  • Loading branch information
maurolacy committed Dec 4, 2023
1 parent 9d2a30c commit 246c7bb
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 8 deletions.
32 changes: 26 additions & 6 deletions contracts/provider/external-staking/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -474,16 +474,22 @@ impl ExternalStakingContract<'_> {
valinfo.infraction_height,
)?;
if active {
// TODO: Compute effective slash ratio
let slash_ratio = match valinfo.slash_ratio.parse::<Decimal>() {
Ok(ratio) => ratio,
Err(_) => {
return Err(ContractError::InvalidSlashRatio);
}
};
// Slash the validator, if bonded
let slash_msg =
self.handle_slashing(&env, deps.storage, &cfg, valoper, slash_ratio)?;
let slash_msg = self.handle_slashing(
&env,
deps.storage,
&cfg,
valoper,
slash_ratio,
valinfo.slash_amount.amount,
valinfo.infraction_time,
)?;
if let Some(msg) = slash_msg {
msgs.push(msg)
}
Expand Down Expand Up @@ -866,8 +872,11 @@ impl ExternalStakingContract<'_> {
config: &Config,
validator: &str,
slash_ratio: Decimal,
slash_amount: Uint128,
infraction_time: u64,
) -> Result<Option<WasmMsg>, ContractError> {
// Get the list of users staking via this validator
// FIXME: It should be over the *historical* (at infraction height) stake. Not over the *current* stake
let users = self
.stakes
.stake
Expand All @@ -883,6 +892,12 @@ impl ExternalStakingContract<'_> {
if users.is_empty() {
return Ok(None);
}
// Compute effective slash ratio
let total_amount = users
.iter()
.map(|(_, stake)| stake.stake.high())
.sum::<Uint128>();
let effective_slash_ratio = Decimal::from_ratio(slash_amount, total_amount);

// Slash their stake in passing
let mut slash_infos = vec![];
Expand All @@ -895,7 +910,7 @@ impl ExternalStakingContract<'_> {
if stake_high.is_zero() {
continue;
}
let stake_slash = stake_high * slash_ratio;
let stake_slash = stake_high * effective_slash_ratio;
// Requires proper saturating methods in commit/rollback_stake/unstake
stake.stake = ValueRange::new(
stake_low.saturating_sub(stake_slash),
Expand All @@ -913,8 +928,13 @@ impl ExternalStakingContract<'_> {
distribution.total_stake = distribution.total_stake.saturating_sub(stake_slash); // Don't fail if pending bond tx
self.distribution.save(storage, validator, &distribution)?;

// Slash the unbondings
let pending_slashed = stake.slash_pending(&env.block, slash_ratio);
// Slash the unbondings. We use the nominal slash ratio here, like in the blockchain
let pending_slashed = stake.slash_pending(
&env.block,
slash_ratio,
config.unbonding_period,
infraction_time,
);

self.stakes.stake.save(storage, (&user, validator), stake)?;

Expand Down
13 changes: 11 additions & 2 deletions contracts/provider/external-staking/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,19 @@ impl Stake {
}

/// Slashes all the entries in `pending_unbonds`, returning total slashed amount.
pub fn slash_pending(&mut self, info: &BlockInfo, slash_ratio: Decimal) -> Uint128 {
pub fn slash_pending(
&mut self,
info: &BlockInfo,
slash_ratio: Decimal,
unbonding_period: u64,
infraction_time: u64,
) -> Uint128 {
self.pending_unbonds
.iter_mut()
.filter(|pending| pending.release_at > info.time)
.filter(|pending| {
pending.release_at.seconds() - unbonding_period > infraction_time
&& pending.release_at > info.time
})
.map(|pending| {
let slash = pending.amount * slash_ratio;
// Slash it
Expand Down

0 comments on commit 246c7bb

Please sign in to comment.