Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

### Fixed

- Compute the oracle ballot `StandardDeviation` as a stake-weighted variance (weight each squared deviation by the vote's power and divide by total voting power) instead of an unweighted average divided by the vote count, aligning the reward-band width with the stake-weighted median and preventing a group of low-stake validators from inflating the deviation to widen the accepted vote window
- Close an oracle slashing bypass in the `EndBlocker` where validators were scored against the post-filtered `voteTargets` map: a denom that received votes but was pushed below the vote threshold (e.g. by a coordinated group abstaining) was dropped from the scoring denominator, letting the abstainers avoid miss penalties. Participation is now scored against the configured targets that received votes (passing targets plus below-threshold targets), crediting validators that voted on a below-threshold target while counting abstention on it as a miss; targets that received no votes at all are still excluded so a legitimately unpriceable denom cannot mass-slash the validator set
- Allow EIP-7702 delegated EOAs to send direct EVM transactions by exempting delegation-designator code from the externally-owned-account-only check in `VerifyIfAccountExists`, so accounts that delegate via `SetCodeTx` can still manage (and revoke) their own delegation without a sponsored transaction
- Remove the forced minimum 1-unit-per-block reward release in `CalculateReward` and skip (instead of deactivating) sub-unit blocks in the rewards `BeginBlocker`, so the proportional share accumulates and the pool follows the configured schedule independent of block time (previously a 10-year, 1M-unit schedule drained in ~12 days at the 1s target block time and ~28 days at the current ~2.4s rate, regardless of the configured duration)
Expand Down
16 changes: 11 additions & 5 deletions x/oracle/types/ballot.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,20 +173,26 @@ func (ex ExchangeRateBallot) StandardDeviation(median sdkMath.LegacyDec) (standa
}
}()

// Get the total voting power to weight the variance
totalPower := ex.Power()
if totalPower == 0 {
return sdkMath.LegacyZeroDec()
}

sum := sdkMath.LegacyZeroDec()
for _, votes := range ex {
deviation := votes.ExchangeRate.Sub(median) // calculate the ex - median
sum = sum.Add(deviation.Mul(deviation)) // Calculate sum += (ex - median)^2
deviation := votes.ExchangeRate.Sub(median) // calculate the ex - median
sum = sum.Add(deviation.Mul(deviation).MulInt64(votes.Power)) // Calculate sum += power * (ex - median)^2
}

// Divide the result by the number of ex
variance := sum.QuoInt64(int64(len(ex)))
// Divide the result by the total voting power
variance := sum.QuoInt64(totalPower)

// Finally get the square root of variance
standardDeviation, err := variance.ApproxSqrt()
if err != nil {
return sdkMath.LegacyZeroDec()
}

return
return standardDeviation
}
2 changes: 1 addition & 1 deletion x/oracle/types/ballot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ func TestStandardDeviation(t *testing.T) {
median := ballot.WeightedMedianWithAssertion()
deviation := ballot.StandardDeviation(median)

expected := sdkMath.LegacyNewDecWithPrec(1224745, 6)
expected := sdkMath.LegacyOneDec()
// 2e-7 tolerance
delta := sdkMath.LegacyNewDecWithPrec(2, 7)

Expand Down
Loading