Skip to content

Commit

Permalink
feat(oracle): implement reward allocation for oracles (#839)
Browse files Browse the repository at this point in the history
* add: wire oracle

* temp: attempt to fix localnet.sh

* upgrade changelog

* add: slash logging

* add: miss counters logging

* tmp

* fix: almost there....

* add: finalize first oracle scenario integration test

* add: function to find private key info for an address

* fix: test

* chore: move oracle to simapp

* chore: lint

* chore: docs and function simplification

* chore: CHANGELOG.md

* chore: move update exchange rates logic to another function

* fix: make clear exchange rates semantically correct

* change: rename Claim to ValidatorPerformance

* change: rename Claim to ValidatorPerformance 2

* change: rename Claim to ValidatorPerformance 3

* chore: document function

* temp: move app_test.go to a separate pkg

* refactor: move exchange rate update logic to the keeper

* chore: simplify genesis tests

* chore: move abci_test to keeper

* change: move slash_test package to keeper_test

* change: move slashing tests to slash_test.go

* chore: rename abci_test to update_exchange_rate_test.go

* chore: lint

* chore: CHANGELOG.md

* chore: remove unused function

* change: rename GetRewardsPool to GetRewardsForPair

* change: remove distribution window parameter

* change: adjust RewardBallotWinners

* chore: adjust doc

* add: rewards protos

* temp: panics so i don't forget

* add: initial keeper methods

* chore: adjust genesis

* change: move rewardsforpair from alias_functions.go to reward.go

* add: rewards distribution logic

* fix: err check

* chore: adjust TestOracleRewardDistribution

* chore: document test

* chore: rename variables to clarify scenario

* chore: adjust test in update_exchange_rate_test.go

* chore: rename denom reference to pair

* chore: remove unused test

* chore: adjust update_exchange_rate_test.go

* add: rewards tests

* change: API name

* chore: lint

* chore: update CHANGELOG.md

Co-authored-by: Agent Smith <agentsmith@matrixsystems.co>
  • Loading branch information
testinginprod and AgentSmithMatrix authored Aug 25, 2022
1 parent a321f52 commit eccb38b
Show file tree
Hide file tree
Showing 26 changed files with 937 additions and 411 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Features

* [#839](https://github.com/NibiruChain/nibiru/pull/839) - x/oracle rewarding
* [#791](https://github.com/NibiruChain/nibiru/pull/791) Add the x/oracle module
* [#811](https://github.com/NibiruChain/nibiru/pull/811) Return the index twap in `QueryPrice` cmd
* [#813](https://github.com/NibiruChain/nibiru/pull/813) - (vpool): Expose mark price, mark TWAP, index price, and k (swap invariant) in the all-pools query
* [#816](https://github.com/NibiruChain/nibiru/pull/816) - Remove tobin tax from x/oracle
* [#810](https://github.com/NibiruChain/nibiru/pull/810) - feat(x/perp): expose 'marginRatioIndex' and block number on QueryTraderPosition
* [#832](https://github.com/NibiruChain/nibiru/pull/832) - x/oracle app wiring

### Documentation

Expand Down
1 change: 1 addition & 0 deletions proto/oracle/v1beta1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ message GenesisState {
repeated AggregateExchangeRatePrevote aggregate_exchange_rate_prevotes = 5 [(gogoproto.nullable) = false];
repeated AggregateExchangeRateVote aggregate_exchange_rate_votes = 6 [(gogoproto.nullable) = false];
repeated Pair pairs = 7 [(gogoproto.nullable) = false];
repeated PairReward pair_rewards = 8;
}

// FeederDelegation is the address for where oracle feeder authority are
Expand Down
22 changes: 17 additions & 5 deletions proto/oracle/v1beta1/oracle.proto
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,18 @@ message Params {
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
uint64 reward_distribution_window = 4 [(gogoproto.moretags) = "yaml:\"reward_distribution_window\""];
repeated Pair whitelist = 5 [
repeated Pair whitelist = 4 [
(gogoproto.moretags) = "yaml:\"whitelist\"",
(gogoproto.castrepeated) = "PairList",
(gogoproto.nullable) = false
];
string slash_fraction = 6 [
string slash_fraction = 5 [
(gogoproto.moretags) = "yaml:\"slash_fraction\"",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
uint64 slash_window = 7 [(gogoproto.moretags) = "yaml:\"slash_window\""];
string min_valid_per_window = 8 [
uint64 slash_window = 6 [(gogoproto.moretags) = "yaml:\"slash_window\""];
string min_valid_per_window = 7 [
(gogoproto.moretags) = "yaml:\"min_valid_per_window\"",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
Expand Down Expand Up @@ -92,3 +91,16 @@ message ExchangeRateTuple {
(gogoproto.nullable) = false
];
}

// PairReward defines a credit object towards validators
// which provide prices faithfully for different pairs.
message PairReward {
// pair defines the pair for which we incentivize validator to provide prices for.
string pair = 1;
// id uniquely identifies the rewards instance of the pair
uint64 id = 2;
// vote_periods defines the vote periods left in which rewards will be distributed.
uint64 vote_periods = 3;
// coins defines the amount of coins to distribute in a single vote period.
repeated cosmos.base.v1beta1.Coin coins = 4 [(gogoproto.nullable) = false];
}
14 changes: 13 additions & 1 deletion x/oracle/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, data *types.GenesisState
}
}

for _, pr := range data.PairRewards {
keeper.SetPairReward(ctx, pr)
}

keeper.SetParams(ctx, data.Params)

// check if the module account exists
Expand Down Expand Up @@ -123,11 +127,19 @@ func ExportGenesis(ctx sdk.Context, keeper keeper.Keeper) *types.GenesisState {
return false
})

pairRewards := []*types.PairReward{}
keeper.IterateAllPairRewards(ctx, func(rewards *types.PairReward) (stop bool) {
pairRewards = append(pairRewards, rewards)
return false
})

return types.NewGenesisState(params,
exchangeRates,
feederDelegations,
missCounters,
aggregateExchangeRatePrevotes,
aggregateExchangeRateVotes,
pairs)
pairs,
pairRewards,
)
}
5 changes: 4 additions & 1 deletion x/oracle/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@ func TestExportInitGenesis(t *testing.T) {
input := keeper.CreateTestInput(t)

input.OracleKeeper.SetFeederDelegation(input.Ctx, keeper.ValAddrs[0], keeper.Addrs[1])
input.OracleKeeper.SetExchangeRate(input.Ctx, "denom", sdk.NewDec(123))
input.OracleKeeper.SetExchangeRate(input.Ctx, "pair1:pair2", sdk.NewDec(123))
input.OracleKeeper.SetAggregateExchangeRatePrevote(input.Ctx, keeper.ValAddrs[0], types.NewAggregateExchangeRatePrevote(types.AggregateVoteHash{123}, keeper.ValAddrs[0], uint64(2)))
input.OracleKeeper.SetAggregateExchangeRateVote(input.Ctx, keeper.ValAddrs[0], types.NewAggregateExchangeRateVote(types.ExchangeRateTuples{{Pair: "foo", ExchangeRate: sdk.NewDec(123)}}, keeper.ValAddrs[0]))
input.OracleKeeper.SetPair(input.Ctx, "pair1:pair1")
input.OracleKeeper.SetPair(input.Ctx, "pair2:pair2")
input.OracleKeeper.SetMissCounter(input.Ctx, keeper.ValAddrs[0], 10)
input.OracleKeeper.SetPairReward(input.Ctx, &types.PairReward{
Pair: "pair1:pair2",
})
genesis := oracle.ExportGenesis(input.Ctx, input.OracleKeeper)

newInput := keeper.CreateTestInput(t)
Expand Down
18 changes: 0 additions & 18 deletions x/oracle/keeper/alias_functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,10 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"

"github.com/NibiruChain/nibiru/x/common"

"github.com/NibiruChain/nibiru/x/oracle/types"
)

// GetOracleAccount returns oracle ModuleAccount
func (k Keeper) GetOracleAccount(ctx sdk.Context) authtypes.ModuleAccountI {
return k.accountKeeper.GetModuleAccount(ctx, types.ModuleName)
}

// GetRewardPool retrieves the balance of the oracle module account
func (k Keeper) GetRewardPool(ctx sdk.Context, denom string) sdk.Coin {
// TODO(mercilex): this logic needs to be redefined. https://github.com/NibiruChain/nibiru/issues/805
if denom != common.DenomGov {
return sdk.NewCoin("zero", sdk.ZeroInt())
}
acc := k.accountKeeper.GetModuleAccount(ctx, types.ModuleName)
return k.bankKeeper.GetBalance(ctx, acc.GetAddress(), denom)
}

// GetRewardPool retrieves the balance of the oracle module account
func (k Keeper) GetRewardPoolLegacy(ctx sdk.Context) sdk.Coins {
acc := k.accountKeeper.GetModuleAccount(ctx, types.ModuleName)
return k.bankKeeper.GetAllBalances(ctx, acc.GetAddress())
}
2 changes: 1 addition & 1 deletion x/oracle/keeper/ballot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func TestOrganizeAggregate(t *testing.T) {
)
}

// organize votes by denom
// organize votes by pair
ballotMap := input.OracleKeeper.OrganizeBallotByPair(input.Ctx, map[string]types.ValidatorPerformance{
ValAddrs[0].String(): {
Power: power,
Expand Down
24 changes: 11 additions & 13 deletions x/oracle/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func TestExchangeRate(t *testing.T) {
require.Error(t, err)

numExchangeRates := 0
handler := func(denom string, exchangeRate sdk.Dec) (stop bool) {
handler := func(_ string, exchangeRate sdk.Dec) (stop bool) {
numExchangeRates = numExchangeRates + 1
return false
}
Expand All @@ -59,8 +59,8 @@ func TestIterateExchangeRates(t *testing.T) {
input.OracleKeeper.SetExchangeRate(input.Ctx, common.PairETHStable.String(), ethStablePrice)
input.OracleKeeper.SetExchangeRate(input.Ctx, common.PairBTCStable.String(), btcStablePrice)

input.OracleKeeper.IterateExchangeRates(input.Ctx, func(denom string, rate sdk.Dec) (stop bool) {
switch denom {
input.OracleKeeper.IterateExchangeRates(input.Ctx, func(pair string, rate sdk.Dec) (stop bool) {
switch pair {
case common.PairCollStable.String():
require.Equal(t, collStablePrice, rate)
case common.PairETHStable.String():
Expand All @@ -83,7 +83,7 @@ func TestRewardPool(t *testing.T) {
panic(err) // never occurs
}
KFees := input.OracleKeeper.GetRewardPool(input.Ctx, common.DenomColl)
KFees := input.OracleKeeper.AccrueVotePeriodPairRewards(input.Ctx, common.DenomColl)
require.Equal(t, fees[0], KFees)
}
Expand Down Expand Up @@ -118,7 +118,6 @@ func TestParams(t *testing.T) {
votePeriod := uint64(10)
voteThreshold := sdk.NewDecWithPrec(33, 2)
oracleRewardBand := sdk.NewDecWithPrec(1, 2)
rewardDistributionWindow := uint64(10000000000000)
slashFraction := sdk.NewDecWithPrec(1, 2)
slashWindow := uint64(1000)
minValidPerWindow := sdk.NewDecWithPrec(1, 4)
Expand All @@ -129,14 +128,13 @@ func TestParams(t *testing.T) {

// Should really test validateParams, but skipping because obvious
newParams := types.Params{
VotePeriod: votePeriod,
VoteThreshold: voteThreshold,
RewardBand: oracleRewardBand,
RewardDistributionWindow: rewardDistributionWindow,
Whitelist: whitelist,
SlashFraction: slashFraction,
SlashWindow: slashWindow,
MinValidPerWindow: minValidPerWindow,
VotePeriod: votePeriod,
VoteThreshold: voteThreshold,
RewardBand: oracleRewardBand,
Whitelist: whitelist,
SlashFraction: slashFraction,
SlashWindow: slashWindow,
MinValidPerWindow: minValidPerWindow,
}
input.OracleKeeper.SetParams(input.Ctx, newParams)

Expand Down
1 change: 0 additions & 1 deletion x/oracle/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,6 @@ func setup(t *testing.T) (TestInput, types.MsgServer) {
params := input.OracleKeeper.GetParams(input.Ctx)
params.VotePeriod = 1
params.SlashWindow = 100
params.RewardDistributionWindow = 100
input.OracleKeeper.SetParams(input.Ctx, params)
msgServer := NewMsgServerImpl(input.OracleKeeper)

Expand Down
6 changes: 0 additions & 6 deletions x/oracle/keeper/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,6 @@ func (k Keeper) RewardBand(ctx sdk.Context) (res sdk.Dec) {
return
}

// RewardDistributionWindow returns the number of vote periods during which seigiornage reward comes in and then is distributed.
func (k Keeper) RewardDistributionWindow(ctx sdk.Context) (res uint64) {
k.paramSpace.Get(ctx, types.KeyRewardDistributionWindow, &res)
return
}

// Whitelist returns the pair list that can be activated
func (k Keeper) Whitelist(ctx sdk.Context) (res types.PairList) {
k.paramSpace.Get(ctx, types.KeyWhitelist, &res)
Expand Down
Loading

0 comments on commit eccb38b

Please sign in to comment.