Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add AvailableMedians method #1657

Merged
merged 10 commits into from
Dec 15, 2022
12 changes: 8 additions & 4 deletions x/oracle/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,16 +265,20 @@ func (s *IntegrationTestSuite) TestEndblockerHistoracle() {
s.Require().NoError(err)
s.Require().Equal(tc.expectedWithinHistoricMedianDeviation, withinHistoricMedianDeviation)

medianOfHistoricMedians, err := app.OracleKeeper.MedianOfHistoricMedians(ctx, denom.SymbolDenom, 6)
medianOfHistoricMedians, numMedians, err := app.OracleKeeper.MedianOfHistoricMedians(ctx, denom.SymbolDenom, 6)
s.Require().Equal(uint32(4), numMedians)
s.Require().Equal(tc.expectedMedianOfHistoricMedians, medianOfHistoricMedians)

averageOfHistoricMedians, err := app.OracleKeeper.AverageOfHistoricMedians(ctx, denom.SymbolDenom, 6)
averageOfHistoricMedians, numMedians, err := app.OracleKeeper.AverageOfHistoricMedians(ctx, denom.SymbolDenom, 6)
s.Require().Equal(uint32(4), numMedians)
s.Require().Equal(tc.expectedAverageOfHistoricMedians, averageOfHistoricMedians)

minOfHistoricMedians, err := app.OracleKeeper.MinOfHistoricMedians(ctx, denom.SymbolDenom, 6)
minOfHistoricMedians, numMedians, err := app.OracleKeeper.MinOfHistoricMedians(ctx, denom.SymbolDenom, 6)
s.Require().Equal(uint32(4), numMedians)
s.Require().Equal(tc.expectedMinOfHistoricMedians, minOfHistoricMedians)

maxOfHistoricMedians, err := app.OracleKeeper.MaxOfHistoricMedians(ctx, denom.SymbolDenom, 6)
maxOfHistoricMedians, numMedians, err := app.OracleKeeper.MaxOfHistoricMedians(ctx, denom.SymbolDenom, 6)
s.Require().Equal(uint32(4), numMedians)
s.Require().Equal(tc.expectedMaxOfHistoricMedians, maxOfHistoricMedians)

clearHistoricPrices(ctx, app.OracleKeeper, denom.SymbolDenom)
Expand Down
52 changes: 36 additions & 16 deletions x/oracle/keeper/historic_price.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,63 +134,83 @@ func (k Keeper) SetHistoricMedianDeviation(
}

// MedianOfHistoricMedians calculates and returns the median of the last stampNum
// historic medians.
// historic medians as well as the amount of medians used to calculate that median.
// If no medians are available, all returns are zero and error is nil.
func (k Keeper) MedianOfHistoricMedians(
ctx sdk.Context,
denom string,
numStamps uint64,
) (sdk.Dec, error) {
) (sdk.Dec, uint32, error) {
medians := k.HistoricMedians(ctx, denom, numStamps)
rbajollari marked this conversation as resolved.
Show resolved Hide resolved
if len(medians) == 0 {
return sdk.ZeroDec(), 0, nil
}
median, err := decmath.Median(medians)
if err != nil {
return sdk.ZeroDec(), sdkerrors.Wrap(err, fmt.Sprintf("denom: %s", denom))
return sdk.ZeroDec(), 0, sdkerrors.Wrap(err, fmt.Sprintf("denom: %s", denom))
}
return median, nil

return median, uint32(len(medians)), nil
}

// AverageOfHistoricMedians calculates and returns the average of the last stampNum
// historic medians.
// historic medians as well as the amount of medians used to calculate that average.
// If no medians are available, all returns are zero and error is nil.
func (k Keeper) AverageOfHistoricMedians(
ctx sdk.Context,
denom string,
numStamps uint64,
) (sdk.Dec, error) {
) (sdk.Dec, uint32, error) {
medians := k.HistoricMedians(ctx, denom, numStamps)
if len(medians) == 0 {
return sdk.ZeroDec(), 0, nil
}
average, err := decmath.Average(medians)
if err != nil {
return sdk.ZeroDec(), sdkerrors.Wrap(err, fmt.Sprintf("denom: %s", denom))
return sdk.ZeroDec(), 0, sdkerrors.Wrap(err, fmt.Sprintf("denom: %s", denom))
}
return average, nil

return average, uint32(len(medians)), nil
}

// MaxOfHistoricMedian calculates and returns the maximum value of the last stampNum
// historic medians.
// historic medians as well as the amount of medians used to calculate that maximum.
// If no medians are available, all returns are zero and error is nil.
func (k Keeper) MaxOfHistoricMedians(
ctx sdk.Context,
denom string,
numStamps uint64,
) (sdk.Dec, error) {
) (sdk.Dec, uint32, error) {
medians := k.HistoricMedians(ctx, denom, numStamps)
if len(medians) == 0 {
return sdk.ZeroDec(), 0, nil
}
max, err := decmath.Max(medians)
if err != nil {
return sdk.ZeroDec(), sdkerrors.Wrap(err, fmt.Sprintf("denom: %s", denom))
return sdk.ZeroDec(), 0, sdkerrors.Wrap(err, fmt.Sprintf("denom: %s", denom))
}
return max, nil

return max, uint32(len(medians)), nil
}

// MinOfHistoricMedians calculates and returns the minimum value of the last stampNum
// historic medians.
// historic medians as well as the amount of medians used to calculate that minimum.
// If no medians are available, all returns are zero and error is nil.
func (k Keeper) MinOfHistoricMedians(
ctx sdk.Context,
denom string,
numStamps uint64,
) (sdk.Dec, error) {
) (sdk.Dec, uint32, error) {
medians := k.HistoricMedians(ctx, denom, numStamps)
if len(medians) == 0 {
return sdk.ZeroDec(), 0, nil
}
min, err := decmath.Min(medians)
if err != nil {
return sdk.ZeroDec(), sdkerrors.Wrap(err, fmt.Sprintf("denom: %s", denom))
return sdk.ZeroDec(), 0, sdkerrors.Wrap(err, fmt.Sprintf("denom: %s", denom))
}
return min, nil

return min, uint32(len(medians)), nil
}

// historicPrices returns all the historic prices of a given denom.
Expand Down
26 changes: 17 additions & 9 deletions x/oracle/keeper/historic_price_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func (s *IntegrationTestSuite) TestSetHistoraclePricing() {
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
}

// check median and median standard deviation
// check medians, num of available medians, and median standard deviation
medians := app.OracleKeeper.HistoricMedians(ctx, displayDenom, 3)
s.Require().Equal(len(medians), 3)
s.Require().Equal(medians[0], sdk.MustNewDecFromStr("1.2"))
Expand All @@ -49,31 +49,39 @@ func (s *IntegrationTestSuite) TestSetHistoraclePricing() {
s.Require().NoError(err)

// check median stats of last 3 stamps
medianOfMedians, err := app.OracleKeeper.MedianOfHistoricMedians(ctx, displayDenom, 3)
medianOfMedians, numMedians, err := app.OracleKeeper.MedianOfHistoricMedians(ctx, displayDenom, 3)
s.Require().NoError(err)
s.Require().Equal(numMedians, uint32(3))
s.Require().Equal(medianOfMedians, sdk.MustNewDecFromStr("1.125"))
averageOfMedians, err := app.OracleKeeper.AverageOfHistoricMedians(ctx, displayDenom, 3)
averageOfMedians, numMedians, err := app.OracleKeeper.AverageOfHistoricMedians(ctx, displayDenom, 3)
s.Require().NoError(err)
s.Require().Equal(numMedians, uint32(3))
s.Require().Equal(averageOfMedians, sdk.MustNewDecFromStr("1.141666666666666666"))
maxMedian, err := app.OracleKeeper.MaxOfHistoricMedians(ctx, displayDenom, 3)
maxMedian, numMedians, err := app.OracleKeeper.MaxOfHistoricMedians(ctx, displayDenom, 3)
s.Require().NoError(err)
s.Require().Equal(numMedians, uint32(3))
s.Require().Equal(maxMedian, sdk.MustNewDecFromStr("1.2"))
minMedian, err := app.OracleKeeper.MinOfHistoricMedians(ctx, displayDenom, 3)
minMedian, numMedians, err := app.OracleKeeper.MinOfHistoricMedians(ctx, displayDenom, 3)
s.Require().NoError(err)
s.Require().Equal(numMedians, uint32(3))
s.Require().Equal(minMedian, sdk.MustNewDecFromStr("1.1"))

// check median stats of last 1 stamps
medianOfMedians, err = app.OracleKeeper.MedianOfHistoricMedians(ctx, displayDenom, 1)
medianOfMedians, numMedians, err = app.OracleKeeper.MedianOfHistoricMedians(ctx, displayDenom, 1)
s.Require().NoError(err)
s.Require().Equal(numMedians, uint32(1))
s.Require().Equal(medianOfMedians, sdk.MustNewDecFromStr("1.2"))
averageOfMedians, err = app.OracleKeeper.AverageOfHistoricMedians(ctx, displayDenom, 1)
averageOfMedians, numMedians, err = app.OracleKeeper.AverageOfHistoricMedians(ctx, displayDenom, 1)
s.Require().NoError(err)
s.Require().Equal(numMedians, uint32(1))
s.Require().Equal(averageOfMedians, sdk.MustNewDecFromStr("1.2"))
maxMedian, err = app.OracleKeeper.MaxOfHistoricMedians(ctx, displayDenom, 1)
maxMedian, numMedians, err = app.OracleKeeper.MaxOfHistoricMedians(ctx, displayDenom, 1)
s.Require().NoError(err)
s.Require().Equal(numMedians, uint32(1))
s.Require().Equal(maxMedian, sdk.MustNewDecFromStr("1.2"))
minMedian, err = app.OracleKeeper.MinOfHistoricMedians(ctx, displayDenom, 1)
minMedian, numMedians, err = app.OracleKeeper.MinOfHistoricMedians(ctx, displayDenom, 1)
s.Require().NoError(err)
s.Require().Equal(numMedians, uint32(1))
s.Require().Equal(minMedian, sdk.MustNewDecFromStr("1.2"))

// delete first median
Expand Down