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(auction): oracle fees #2500

Merged
merged 6 commits into from
Apr 19, 2024
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 @@ -49,6 +49,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Features

- [2472](https://github.com/umee-network/umee/pull/2472) un-wire the `crisis` module from umee app.
- [2500](https://github.com/umee-network/umee/pull/2500) (x/leverage): add Rewards Auction fees and `params.rewards_auction_factor`.

### Improvements

Expand Down
5 changes: 5 additions & 0 deletions proto/umee/leverage/v1/events.proto
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,8 @@ message EventFundOracle {
// Assets sent to oracle module
repeated cosmos.base.v1beta1.Coin assets = 1 [(gogoproto.nullable) = false];
}

// EventFundAuction is emitted when sending rewards to auction module
message EventFundAuction {
repeated cosmos.base.v1beta1.Coin assets = 1 [(gogoproto.nullable) = false];
}
8 changes: 8 additions & 0 deletions proto/umee/leverage/v1/leverage.proto
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ message Params {
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"direct_liquidation_fee\""
];
// Rewards Auction Factor determines the portion of interest accrued on
// borrows that is sent to the auction module for the rewards auction.
// Valid values: 0-1.
string rewards_auction_factor = 7 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"oracle_reward_factor\""
];
}

// Token defines a token, along with its metadata and parameters, in the Umee
Expand Down
26 changes: 26 additions & 0 deletions swagger/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1110,6 +1110,16 @@ paths:

uTokens as liquidation rewards.

Valid values: 0-1.
rewards_auction_factor:
type: string
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved
description: >-
Rewards Auction Factor determines the portion of interest
accrued on

borrows that is sent to the auction module for the rewards
auction.

Valid values: 0-1.
description: Params defines the parameters for the leverage module.
description: >-
Expand Down Expand Up @@ -6575,6 +6585,12 @@ definitions:

uTokens as liquidation rewards.

Valid values: 0-1.
rewards_auction_factor:
type: string
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved
description: |-
Rewards Auction Factor determines the portion of interest accrued on
borrows that is sent to the auction module for the rewards auction.
Valid values: 0-1.
description: Params defines the parameters for the leverage module.
umee.leverage.v1.QueryAccountBalancesResponse:
Expand Down Expand Up @@ -7235,6 +7251,16 @@ definitions:

uTokens as liquidation rewards.

Valid values: 0-1.
rewards_auction_factor:
type: string
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved
description: >-
Rewards Auction Factor determines the portion of interest accrued
on

borrows that is sent to the auction module for the rewards
auction.

Valid values: 0-1.
description: Params defines the parameters for the leverage module.
description: |-
Expand Down
4 changes: 2 additions & 2 deletions x/leverage/client/tests/tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ func (s *IntegrationTests) TestLeverageScenario() {
OracleHistoricPrice: &oracleSymbolPrice,
UTokenExchangeRate: sdk.OneDec(),
// Borrow rate * (1 - ReserveFactor - OracleRewardFactor)
// 1.52 * (1 - 0.2 - 0.01) = 1.2008
Supply_APY: sdk.MustNewDecFromStr("1.2008"),
// 1.52 * (1 - 0.2 - 0.01 - 0.02)
Supply_APY: sdk.MustNewDecFromStr("1.1704"),
// This is an edge case technically - when effective supply, meaning
// module balance + total borrows, is zero, utilization (0/0) is
// interpreted as 100% so max borrow rate (152% APY) is used.
Expand Down
1 change: 1 addition & 0 deletions x/leverage/fixtures/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ func Params() types.Params {
CompleteLiquidationThreshold: sdk.MustNewDecFromStr("0.1"),
MinimumCloseFactor: sdk.MustNewDecFromStr("0.01"),
OracleRewardFactor: sdk.MustNewDecFromStr("0.01"),
RewardsAuctionFactor: sdk.MustNewDecFromStr("0.02"),
SmallLiquidationSize: sdk.MustNewDecFromStr("100.00"),
DirectLiquidationFee: sdk.MustNewDecFromStr("0.1"),
}
Expand Down
13 changes: 7 additions & 6 deletions x/leverage/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,13 @@ func (s *IntegrationTestSuite) TestQuerier_MarketSummary() {
oracleSymbolPrice := sdk.MustNewDecFromStr("4.21")

expected := types.QueryMarketSummaryResponse{
SymbolDenom: "UMEE",
Exponent: 6,
OraclePrice: &oracleSymbolPrice,
OracleHistoricPrice: &oracleSymbolPrice,
UTokenExchangeRate: sdk.OneDec(),
Supply_APY: sdk.MustNewDecFromStr("1.2008"),
SymbolDenom: "UMEE",
Exponent: 6,
OraclePrice: &oracleSymbolPrice,
OracleHistoricPrice: &oracleSymbolPrice,
UTokenExchangeRate: sdk.OneDec(),
// see cli/tests "query market summary - zero supply"
Supply_APY: sdk.MustNewDecFromStr("1.1704"),
Borrow_APY: sdk.MustNewDecFromStr("1.52"),
Supplied: sdk.ZeroInt(),
Reserved: sdk.ZeroInt(),
Expand Down
17 changes: 10 additions & 7 deletions x/leverage/keeper/interest.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ func (k Keeper) DeriveSupplyAPY(ctx sdk.Context, denom string) sdk.Dec {

borrowRate := k.DeriveBorrowAPY(ctx, denom)
utilization := k.SupplyUtilization(ctx, denom)
reduction := k.GetParams(ctx).OracleRewardFactor.Add(token.ReserveFactor)
params := k.GetParams(ctx)
reduction := params.OracleRewardFactor.Add(params.RewardsAuctionFactor).Add(token.ReserveFactor)

// supply APY = borrow APY * utilization, reduced by reserve factor and oracle reward factor
return borrowRate.Mul(utilization).Mul(sdk.OneDec().Sub(reduction))
Expand Down Expand Up @@ -106,10 +107,11 @@ func (k Keeper) AccrueAllInterest(ctx sdk.Context) error {

// fetch required parameters
tokens := k.GetAllRegisteredTokens(ctx)
oracleRewardFactor := k.GetParams(ctx).OracleRewardFactor
params := k.GetParams(ctx)

// create sdk.Coins objects to track oracle rewards, new reserves, and total interest accrued
oracleRewards := sdk.NewCoins()
auctionRewards := sdk.NewCoins()
newReserves := sdk.NewCoins()
totalInterest := sdk.NewCoins()

Expand Down Expand Up @@ -148,10 +150,13 @@ func (k Keeper) AccrueAllInterest(ctx sdk.Context) error {
))
}

// calculate oracle rewards accrued for this denom
oracleRewards = oracleRewards.Add(sdk.NewCoin(
token.BaseDenom,
interestAccrued.Mul(oracleRewardFactor).TruncateInt(),
interestAccrued.Mul(params.OracleRewardFactor).TruncateInt(),
))
auctionRewards = auctionRewards.Add(sdk.NewCoin(
token.BaseDenom,
interestAccrued.Mul(params.RewardsAuctionFactor).TruncateInt(),
))
}

Expand All @@ -162,12 +167,10 @@ func (k Keeper) AccrueAllInterest(ctx sdk.Context) error {
}
}

// fund oracle reward pool
if err := k.FundOracle(ctx, oracleRewards); err != nil {
if err := k.fundModules(ctx, oracleRewards, auctionRewards); err != nil {
return err
}

// set LastInterestTime
err := k.setLastInterestTime(ctx, currentTime)
if err != nil {
return err
Expand Down
6 changes: 3 additions & 3 deletions x/leverage/keeper/interest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ func (s *IntegrationTestSuite) TestAccrueZeroInterest() {
require.Equal(sdk.MustNewDecFromStr("0.03"), borrowAPY)

// supply APY when borrow APY is 3%
// and utilization is 4%, and reservefactor is 20%, and OracleRewardFactor is 1%
// 0.03 * 0.04 * (1 - 0.21) = 0.000948
// and utilization is 4%, and reserve factor=20%, OracleRewardFactor=1% RewardsAuctionFactor=2%
// 0.03 * 0.04 * (1 - 0.2 - 0.01 - 0.02)
supplyAPY := app.LeverageKeeper.DeriveSupplyAPY(ctx, appparams.BondDenom)
require.Equal(sdk.MustNewDecFromStr("0.000948"), supplyAPY)
require.Equal(sdk.MustNewDecFromStr("0.000924"), supplyAPY)
}

func (s *IntegrationTestSuite) TestDynamicInterest() {
Expand Down
56 changes: 40 additions & 16 deletions x/leverage/keeper/oracle.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
"strings"

"cosmossdk.io/errors"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/umee-network/umee/v6/util/coin"
"github.com/umee-network/umee/v6/util/sdkutil"
"github.com/umee-network/umee/v6/x/auction"
"github.com/umee-network/umee/v6/x/leverage/types"
oracletypes "github.com/umee-network/umee/v6/x/oracle/types"
)
Expand Down Expand Up @@ -250,30 +252,52 @@
return exponent(p1, powerDifference).Quo(p2), nil
}

// FundOracle transfers requested coins to the oracle module account, as
// fundModules transfers requested coins to other module account, as
// long as the leverage module account has sufficient unreserved assets.
func (k Keeper) FundOracle(ctx sdk.Context, requested sdk.Coins) error {
rewards := sdk.Coins{}
func (k Keeper) fundModules(ctx sdk.Context, toOracle, toAuction sdk.Coins) error {
toOracleCheck := sdk.Coins{}
toAuctionCheck := sdk.Coins{}
available := map[string]sdkmath.Int{}

// reduce rewards if they exceed unreserved module balance
for _, coin := range requested {
amountToTransfer := sdk.MinInt(coin.Amount, k.AvailableLiquidity(ctx, coin.Denom))

if amountToTransfer.IsPositive() {
rewards = rewards.Add(sdk.NewCoin(coin.Denom, amountToTransfer))
for _, o := range toOracle {
avl := k.AvailableLiquidity(ctx, o.Denom)
amt := sdk.MinInt(o.Amount, avl)
if amt.IsPositive() {
toOracleCheck = toOracleCheck.Add(sdk.NewCoin(o.Denom, amt))
avl.Sub(amt)

Check warning on line 268 in x/leverage/keeper/oracle.go

View check run for this annotation

Codecov / codecov/patch

x/leverage/keeper/oracle.go#L264-L268

Added lines #L264 - L268 were not covered by tests
}
available[o.Denom] = avl

Check warning on line 270 in x/leverage/keeper/oracle.go

View check run for this annotation

Codecov / codecov/patch

x/leverage/keeper/oracle.go#L270

Added line #L270 was not covered by tests
}
for _, o := range toAuction {
avl, ok := available[o.Denom]
if !ok {
avl = k.AvailableLiquidity(ctx, o.Denom)

Check warning on line 275 in x/leverage/keeper/oracle.go

View check run for this annotation

Codecov / codecov/patch

x/leverage/keeper/oracle.go#L273-L275

Added lines #L273 - L275 were not covered by tests
}
amt := sdk.MinInt(o.Amount, avl)
if amt.IsPositive() {
toAuctionCheck = toAuctionCheck.Add(sdk.NewCoin(o.Denom, amt))
avl.Sub(amt)

Check warning on line 280 in x/leverage/keeper/oracle.go

View check run for this annotation

Codecov / codecov/patch

x/leverage/keeper/oracle.go#L277-L280

Added lines #L277 - L280 were not covered by tests
}
available[o.Denom] = avl

Check warning on line 282 in x/leverage/keeper/oracle.go

View check run for this annotation

Codecov / codecov/patch

x/leverage/keeper/oracle.go#L282

Added line #L282 was not covered by tests
}

// This action is not caused by a message so we need to make an event here
// This action is caused by end blocker, not a message handler, so we need to emit an event
k.Logger(ctx).Debug(
"funded oracle",
"amount", rewards,
"funded ",
"to oracle", toOracleCheck,
"to auction", toAuctionCheck,
)
sdkutil.Emit(&ctx, &types.EventFundOracle{Assets: rewards})

// Send rewards
if !rewards.IsZero() {
return k.bankKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, oracletypes.ModuleName, rewards)
send := k.bankKeeper.SendCoinsFromModuleToModule
if !toOracleCheck.IsZero() {
sdkutil.Emit(&ctx, &types.EventFundOracle{Assets: toOracleCheck})
if err := send(ctx, types.ModuleName, oracletypes.ModuleName, toOracleCheck); err != nil {
return err

Check warning on line 295 in x/leverage/keeper/oracle.go

View check run for this annotation

Codecov / codecov/patch

x/leverage/keeper/oracle.go#L293-L295

Added lines #L293 - L295 were not covered by tests
}
}
if !toAuctionCheck.IsZero() {
sdkutil.Emit(&ctx, &types.EventFundAuction{Assets: toOracleCheck})
return send(ctx, types.ModuleName, auction.ModuleName, toAuctionCheck)

Check warning on line 300 in x/leverage/keeper/oracle.go

View check run for this annotation

Codecov / codecov/patch

x/leverage/keeper/oracle.go#L299-L300

Added lines #L299 - L300 were not covered by tests
}

return nil
Expand Down
Loading
Loading