diff --git a/tests/e2e/e2e_metoken_test.go b/tests/e2e/e2e_metoken_test.go index 7835612de0..6e43a5cf33 100644 --- a/tests/e2e/e2e_metoken_test.go +++ b/tests/e2e/e2e_metoken_test.go @@ -115,6 +115,22 @@ func (s *E2ETest) TestMetokenSwapAndRedeem() { ) } +func (s *E2ETest) checkMetokenPriceInOracle(denom string) { + s.Require().Eventually( + func() bool { + exchangeRates, err := s.QueryExchangeRate(s.UmeeREST(), denom) + if err != nil { + return false + } + if exchangeRates.AmountOf(denom).IsZero() { + return false + } + return true + }, + 2*time.Minute, 12*time.Second, "fetching metoken price", + ) +} + func (s *E2ETest) checkMetokenBalance(valAddr, denom string) { s.Require().Eventually( func() bool { diff --git a/x/metoken/expected_keepers.go b/x/metoken/expected_keepers.go index 64e2838981..0fbe27a669 100644 --- a/x/metoken/expected_keepers.go +++ b/x/metoken/expected_keepers.go @@ -34,4 +34,5 @@ type LeverageKeeper interface { // OracleKeeper interface for price feed. type OracleKeeper interface { AllMedianPrices(ctx sdk.Context) otypes.Prices + SetExchangeRate(ctx sdk.Context, denom string, rate sdk.Dec) } diff --git a/x/metoken/keeper/intest/keeper_test.go b/x/metoken/keeper/intest/keeper_test.go index 7096180e60..d6cf7e5610 100644 --- a/x/metoken/keeper/intest/keeper_test.go +++ b/x/metoken/keeper/intest/keeper_test.go @@ -52,6 +52,7 @@ func initTestSuite(t *testing.T, registry []metoken.Index, balances []metoken.In AllMedianPrices(gomock.Any()). Return(mocks.ValidPrices()). AnyTimes() + oracleMock.EXPECT().SetExchangeRate(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() kb := keeper.NewKeeperBuilder( app.AppCodec(), @@ -108,6 +109,12 @@ func initTestSuite(t *testing.T, registry []metoken.Index, balances []metoken.In mocks.ValidToken(mocks.ETHBaseDenom, mocks.ETHSymbolDenom, 18), ), ) + require.NoError( + app.LeverageKeeper.SetTokenSettings( + ctx, + mocks.ValidToken(mocks.MeUSDDenom, mocks.MeUSDDenom, 6), + ), + ) return &KeeperTestSuite{ ctx: ctx, diff --git a/x/metoken/keeper/intest/price_test.go b/x/metoken/keeper/intest/price_test.go new file mode 100644 index 0000000000..3a6df76d45 --- /dev/null +++ b/x/metoken/keeper/intest/price_test.go @@ -0,0 +1,30 @@ +package intest + +import ( + "testing" + + "github.com/stretchr/testify/require" + "github.com/umee-network/umee/v6/util/checkers" + "github.com/umee-network/umee/v6/x/metoken" + "github.com/umee-network/umee/v6/x/metoken/mocks" +) + +func TestPrice_SetPricesToOracle(t *testing.T) { + index := mocks.StableIndex(mocks.MeUSDDenom) + + s := initTestSuite(t, nil, nil) + msgServer, ctx, app := s.msgServer, s.ctx, s.app + + _, err := msgServer.GovUpdateRegistry( + ctx, &metoken.MsgGovUpdateRegistry{ + Authority: checkers.GovModuleAddr, + AddIndex: []metoken.Index{index}, + UpdateIndex: nil, + }, + ) + require := require.New(t) + require.NoError(err) + + err = app.MetokenKeeperB.Keeper(&ctx).SetPricesToOracle() + require.NoError(err) +} diff --git a/x/metoken/keeper/mocks_test.go b/x/metoken/keeper/mocks_test.go index e38825a51c..a99f520f48 100644 --- a/x/metoken/keeper/mocks_test.go +++ b/x/metoken/keeper/mocks_test.go @@ -18,6 +18,9 @@ func (o Oracle) AllMedianPrices(_ sdk.Context) otypes.Prices { return o.prices } +func (o Oracle) SetExchangeRate(_ sdk.Context, _ string, _ sdk.Dec) { +} + func NewOracleMock() Oracle { return Oracle{prices: mocks.ValidPrices()} } diff --git a/x/metoken/keeper/price.go b/x/metoken/keeper/price.go index 33cf972cd0..16d2c6ca54 100644 --- a/x/metoken/keeper/price.go +++ b/x/metoken/keeper/price.go @@ -96,6 +96,38 @@ func (k Keeper) Prices(index metoken.Index) (metoken.IndexPrices, error) { return indexPrices, nil } +// SetPricesToOracle of every registered index. +func (k Keeper) SetPricesToOracle() error { + indexes := k.GetAllRegisteredIndexes() + for _, index := range indexes { + iPrice, err := k.Prices(index) + if err != nil { + k.Logger().Error( + "setting price to oracle: couldn't calculate the price", + "denom", index.Denom, + "error", err.Error(), + "block_time", k.ctx.BlockTime(), + ) + continue + } + + indexToken, err := k.leverageKeeper.GetTokenSettings(*k.ctx, index.Denom) + if err != nil { + k.Logger().Error( + "setting price to oracle: couldn't get token settings", + "denom", index.Denom, + "error", err.Error(), + "block_time", k.ctx.BlockTime(), + ) + continue + } + + k.oracleKeeper.SetExchangeRate(*k.ctx, indexToken.SymbolDenom, iPrice.Price) + } + + return nil +} + // latestPrice from the list of medians, based on the block number. func latestPrice(prices otypes.Prices, symbolDenom string) (sdk.Dec, error) { latestPrice := otypes.Price{} diff --git a/x/metoken/keeper/price_test.go b/x/metoken/keeper/price_test.go index 51d712273e..9c686553fb 100644 --- a/x/metoken/keeper/price_test.go +++ b/x/metoken/keeper/price_test.go @@ -157,6 +157,13 @@ func TestIndexPrices_Convert(t *testing.T) { ) } +func TestIndexPrices_SetPricesToOracle(t *testing.T) { + o := NewOracleMock() + l := NewLeverageMock() + k := initMeUSDKeeper(t, nil, l, o) + require.NoError(t, k.SetPricesToOracle()) +} + func meUSDIndexPricesAdjustedToBalance(t *testing.T, balance metoken.IndexBalances) metoken.IndexPrices { usdtSupply, i := balance.AssetBalance(mocks.USDTBaseDenom) require.True(t, i >= 0) diff --git a/x/metoken/mocks/keepers.go b/x/metoken/mocks/keepers.go index d76c19431d..fa015700f6 100644 --- a/x/metoken/mocks/keepers.go +++ b/x/metoken/mocks/keepers.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: ./x/metoken/expected_keepers.go +// Source: ./../../x/metoken/expected_keepers.go // Package mocks is a generated GoMock package. package mocks @@ -274,3 +274,15 @@ func (mr *MockOracleKeeperMockRecorder) AllMedianPrices(ctx interface{}) *gomock mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllMedianPrices", reflect.TypeOf((*MockOracleKeeper)(nil).AllMedianPrices), ctx) } + +// SetExchangeRate mocks base method. +func (m *MockOracleKeeper) SetExchangeRate(ctx types.Context, denom string, rate types.Dec) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetExchangeRate", ctx, denom, rate) +} + +// SetExchangeRate indicates an expected call of SetExchangeRate. +func (mr *MockOracleKeeperMockRecorder) SetExchangeRate(ctx, denom, rate interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetExchangeRate", reflect.TypeOf((*MockOracleKeeper)(nil).SetExchangeRate), ctx, denom, rate) +} diff --git a/x/metoken/module/abci.go b/x/metoken/module/abci.go index cb76993ccf..2b23205551 100644 --- a/x/metoken/module/abci.go +++ b/x/metoken/module/abci.go @@ -11,5 +11,6 @@ import ( func EndBlocker(k keeper.Keeper) []abci.ValidatorUpdate { util.Panic(k.ClaimLeverageInterest()) util.Panic(k.RebalanceReserves()) + util.Panic(k.SetPricesToOracle()) return []abci.ValidatorUpdate{} } diff --git a/x/oracle/keeper/hooks.go b/x/oracle/keeper/hooks.go index a3d8554e1c..cc1e1bc2e4 100644 --- a/x/oracle/keeper/hooks.go +++ b/x/oracle/keeper/hooks.go @@ -2,6 +2,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/umee-network/umee/v6/x/metoken" leveragetypes "github.com/umee-network/umee/v6/x/leverage/types" "github.com/umee-network/umee/v6/x/oracle/types" @@ -29,6 +30,11 @@ func (h Hooks) AfterTokenRegistered(ctx sdk.Context, token leveragetypes.Token) return } + // Metokens shouldn't be part of oracle accept list. Every index informs its price to oracle each endBlock. + if metoken.IsMeToken(token.BaseDenom) { + return + } + acceptList := h.k.AcceptList(ctx) var tokenExists bool