diff --git a/x/pricefeed/abci.go b/x/pricefeed/abci.go index 67a0cb0b..ac0ca068 100644 --- a/x/pricefeed/abci.go +++ b/x/pricefeed/abci.go @@ -1,17 +1,25 @@ package pricefeed import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" ) // EndBlocker updates the current pricefeed func EndBlocker(ctx sdk.Context, k Keeper) { // Update the current price of each asset. - for _, a := range k.GetAssetParams(ctx) { + for _, a := range k.GetMarketParams(ctx) { if a.Active { - err := k.SetCurrentPrices(ctx, a.AssetCode) + err := k.SetCurrentPrices(ctx, a.MarketID) if err != nil { - // TODO emit an event that price failed to update + // In the event of failure, emit an event. + ctx.EventManager().EmitEvent( + sdk.NewEvent( + EventTypeNoValidPrices, + sdk.NewAttribute(AttributeKeyPriceUpdateFailed, fmt.Sprintf("%s", a.MarketID)), + ), + ) continue } } diff --git a/x/pricefeed/alias.go b/x/pricefeed/alias.go index bbe6e654..01a51ea7 100644 --- a/x/pricefeed/alias.go +++ b/x/pricefeed/alias.go @@ -11,25 +11,27 @@ import ( ) const ( - DefaultCodespace = types.DefaultCodespace - CodeEmptyInput = types.CodeEmptyInput - CodeExpired = types.CodeExpired - CodeInvalidPrice = types.CodeInvalidPrice - CodeInvalidAsset = types.CodeInvalidAsset - CodeInvalidOracle = types.CodeInvalidOracle - ModuleName = types.ModuleName - StoreKey = types.StoreKey - RouterKey = types.RouterKey - QuerierRoute = types.QuerierRoute - DefaultParamspace = types.DefaultParamspace - RawPriceFeedPrefix = types.RawPriceFeedPrefix - CurrentPricePrefix = types.CurrentPricePrefix - AssetPrefix = types.AssetPrefix - OraclePrefix = types.OraclePrefix - TypeMsgPostPrice = types.TypeMsgPostPrice - QueryCurrentPrice = types.QueryCurrentPrice - QueryRawPrices = types.QueryRawPrices - QueryAssets = types.QueryAssets + DefaultCodespace = types.DefaultCodespace + CodeEmptyInput = types.CodeEmptyInput + CodeExpired = types.CodeExpired + CodeInvalidPrice = types.CodeInvalidPrice + CodeInvalidAsset = types.CodeInvalidAsset + CodeInvalidOracle = types.CodeInvalidOracle + EventTypeNoValidPrices = types.EventTypeNoValidPrices + AttributeKeyPriceUpdateFailed = types.AttributeKeyPriceUpdateFailed + ModuleName = types.ModuleName + StoreKey = types.StoreKey + RouterKey = types.RouterKey + QuerierRoute = types.QuerierRoute + DefaultParamspace = types.DefaultParamspace + RawPriceFeedPrefix = types.RawPriceFeedPrefix + CurrentPricePrefix = types.CurrentPricePrefix + AssetPrefix = types.AssetPrefix + OraclePrefix = types.OraclePrefix + TypeMsgPostPrice = types.TypeMsgPostPrice + QueryCurrentPrice = types.QueryCurrentPrice + QueryRawPrices = types.QueryRawPrices + QueryAssets = types.QueryAssets ) var ( @@ -51,23 +53,23 @@ var ( NewQuerier = keeper.NewQuerier // variable aliases - ModuleCdc = types.ModuleCdc - KeyAssets = types.KeyAssets + ModuleCdc = types.ModuleCdc + KeyMarkets = types.KeyMarkets ) type ( + Market = types.Market + Markets = types.Markets + Oracle = types.Oracle + Oracles = types.Oracles + CurrentPrice = types.CurrentPrice + PostedPrice = types.PostedPrice + SortDecs = types.SortDecs GenesisState = types.GenesisState MsgPostPrice = types.MsgPostPrice Params = types.Params ParamSubspace = types.ParamSubspace QueryRawPricesResp = types.QueryRawPricesResp QueryAssetsResp = types.QueryAssetsResp - Asset = types.Asset - Assets = types.Assets - Oracle = types.Oracle - Oracles = types.Oracles - CurrentPrice = types.CurrentPrice - PostedPrice = types.PostedPrice - SortDecs = types.SortDecs Keeper = keeper.Keeper ) diff --git a/x/pricefeed/genesis.go b/x/pricefeed/genesis.go index 87cb45fc..3bf16251 100644 --- a/x/pricefeed/genesis.go +++ b/x/pricefeed/genesis.go @@ -12,16 +12,16 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState) { // Iterate through the posted prices and set them in the store for _, pp := range data.PostedPrices { - _, err := keeper.SetPrice(ctx, pp.OracleAddress, pp.AssetCode, pp.Price, pp.Expiry) + _, err := keeper.SetPrice(ctx, pp.OracleAddress, pp.MarketID, pp.Price, pp.Expiry) if err != nil { panic(err) } } // Set the current price (if any) based on what's now in the store - for _, a := range data.Params.Assets { + for _, a := range data.Params.Markets { if a.Active { - _ = keeper.SetCurrentPrices(ctx, a.AssetCode) + _ = keeper.SetCurrentPrices(ctx, a.MarketID) } } } @@ -33,8 +33,8 @@ func ExportGenesis(ctx sdk.Context, keeper Keeper) GenesisState { params := keeper.GetParams(ctx) var postedPrices []PostedPrice - for _, asset := range keeper.GetAssetParams(ctx) { - pp := keeper.GetRawPrices(ctx, asset.AssetCode) + for _, asset := range keeper.GetMarketParams(ctx) { + pp := keeper.GetRawPrices(ctx, asset.MarketID) postedPrices = append(postedPrices, pp...) } diff --git a/x/pricefeed/keeper/keeper.go b/x/pricefeed/keeper/keeper.go index a5fcfa0d..f50291d7 100644 --- a/x/pricefeed/keeper/keeper.go +++ b/x/pricefeed/keeper/keeper.go @@ -41,13 +41,13 @@ func NewKeeper( func (k Keeper) SetPrice( ctx sdk.Context, oracle sdk.AccAddress, - assetCode string, + marketID string, price sdk.Dec, expiry time.Time) (types.PostedPrice, sdk.Error) { // If the expiry is less than or equal to the current blockheight, we consider the price valid if expiry.After(ctx.BlockTime()) { store := ctx.KVStore(k.storeKey) - prices := k.GetRawPrices(ctx, assetCode) + prices := k.GetRawPrices(ctx, marketID) var index int found := false for i := range prices { @@ -60,17 +60,17 @@ func (k Keeper) SetPrice( // set the price for that particular oracle if found { prices[index] = types.PostedPrice{ - AssetCode: assetCode, OracleAddress: oracle, + MarketID: marketID, OracleAddress: oracle, Price: price, Expiry: expiry} } else { prices = append(prices, types.PostedPrice{ - AssetCode: assetCode, OracleAddress: oracle, + MarketID: marketID, OracleAddress: oracle, Price: price, Expiry: expiry}) index = len(prices) - 1 } store.Set( - []byte(types.RawPriceFeedPrefix+assetCode), k.cdc.MustMarshalBinaryBare(prices), + []byte(types.RawPriceFeedPrefix+marketID), k.cdc.MustMarshalBinaryBare(prices), ) return prices[index], nil } @@ -79,67 +79,74 @@ func (k Keeper) SetPrice( } // SetCurrentPrices updates the price of an asset to the meadian of all valid oracle inputs -func (k Keeper) SetCurrentPrices(ctx sdk.Context, assetCode string) sdk.Error { - _, ok := k.GetAsset(ctx, assetCode) +func (k Keeper) SetCurrentPrices(ctx sdk.Context, marketID string) sdk.Error { + _, ok := k.GetMarket(ctx, marketID) if !ok { return types.ErrInvalidAsset(k.codespace) } - prices := k.GetRawPrices(ctx, assetCode) + prices := k.GetRawPrices(ctx, marketID) var notExpiredPrices []types.CurrentPrice // filter out expired prices for _, v := range prices { if v.Expiry.After(ctx.BlockTime()) { notExpiredPrices = append(notExpiredPrices, types.CurrentPrice{ - AssetCode: v.AssetCode, - Price: v.Price, + MarketID: v.MarketID, + Price: v.Price, }) } } - l := len(notExpiredPrices) - var medianPrice sdk.Dec - // TODO make threshold for acceptance (ie. require 51% of oracles to have posted valid prices - if l == 0 { - // Error if there are no valid prices in the raw pricefeed - return types.ErrNoValidPrice(k.codespace) - } else if l == 1 { - // Return immediately if there's only one price - medianPrice = notExpiredPrices[0].Price - } else { - // sort the prices - sort.Slice(notExpiredPrices, func(i, j int) bool { - return notExpiredPrices[i].Price.LT(notExpiredPrices[j].Price) - }) - // If there's an even number of prices - if l%2 == 0 { - // TODO make sure this is safe. - // Since it's a price and not a balance, division with precision loss is OK. - price1 := notExpiredPrices[l/2-1].Price - price2 := notExpiredPrices[l/2].Price - sum := price1.Add(price2) - divsor, _ := sdk.NewDecFromStr("2") - medianPrice = sum.Quo(divsor) - } else { - // integer division, so we'll get an integer back, rounded down - medianPrice = notExpiredPrices[l/2].Price - } + medianPrice, err := k.CalculateMedianPrice(ctx, notExpiredPrices) + if err != nil { + return err } store := ctx.KVStore(k.storeKey) currentPrice := types.CurrentPrice{ - AssetCode: assetCode, - Price: medianPrice, + MarketID: marketID, + Price: medianPrice, } store.Set( - []byte(types.CurrentPricePrefix+assetCode), k.cdc.MustMarshalBinaryBare(currentPrice), + []byte(types.CurrentPricePrefix+marketID), k.cdc.MustMarshalBinaryBare(currentPrice), ) return nil } +// CalculateMedianPrice calculates the median prices for the input prices. +func (k Keeper) CalculateMedianPrice(ctx sdk.Context, prices []types.CurrentPrice) (sdk.Dec, sdk.Error) { + l := len(prices) + + if l == 0 { + // Error if there are no valid prices in the raw pricefeed + return sdk.Dec{}, types.ErrNoValidPrice(k.codespace) + } else if l == 1 { + // Return immediately if there's only one price + return prices[0].Price, nil + } else { + // sort the prices + sort.Slice(prices, func(i, j int) bool { + return prices[i].Price.LT(prices[j].Price) + }) + // for even numbers of prices, the median is calculated as the mean of the two middle prices + if l%2 == 0 { + median := k.calculateMeanPrice(ctx, prices[l/2-1:l/2+1]) + return median, nil + } + // for odd numbers of prices, return the middle element + return prices[l/2].Price, nil + } +} + +func (k Keeper) calculateMeanPrice(ctx sdk.Context, prices []types.CurrentPrice) sdk.Dec { + sum := prices[0].Price.Add(prices[1].Price) + mean := sum.Quo(sdk.NewDec(2)) + return mean +} + // GetCurrentPrice fetches the current median price of all oracles for a specific asset -func (k Keeper) GetCurrentPrice(ctx sdk.Context, assetCode string) types.CurrentPrice { +func (k Keeper) GetCurrentPrice(ctx sdk.Context, marketID string) types.CurrentPrice { store := ctx.KVStore(k.storeKey) - bz := store.Get([]byte(types.CurrentPricePrefix + assetCode)) + bz := store.Get([]byte(types.CurrentPricePrefix + marketID)) // TODO panic or return error if not found var price types.CurrentPrice k.cdc.MustUnmarshalBinaryBare(bz, &price) @@ -147,14 +154,15 @@ func (k Keeper) GetCurrentPrice(ctx sdk.Context, assetCode string) types.Current } // GetRawPrices fetches the set of all prices posted by oracles for an asset -func (k Keeper) GetRawPrices(ctx sdk.Context, assetCode string) []types.PostedPrice { +func (k Keeper) GetRawPrices(ctx sdk.Context, marketID string) []types.PostedPrice { store := ctx.KVStore(k.storeKey) - bz := store.Get([]byte(types.RawPriceFeedPrefix + assetCode)) + bz := store.Get([]byte(types.RawPriceFeedPrefix + marketID)) var prices []types.PostedPrice k.cdc.MustUnmarshalBinaryBare(bz, &prices) return prices } +// Codespace return the codespace for the keeper func (k Keeper) Codespace() sdk.CodespaceType { return k.codespace } diff --git a/x/pricefeed/keeper/keeper_test.go b/x/pricefeed/keeper/keeper_test.go index 1c93cb9d..105062bb 100644 --- a/x/pricefeed/keeper/keeper_test.go +++ b/x/pricefeed/keeper/keeper_test.go @@ -12,8 +12,8 @@ import ( "github.com/kava-labs/kava/x/pricefeed/types" ) -// TestKeeper_SetGetAsset tests adding assets to the pricefeed, getting assets from the store -func TestKeeper_SetGetAsset(t *testing.T) { +// TestKeeper_SetGetMarket tests adding markets to the pricefeed, getting markets from the store +func TestKeeper_SetGetMarket(t *testing.T) { helper := getMockApp(t, 0, types.GenesisState{}, nil) header := abci.Header{ Height: helper.mApp.LastBlockHeight() + 1, @@ -21,32 +21,32 @@ func TestKeeper_SetGetAsset(t *testing.T) { helper.mApp.BeginBlock(abci.RequestBeginBlock{Header: header}) ctx := helper.mApp.BaseApp.NewContext(false, header) - ap := types.Params{ - Assets: []types.Asset{ - types.Asset{AssetCode: "tstusd", BaseAsset: "tst", QuoteAsset: "usd", Oracles: types.Oracles{}, Active: true}, + mp := types.Params{ + Markets: types.Markets{ + types.Market{MarketID: "tstusd", BaseAsset: "tst", QuoteAsset: "usd", Oracles: types.Oracles{}, Active: true}, }, } - helper.keeper.SetParams(ctx, ap) - assets := helper.keeper.GetAssetParams(ctx) - require.Equal(t, len(assets), 1) - require.Equal(t, assets[0].AssetCode, "tstusd") + helper.keeper.SetParams(ctx, mp) + markets := helper.keeper.GetMarketParams(ctx) + require.Equal(t, len(markets), 1) + require.Equal(t, markets[0].MarketID, "tstusd") - _, found := helper.keeper.GetAsset(ctx, "tstusd") + _, found := helper.keeper.GetMarket(ctx, "tstusd") require.Equal(t, found, true) - ap = types.Params{ - Assets: []types.Asset{ - types.Asset{AssetCode: "tstusd", BaseAsset: "tst", QuoteAsset: "usd", Oracles: types.Oracles{}, Active: true}, - types.Asset{AssetCode: "tst2usd", BaseAsset: "tst2", QuoteAsset: "usd", Oracles: types.Oracles{}, Active: true}, + mp = types.Params{ + Markets: types.Markets{ + types.Market{MarketID: "tstusd", BaseAsset: "tst", QuoteAsset: "usd", Oracles: types.Oracles{}, Active: true}, + types.Market{MarketID: "tst2usd", BaseAsset: "tst2", QuoteAsset: "usd", Oracles: types.Oracles{}, Active: true}, }, } - helper.keeper.SetParams(ctx, ap) - assets = helper.keeper.GetAssetParams(ctx) - require.Equal(t, len(assets), 2) - require.Equal(t, assets[0].AssetCode, "tstusd") - require.Equal(t, assets[1].AssetCode, "tst2usd") + helper.keeper.SetParams(ctx, mp) + markets = helper.keeper.GetMarketParams(ctx) + require.Equal(t, len(markets), 2) + require.Equal(t, markets[0].MarketID, "tstusd") + require.Equal(t, markets[1].MarketID, "tst2usd") - _, found = helper.keeper.GetAsset(ctx, "nan") + _, found = helper.keeper.GetMarket(ctx, "nan") require.Equal(t, found, false) } @@ -58,12 +58,12 @@ func TestKeeper_GetSetPrice(t *testing.T) { Time: tmtime.Now()} helper.mApp.BeginBlock(abci.RequestBeginBlock{Header: header}) ctx := helper.mApp.BaseApp.NewContext(false, header) - ap := types.Params{ - Assets: []types.Asset{ - types.Asset{AssetCode: "tstusd", BaseAsset: "tst", QuoteAsset: "usd", Oracles: types.Oracles{}, Active: true}, + mp := types.Params{ + Markets: types.Markets{ + types.Market{MarketID: "tstusd", BaseAsset: "tst", QuoteAsset: "usd", Oracles: types.Oracles{}, Active: true}, }, } - helper.keeper.SetParams(ctx, ap) + helper.keeper.SetParams(ctx, mp) // Set price by oracle 1 _, err := helper.keeper.SetPrice( ctx, helper.addrs[0], "tstusd", @@ -103,12 +103,12 @@ func TestKeeper_GetSetCurrentPrice(t *testing.T) { Time: tmtime.Now()} helper.mApp.BeginBlock(abci.RequestBeginBlock{Header: header}) ctx := helper.mApp.BaseApp.NewContext(false, header) - ap := types.Params{ - Assets: []types.Asset{ - types.Asset{AssetCode: "tstusd", BaseAsset: "tst", QuoteAsset: "usd", Oracles: types.Oracles{}, Active: true}, + mp := types.Params{ + Markets: types.Markets{ + types.Market{MarketID: "tstusd", BaseAsset: "tst", QuoteAsset: "usd", Oracles: types.Oracles{}, Active: true}, }, } - helper.keeper.SetParams(ctx, ap) + helper.keeper.SetParams(ctx, mp) helper.keeper.SetPrice( ctx, helper.addrs[0], "tstusd", sdk.MustNewDecFromStr("0.33"), diff --git a/x/pricefeed/keeper/params.go b/x/pricefeed/keeper/params.go index 576c9398..aa64cca1 100644 --- a/x/pricefeed/keeper/params.go +++ b/x/pricefeed/keeper/params.go @@ -10,7 +10,7 @@ import ( // GetParams gets params from the store func (k Keeper) GetParams(ctx sdk.Context) types.Params { - return types.NewParams(k.GetAssetParams(ctx)) + return types.NewParams(k.GetMarketParams(ctx)) } // SetParams updates params in the store @@ -18,47 +18,47 @@ func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { k.paramstore.SetParamSet(ctx, ¶ms) } -// GetAssetParams get asset params from store -func (k Keeper) GetAssetParams(ctx sdk.Context) types.Assets { - var assets types.Assets - k.paramstore.Get(ctx, types.KeyAssets, &assets) - return assets +// GetMarketParams get asset params from store +func (k Keeper) GetMarketParams(ctx sdk.Context) types.Markets { + var markets types.Markets + k.paramstore.Get(ctx, types.KeyMarkets, &markets) + return markets } // GetOracles returns the oracles in the pricefeed store -func (k Keeper) GetOracles(ctx sdk.Context, assetCode string) (types.Oracles, error) { +func (k Keeper) GetOracles(ctx sdk.Context, marketID string) (types.Oracles, error) { - for _, a := range k.GetAssetParams(ctx) { - if assetCode == a.AssetCode { - return a.Oracles, nil + for _, m := range k.GetMarketParams(ctx) { + if marketID == m.MarketID { + return m.Oracles, nil } } - return types.Oracles{}, fmt.Errorf("asset %s not found", assetCode) + return types.Oracles{}, fmt.Errorf("asset %s not found", marketID) } // GetOracle returns the oracle from the store or an error if not found -func (k Keeper) GetOracle(ctx sdk.Context, assetCode string, address sdk.AccAddress) (types.Oracle, error) { - oracles, err := k.GetOracles(ctx, assetCode) +func (k Keeper) GetOracle(ctx sdk.Context, marketID string, address sdk.AccAddress) (types.Oracle, error) { + oracles, err := k.GetOracles(ctx, marketID) if err != nil { - return types.Oracle{}, fmt.Errorf("asset %s not found", assetCode) + return types.Oracle{}, fmt.Errorf("asset %s not found", marketID) } for _, o := range oracles { if address.Equals(o.Address) { return o, nil } } - return types.Oracle{}, fmt.Errorf("oracle %s not found for asset %s", address, assetCode) + return types.Oracle{}, fmt.Errorf("oracle %s not found for asset %s", address, marketID) } -// GetAsset returns the asset if it is in the pricefeed system -func (k Keeper) GetAsset(ctx sdk.Context, assetCode string) (types.Asset, bool) { - assets := k.GetAssetParams(ctx) +// GetMarket returns the market if it is in the pricefeed system +func (k Keeper) GetMarket(ctx sdk.Context, marketID string) (types.Market, bool) { + markets := k.GetMarketParams(ctx) - for i := range assets { - if assets[i].AssetCode == assetCode { - return assets[i], true + for i := range markets { + if markets[i].MarketID == marketID { + return markets[i], true } } - return types.Asset{}, false + return types.Market{}, false } diff --git a/x/pricefeed/keeper/querier.go b/x/pricefeed/keeper/querier.go index 245fa754..a862b776 100644 --- a/x/pricefeed/keeper/querier.go +++ b/x/pricefeed/keeper/querier.go @@ -27,12 +27,12 @@ func NewQuerier(keeper Keeper) sdk.Querier { } func queryCurrentPrice(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { - assetCode := path[0] - _, found := keeper.GetAsset(ctx, assetCode) + marketID := path[0] + _, found := keeper.GetMarket(ctx, marketID) if !found { return []byte{}, sdk.ErrUnknownRequest("asset not found") } - currentPrice := keeper.GetCurrentPrice(ctx, assetCode) + currentPrice := keeper.GetCurrentPrice(ctx, marketID) bz, err2 := codec.MarshalJSONIndent(keeper.cdc, currentPrice) if err2 != nil { @@ -44,12 +44,12 @@ func queryCurrentPrice(ctx sdk.Context, path []string, req abci.RequestQuery, ke func queryRawPrices(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { var priceList types.QueryRawPricesResp - assetCode := path[0] - _, found := keeper.GetAsset(ctx, assetCode) + marketID := path[0] + _, found := keeper.GetMarket(ctx, marketID) if !found { return []byte{}, sdk.ErrUnknownRequest("asset not found") } - rawPrices := keeper.GetRawPrices(ctx, assetCode) + rawPrices := keeper.GetRawPrices(ctx, marketID) for _, price := range rawPrices { priceList = append(priceList, price.String()) } @@ -63,7 +63,7 @@ func queryRawPrices(ctx sdk.Context, path []string, req abci.RequestQuery, keepe func queryAssets(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { var assetList types.QueryAssetsResp - assets := keeper.GetAssetParams(ctx) + assets := keeper.GetMarketParams(ctx) for _, asset := range assets { assetList = append(assetList, asset.String()) } diff --git a/x/pricefeed/types/asset.go b/x/pricefeed/types/asset.go index 83ba1c0b..bc19b532 100644 --- a/x/pricefeed/types/asset.go +++ b/x/pricefeed/types/asset.go @@ -8,34 +8,34 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// Asset struct that represents an asset in the pricefeed -type Asset struct { - AssetCode string `json:"asset_code" yaml:"asset_code"` +// Market struct that represents an asset in the pricefeed +type Market struct { + MarketID string `json:"market_id" yaml:"market_id"` BaseAsset string `json:"base_asset" yaml:"base_asset"` QuoteAsset string `json:"quote_asset" yaml:"quote_asset"` Oracles Oracles `json:"oracles" yaml:"oracles"` Active bool `json:"active" yaml:"active"` } -// implement fmt.Stringer -func (a Asset) String() string { +// String implement fmt.Stringer +func (a Market) String() string { return fmt.Sprintf(`Asset: - Asset Code: %s + Market ID: %s Base Asset: %s Quote Asset: %s Oracles: %s Active: %t`, - a.AssetCode, a.BaseAsset, a.QuoteAsset, a.Oracles, a.Active) + a.MarketID, a.BaseAsset, a.QuoteAsset, a.Oracles, a.Active) } -// Assets array type for oracle -type Assets []Asset +// Markets array type for oracle +type Markets []Market // String implements fmt.Stringer -func (as Assets) String() string { - out := "Assets:\n" - for _, a := range as { - out += fmt.Sprintf("%s\n", a.String()) +func (ms Markets) String() string { + out := "Markets:\n" + for _, m := range ms { + out += fmt.Sprintf("%s\n", m.String()) } return strings.TrimSpace(out) } @@ -64,13 +64,13 @@ func (os Oracles) String() string { // CurrentPrice struct that contains the metadata of a current price for a particular asset in the pricefeed module. type CurrentPrice struct { - AssetCode string `json:"asset_code" yaml:"asset_code"` - Price sdk.Dec `json:"price" yaml:"price"` + MarketID string `json:"market_id" yaml:"market_id"` + Price sdk.Dec `json:"price" yaml:"price"` } // PostedPrice struct represented a price for an asset posted by a specific oracle type PostedPrice struct { - AssetCode string `json:"asset_code" yaml:"asset_code"` + MarketID string `json:"market_id" yaml:"market_id"` OracleAddress sdk.AccAddress `json:"oracle_address" yaml:"oracle_address"` Price sdk.Dec `json:"price" yaml:"price"` Expiry time.Time `json:"expiry" yaml:"expiry"` @@ -78,16 +78,16 @@ type PostedPrice struct { // implement fmt.Stringer func (cp CurrentPrice) String() string { - return strings.TrimSpace(fmt.Sprintf(`AssetCode: %s -Price: %s`, cp.AssetCode, cp.Price)) + return strings.TrimSpace(fmt.Sprintf(`Market ID: %s +Price: %s`, cp.MarketID, cp.Price)) } // implement fmt.Stringer func (pp PostedPrice) String() string { - return strings.TrimSpace(fmt.Sprintf(`AssetCode: %s -OracleAddress: %s + return strings.TrimSpace(fmt.Sprintf(`Market ID: %s +Oracle Address: %s Price: %s -Expiry: %s`, pp.AssetCode, pp.OracleAddress, pp.Price, pp.Expiry)) +Expiry: %s`, pp.MarketID, pp.OracleAddress, pp.Price, pp.Expiry)) } // SortDecs provides the interface needed to sort sdk.Dec slices diff --git a/x/pricefeed/types/events.go b/x/pricefeed/types/events.go new file mode 100644 index 00000000..0bf5fa51 --- /dev/null +++ b/x/pricefeed/types/events.go @@ -0,0 +1,8 @@ +package types + +// Pricefeed module event types +const ( + EventTypeNoValidPrices = "no_valid_prices" + + AttributeKeyPriceUpdateFailed = "price_update_failed" +) diff --git a/x/pricefeed/types/params.go b/x/pricefeed/types/params.go index 49d68716..fdef14d3 100644 --- a/x/pricefeed/types/params.go +++ b/x/pricefeed/types/params.go @@ -9,8 +9,8 @@ import ( ) var ( - // KeyAssets store key for assets - KeyAssets = []byte("assets") + // KeyMarkets store key for markets + KeyMarkets = []byte("Markets") ) // ParamKeyTable Key declaration for parameters @@ -20,33 +20,33 @@ func ParamKeyTable() params.KeyTable { // Params params for pricefeed. Can be altered via governance type Params struct { - Assets []Asset `json:"assets" yaml:"assets"` // Array containing the assets supported by the pricefeed + Markets Markets `json:"markets" yaml:"markets"` // Array containing the markets supported by the pricefeed } // ParamSetPairs implements the ParamSet interface and returns all the key/value pairs // pairs of pricefeed module's parameters. func (p Params) ParamSetPairs() params.ParamSetPairs { return params.ParamSetPairs{ - {Key: KeyAssets, Value: &p.Assets}, + {Key: KeyMarkets, Value: &p.Markets}, } } // NewParams creates a new AssetParams object -func NewParams(assets []Asset) Params { +func NewParams(markets Markets) Params { return Params{ - Assets: assets, + Markets: markets, } } // DefaultParams default params for pricefeed func DefaultParams() Params { - return NewParams(Assets{}) + return NewParams(Markets{}) } // String implements fmt.stringer func (p Params) String() string { out := "Params:\n" - for _, a := range p.Assets { + for _, a := range p.Markets { out += a.String() } return strings.TrimSpace(out) @@ -61,9 +61,9 @@ type ParamSubspace interface { // Validate ensure that params have valid values func (p Params) Validate() error { // iterate over assets and verify them - for _, asset := range p.Assets { - if asset.AssetCode == "" { - return fmt.Errorf("invalid asset: %s. missing asset code", asset.String()) + for _, asset := range p.Markets { + if asset.MarketID == "" { + return fmt.Errorf("invalid market: %s. missing market ID", asset.String()) } } return nil