From fc0ee227a42cf076d105880c7e0a884c962c3fba Mon Sep 17 00:00:00 2001 From: Cosmic Vagabond <121588426+cosmic-vagabond@users.noreply.github.com> Date: Fri, 7 Jun 2024 07:24:27 +0200 Subject: [PATCH] docs: add oracle specs (#553) --- x/oracle/spec/01_concepts.md | 7 + x/oracle/spec/02_usage.md | 68 +++ x/oracle/spec/03_keeper.md | 203 +++++++++ x/oracle/spec/04_protobuf_definitions.md | 506 +++++++++++++++++++++++ x/oracle/spec/05_functions.md | 117 ++++++ x/oracle/spec/README.md | 29 ++ 6 files changed, 930 insertions(+) create mode 100644 x/oracle/spec/01_concepts.md create mode 100644 x/oracle/spec/02_usage.md create mode 100644 x/oracle/spec/03_keeper.md create mode 100644 x/oracle/spec/04_protobuf_definitions.md create mode 100644 x/oracle/spec/05_functions.md create mode 100644 x/oracle/spec/README.md diff --git a/x/oracle/spec/01_concepts.md b/x/oracle/spec/01_concepts.md new file mode 100644 index 000000000..cc990ce91 --- /dev/null +++ b/x/oracle/spec/01_concepts.md @@ -0,0 +1,7 @@ + + +# Concepts + +The `oracle` module in the Elys Network provides decentralized price feeds and asset information. It facilitates querying and setting asset prices from different sources such as Band and Elys, maintaining the integrity and availability of price data within the network. This module enhances the efficiency and reliability of price-related operations across the network. diff --git a/x/oracle/spec/02_usage.md b/x/oracle/spec/02_usage.md new file mode 100644 index 000000000..c55a10bc7 --- /dev/null +++ b/x/oracle/spec/02_usage.md @@ -0,0 +1,68 @@ + + +# Usage + +## Commands + +### Querying Parameters and Band Price Results + +```bash +elysd query oracle params +elysd query oracle band-price-result [request_id] +elysd query oracle last-band-request-id +``` + +### Querying Asset Info + +```bash +elysd query oracle list-asset-info +elysd query oracle show-asset-info [denom] +``` + +### Querying Prices + +```bash +elysd query oracle list-price +elysd query oracle show-price [asset] --source="[source]" --timestamp=[timestamp] +elysd query oracle show-price [asset] --source="[source]" +elysd query oracle show-price [asset] +``` + +### Managing Price Feeders + +```bash +elysd query oracle list-price-feeder +elysd query oracle show-price-feeder [feeder_address] + +elysd tx oracle set-price-feeder [feeder_address] [is_active] --from=[key] --chain-id=[chain-id] --broadcast-mode=block --yes +elysd tx oracle delete-price-feeder [feeder_address] --from=[key] --chain-id=[chain-id] --broadcast-mode=block --yes +``` + +### Feeding Prices + +```bash +elysd tx oracle feed-price [asset] [price] [source] --from=[provider] --chain-id=[chain-id] --broadcast-mode=block --yes +elysd tx oracle feed-multiple-prices [prices-json] --from=[creator] --chain-id=[chain-id] --broadcast-mode=block --yes +``` + +### Managing Asset Info + +```bash +elysd tx oracle add-asset-info-proposal [denom] [display] [band_ticker] [elys_ticker] [decimal] --title="[title]" --description="[description]" --deposit="[deposit_amount]" --from=[authority] --chain-id=[chain-id] --broadcast-mode=block --yes +elysd tx oracle remove-asset-info-proposal [denom] --title="[title]" --description="[description]" --deposit="[deposit_amount]" --from=[authority] --chain-id=[chain-id] --broadcast-mode=block --yes +``` + +### Submitting Governance Proposals + +```bash +elysd query gov proposals +elysd tx gov vote [proposal_id] yes --from=[voter] --chain-id=[chain-id] --broadcast-mode=block --yes +``` + +### Requesting Band Price + +```bash +elysd tx oracle request-band-price --from=[key] --chain-id=[chain-id] --broadcast-mode=block --yes +``` diff --git a/x/oracle/spec/03_keeper.md b/x/oracle/spec/03_keeper.md new file mode 100644 index 000000000..844a6b839 --- /dev/null +++ b/x/oracle/spec/03_keeper.md @@ -0,0 +1,203 @@ + + +# Keeper + +## Price Management + +The `oracle` module's keeper handles the management and querying of asset prices and related information. It ensures the timely update and retrieval of price data and manages the lifecycle of price feeders. + +### EndBlocker + +The `EndBlocker` function is invoked at the end of each block. It is responsible for removing outdated prices based on the configured expiration parameters. + +```go +func (k Keeper) EndBlock(ctx sdk.Context) { + params := k.GetParams(ctx) + for _, price := range k.GetAllPrice(ctx) { + if price.Timestamp + params.PriceExpiryTime < uint64(ctx.BlockTime().Unix()) { + k.RemovePrice(ctx, price.Asset, price.Source, price.Timestamp) + } + if price.BlockHeight + params.LifeTimeInBlocks < uint64(ctx.BlockHeight()) { + k.RemovePrice(ctx, price.Asset, price.Source, price.Timestamp) + } + } +} +``` + +### Managing Asset Info + +The `SetAssetInfo`, `GetAssetInfo`, `RemoveAssetInfo`, and `GetAllAssetInfo` functions handle the creation, retrieval, deletion, and listing of asset information. + +```go +func (k Keeper) SetAssetInfo(ctx sdk.Context, assetInfo types.AssetInfo) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.AssetInfoKeyPrefix)) + bz := k.cdc.MustMarshal(&assetInfo) + store.Set(types.AssetInfoKey(assetInfo.Denom), bz) +} + +func (k Keeper) GetAssetInfo(ctx sdk.Context, denom string) (val types.AssetInfo, found bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.AssetInfoKeyPrefix)) + bz := store.Get(types.AssetInfoKey(denom)) + if bz == nil { + return val, false + } + k.cdc.MustUnmarshal(bz, &val) + return val, true +} + +func (k Keeper) RemoveAssetInfo(ctx sdk.Context, denom string) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.AssetInfoKeyPrefix)) + store.Delete(types.AssetInfoKey(denom)) +} + +func (k Keeper) GetAllAssetInfo(ctx sdk.Context) (list []types.AssetInfo) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.AssetInfoKeyPrefix)) + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var val types.AssetInfo + k.cdc.MustUnmarshal(iterator.Value(), &val) + list = append(list, val) + } + return +} +``` + +### Managing Band Price Results + +The `SetBandPriceResult`, `GetBandPriceResult`, `GetLastBandRequestId`, and `SetLastBandRequestId` functions manage the storage and retrieval of price data from Band protocol. + +```go +func (k Keeper) SetBandPriceResult(ctx sdk.Context, requestID types.OracleRequestID, result types.BandPriceResult) { + store := ctx.KVStore(k.storeKey) + store.Set(types.BandPriceResultStoreKey(requestID), k.cdc.MustMarshal(&result)) +} + +func (k Keeper) GetBandPriceResult(ctx sdk.Context, id types.OracleRequestID) (types.BandPriceResult, error) { + bz := ctx.KVStore(k.storeKey).Get(types.BandPriceResultStoreKey(id)) + if bz == nil { + return types.BandPriceResult{}, errorsmod.Wrapf(types.ErrNotAvailable, "Result for request ID %d is not available.", id) + } + var result types.BandPriceResult + k.cdc.MustUnmarshal(bz, &result) + return result, nil +} + +func (k Keeper) GetLastBandRequestId(ctx sdk.Context) int64 { + bz := ctx.KVStore(k.storeKey).Get(types.KeyPrefix(types.LastBandRequestIdKey)) + intV := gogotypes.Int64Value{} + k.cdc.MustUnmarshalLengthPrefixed(bz, &intV) + return intV.GetValue() +} + +func (k Keeper) SetLastBandRequestId(ctx sdk.Context, id types.OracleRequestID) { + store := ctx.KVStore(k.storeKey) + store.Set(types.KeyPrefix(types.LastBandRequestIdKey), k.cdc.MustMarshalLengthPrefixed(&gogotypes.Int64Value{Value: int64(id)})) +} +``` + +### Managing Prices + +The `SetPrice`, `GetPrice`, `GetLatestPriceFromAssetAndSource`, `GetLatestPriceFromAnySource`, `RemovePrice`, and `GetAllPrice` functions manage the lifecycle and retrieval of price data. + +```go +func (k Keeper) SetPrice(ctx sdk.Context, price types.Price) { + store := ctx.KVStore(k.storeKey) + b := k.cdc.MustMarshal(&price) + store.Set(types.PriceKey(price.Asset, price.Source, price.Timestamp), b) +} + +func (k Keeper) GetPrice(ctx sdk.Context, asset, source string, timestamp uint64) (val types.Price, found bool) { + store := ctx.KVStore(k.storeKey) + b := store.Get(types.PriceKey(asset, source, timestamp)) + if b == nil { + return val, false + } + k.cdc.MustUnmarshal(b, &val) + return val, true +} + +func (k Keeper) GetLatestPriceFromAssetAndSource(ctx sdk.Context, asset, source string) (val types.Price, found bool) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStoreReversePrefixIterator(store, types.PriceKeyPrefixAssetAndSource(asset, source)) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var val types.Price + k.cdc.MustUnmarshal(iterator.Value(), &val) + return val, true + } + return val, false +} + +func (k Keeper) GetLatestPriceFromAnySource(ctx sdk.Context, asset string) (val types.Price, found bool) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStoreReversePrefixIterator(store, types.PriceKeyPrefixAsset(asset)) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var val types.Price + k.cdc.MustUnmarshal(iterator.Value(), &val) + return val, true + } + return val, false +} + +func (k Keeper) RemovePrice(ctx sdk.Context, asset, source string, timestamp uint64) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.PriceKey(asset, source, timestamp)) +} + +func (k Keeper) GetAllPrice(ctx sdk.Context) (list []types.Price) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.PriceKeyPrefix)) + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var val types.Price + k.cdc.MustUnmarshal(iterator.Value(), &val) + list = append(list, val) + } + return +} +``` + +### Managing Price Feeders + +The `SetPriceFeeder`, `GetPriceFeeder`, `RemovePriceFeeder`, and `GetAllPriceFeeder` functions manage the lifecycle and retrieval of price feeder data. + +```go +func (k Keeper) SetPriceFeeder(ctx sdk.Context, priceFeeder types.PriceFeeder) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.PriceFeederKeyPrefix)) + b := k.cdc.MustMarshal(&priceFeeder) + store.Set(types.PriceFeederKey(priceFeeder.Feeder), b) +} + +func ( + +k Keeper) GetPriceFeeder(ctx sdk.Context, feeder string) (val types.PriceFeeder, found bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.PriceFeederKeyPrefix)) + b := store.Get(types.PriceFeederKey(feeder)) + if b == nil { + return val, false + } + k.cdc.MustUnmarshal(b, &val) + return val, true +} + +func (k Keeper) RemovePriceFeeder(ctx sdk.Context, feeder string) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.PriceFeederKeyPrefix)) + store.Delete(types.PriceFeederKey(feeder)) +} + +func (k Keeper) GetAllPriceFeeder(ctx sdk.Context) (list []types.PriceFeeder) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.PriceFeederKeyPrefix)) + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var val types.PriceFeeder + k.cdc.MustUnmarshal(iterator.Value(), &val) + list = append(list, val) + } + return +} +``` diff --git a/x/oracle/spec/04_protobuf_definitions.md b/x/oracle/spec/04_protobuf_definitions.md new file mode 100644 index 000000000..fce9506ab --- /dev/null +++ b/x/oracle/spec/04_protobuf_definitions.md @@ -0,0 +1,506 @@ + + +# Types, Messages, Queries, and States + +## Types + +### AssetInfo + +The `AssetInfo` message contains information about an asset, including its denomination, display name, Band ticker, Elys ticker, and decimal precision. + +```proto +message AssetInfo { + string denom = 1; + string display = 2; + string band_ticker = 3; + string elys_ticker = 4; + uint64 decimal = 5; +} +``` + +### BandPriceCallData + +The `BandPriceCallData` message contains the symbols to query and the multiplier used in Band price queries. + +```proto +message BandPriceCallData { + repeated string symbols = 1; + uint64 multiplier = 2; +} +``` + +### BandPriceResult + +The `BandPriceResult` message contains the results of a Band price query. + +```proto +message BandPriceResult { + repeated uint64 rates = 1; +} +``` + +### Params + +The `Params` message defines the parameters for the `oracle` module, including settings for Band channel source, Oracle script ID, multiplier, ask count, minimum count, fee limit, gas parameters, client ID, band epoch, price expiry time, and lifetime in blocks. + +```proto +message Params { + option (gogoproto.goproto_stringer) = false; + + string band_channel_source = 1; + uint64 oracle_script_id = 2 [ + (gogoproto.customname) = "OracleScriptID" + ]; + uint64 multiplier = 3; + uint64 ask_count = 4; + uint64 min_count = 5; + repeated cosmos.base.v1beta1.Coin fee_limit = 6 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; + uint64 prepare_gas = 7; + uint64 execute_gas = 8; + string client_id = 9 [ + (gogoproto.customname) = "ClientID" + ]; + string band_epoch = 10; + uint64 price_expiry_time = 11; + uint64 life_time_in_blocks = 12; +} +``` + +### Price + +The `Price` message contains price data for an asset, including the asset identifier, price value, source, provider, timestamp, and block height. + +```proto +message Price { + string asset = 1; + string price = 2 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + string source = 3; + string provider = 4; + uint64 timestamp = 5; + uint64 block_height = 6; +} +``` + +### PriceFeeder + +The `PriceFeeder` message contains information about a price feeder, including the feeder identifier and whether it is active. + +```proto +message PriceFeeder { + string feeder = 1; + bool is_active = 2; +} +``` + +### GenesisState + +The `GenesisState` message defines the initial state of the `oracle` module at genesis. + +```proto +message GenesisState { + Params params = 1 [ + (gogoproto.nullable) = false + ]; + string port_id = 2; + repeated AssetInfo asset_infos = 3 [ + (gogoproto.nullable) = false + ]; + repeated Price prices = 4 [ + (gogoproto.nullable) = false + ]; + repeated PriceFeeder price_feeders = 5 [ + (gogoproto.nullable) = false + ]; +} +``` + +## Messages + +### Msg Service + +The `Msg` service defines the transactions available in the `oracle` module. + +```proto +service Msg { + rpc FeedPrice(MsgFeedPrice) returns (MsgFeedPriceResponse); + rpc FeedMultiplePrices(MsgFeedMultiplePrices) returns (MsgFeedMultiplePricesResponse); + rpc SetPriceFeeder(MsgSetPriceFeeder) returns (MsgSetPriceFeederResponse); + rpc DeletePriceFeeder(MsgDeletePriceFeeder) returns (MsgDeletePriceFeederResponse); + // proposals + rpc AddAssetInfo(MsgAddAssetInfo) returns (MsgAddAssetInfoResponse); + rpc RemoveAssetInfo(MsgRemoveAssetInfo) returns (MsgRemoveAssetInfoResponse); + rpc AddPriceFeeders(MsgAddPriceFeeders) returns (MsgAddPriceFeedersResponse); + rpc RemovePriceFeeders(MsgRemovePriceFeeders) returns (MsgRemovePriceFeedersResponse); + rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); +} +``` + +#### MsgFeedPrice + +This message allows a price feeder to submit a price for an asset. + +```proto +message MsgFeedPrice { + string asset = 1; + string price = 2 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + string source = 3; + string provider = 4; +} + +message MsgFeedPriceResponse {} +``` + +#### MsgFeedMultiplePrices + +This message allows a price feeder to submit multiple prices at once. + +```proto +message MsgFeedMultiplePrices { + string creator = 1; + repeated Price prices = 2 [ + (gogoproto.nullable) = false + ]; +} + +message MsgFeedMultiplePricesResponse {} +``` + +#### MsgSetPriceFeeder + +This message allows the authority to set the status of a price feeder. + +```proto +message MsgSetPriceFeeder { + string feeder = 1; + bool is_active = 2; +} + +message MsgSetPriceFeederResponse {} +``` + +#### MsgDeletePriceFeeder + +This message allows the authority to delete a price feeder. + +```proto +message MsgDeletePriceFeeder { + string feeder = 1; +} + +message MsgDeletePriceFeederResponse {} +``` + +#### MsgAddAssetInfo + +This message allows the authority to add information about an asset. + +```proto +message MsgAddAssetInfo { + string authority = 1; + string denom = 2; + string display = 3; + string band_ticker = 4; + string elys_ticker = 5; + uint64 decimal = 6; +} + +message MsgAddAssetInfoResponse {} +``` + +#### MsgRemoveAssetInfo + +This message allows the authority to remove information about an asset. + +```proto +message MsgRemoveAssetInfo { + string authority = 1; + string denom = 2; +} + +message MsgRemoveAssetInfoResponse {} +``` + +#### MsgAddPriceFeeders + +This message allows the authority to add multiple price feeders. + +```proto +message MsgAddPriceFeeders { + string authority = 1; + repeated string feeders = 2; +} + +message MsgAddPriceFeedersResponse {} +``` + +#### MsgRemovePriceFeeders + +This message allows the authority to remove multiple price feeders. + +```proto +message MsgRemovePriceFeeders { + string authority = 1; + repeated string feeders = 2; +} + +message MsgRemovePriceFeedersResponse {} +``` + +#### MsgUpdateParams + +This message allows the authority to update the parameters of the `oracle` module. + +```proto +message MsgUpdateParams { + string authority = 1; + Params params = 2 [ + (gogoproto.nullable) = false + ]; +} + +message MsgUpdateParamsResponse {} +``` + +## Queries + +### Query Service + +The `Query` service defines the gRPC querier service for the `oracle` module. + +```proto +service Query { + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/elys-network/elys/oracle/params"; + } + rpc BandPriceResult(QueryBandPriceRequest) returns (QueryBandPriceResponse) { + option (google.api.http).get = "/elys/oracle/band_price_result/{request_id}"; + } + rpc LastBandRequestId(QueryLastBandRequestIdRequest) returns (QueryLastBandRequestIdResponse) { + option (google.api.http).get = "/elys/oracle/last_band_price_request_id"; + } + rpc AssetInfo(QueryGetAssetInfoRequest) returns (QueryGetAssetInfoResponse) { + option (google.api.http).get = "/elys-network/elys/oracle/asset_info/{denom}"; + } + rpc AssetInfoAll(QueryAllAssetInfoRequest) returns (QueryAllAssetInfoResponse) { + option (google.api.http).get = "/elys-network/elys/oracle/asset_info"; + } + rpc Price(QueryGetPriceRequest) returns (QueryGetPriceResponse) { + option (google.api.http).get = "/elys-network/elys/oracle/price"; + } + rpc PriceAll(QueryAllPriceRequest) returns (QueryAllPriceResponse) { + option (google.api.http).get = "/elys-network/elys/oracle/price"; + } + rpc PriceFeeder(QueryGetPriceFeederRequest) returns (QueryGetPriceFeederResponse) { + option (google.api.http).get = "/elys-network/elys/oracle/price_feeder/{feeder}"; + } + rpc PriceFeederAll(QueryAllPriceFeederRequest) returns (QueryAllPriceFeederResponse) { + option (google.api.http).get = "/elys-network/elys/oracle/price_feeder"; + } +} +``` + +#### QueryParamsRequest + +This message requests the parameters of the `oracle` module. + +```proto +message QueryParamsRequest {} +``` + +#### QueryParamsResponse + +This message responds with the parameters of the `oracle` module. + +```proto +message QueryParamsResponse { + Params params = 1 [ + (gogoproto.nullable) = false + ]; +} +``` + +#### QueryBandPriceRequest + +This message requests the Band price result for a given request ID. + +```proto +message QueryBandPriceRequest { + int64 request_id = 1; +} +``` + +#### QueryBandPriceResponse + +This message responds with the Band price result for a given request ID. + +```proto +message QueryBandPriceResponse { + BandPriceResult result = 1; +} +``` + +#### QueryLastBandRequestIdRequest + +This message requests the last Band price request ID. + +```proto +message QueryLastBandRequestIdRequest {} +``` + +#### QueryLastBandRequestIdResponse + +This message responds with the last Band price request ID. + +```proto +message QueryLastBandRequestIdResponse { + int64 request_id = 1; +} +``` + +#### QueryGetAssetInfoRequest + +This message requests the information of an asset by its denomination. + +```proto +message QueryGetAssetInfoRequest { + string denom = 1; +} +``` + +#### QueryGetAssetInfoResponse + +This message responds with the information of an asset by its denomination. + +```proto +message QueryGetAssetInfoResponse { + AssetInfo asset_info = 1 [ + (gogoproto.nullable) = false + ]; +} +``` + +#### QueryAllAssetInfoRequest + +This message requests the list of all asset information with pagination support. + +```proto +message QueryAllAssetInfoRequest { + cosmos.base.query.v1beta1.PageRequest pagination = 1; +} +``` + +#### QueryAllAssetInfoResponse + +This message responds with the list of all asset information and pagination details. + +```proto +message QueryAllAssetInfoResponse { + repeated AssetInfo asset_info = 1 [ + (gogoproto.nullable) = false + ]; + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} +``` + +#### QueryGetPriceRequest + +This message requests the price of an asset, optionally specifying the source and timestamp. + +```proto +message QueryGetPriceRequest { + string asset = 1; + string source = 2; + uint64 timestamp = 3; +} +``` + +#### QueryGetPriceResponse + +This message responds with the price of an asset. + +```proto +message QueryGetPriceResponse { + Price price = 1 [ + (gogoproto.nullable) = false + ]; +} +``` + +#### QueryAllPriceRequest + +This message requests the list of all prices with pagination support. + +```proto +message QueryAllPriceRequest { + cosmos.base.query.v1beta1.PageRequest pagination = 1; +} +``` + +#### QueryAllPriceResponse + +This message responds with the list of all prices and pagination details. + +```proto +message QueryAllPriceResponse { + repeated Price price = 1 [ + (gogoproto.nullable) = false + ]; + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} +``` + +#### QueryGetPriceFeederRequest + +This message requests the information of a price feeder by its identifier. + +```proto +message QueryGetPriceFeederRequest { + string feeder = 1; +} +``` + +#### QueryGetPriceFeederResponse + +This message responds with the information of a price feeder by its identifier. + +```proto +message QueryGetPriceFeederResponse { + PriceFeeder price_feeder = 1 [ + (gogoproto.nullable) = false + ]; +} +``` + +#### QueryAllPriceFeederRequest + +This message requests the list of all price feeders with pagination support. + +```proto +message QueryAllPriceFeederRequest { + cosmos.base.query.v1beta1.PageRequest pagination = 1; +} +``` + +#### QueryAllPriceFeederResponse + +This message responds with the list of all price feeders and pagination details. + +```proto +message QueryAllPriceFeederResponse { + repeated PriceFeeder price_feeder = 1 [ + (gogoproto.nullable) = false + ]; + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} +``` diff --git a/x/oracle/spec/05_functions.md b/x/oracle/spec/05_functions.md new file mode 100644 index 000000000..59efd71a4 --- /dev/null +++ b/x/oracle/spec/05_functions.md @@ -0,0 +1,117 @@ + + +# Functions + +## EndBlocker + +The `EndBlocker` function is called at the end of each block to perform necessary updates and maintenance for the `oracle` module. It processes the removal of outdated prices. + +```go +func (k Keeper) EndBlock(ctx sdk.Context) { + params := k.GetParams(ctx) + for _, price := range k.GetAllPrice(ctx) { + if price.Timestamp + params.PriceExpiryTime < uint64(ctx.BlockTime().Unix()) { + k.RemovePrice(ctx, price.Asset, price.Source, price.Timestamp) + } + if price.BlockHeight + params.LifeTimeInBlocks < uint64(ctx.BlockHeight()) { + k.RemovePrice(ctx, price.Asset, price.Source, price.Timestamp) + } + } +} +``` + +### FeedPrice + +The `FeedPrice` function is responsible for submitting a price for an asset. + +```go +func (k msgServer) FeedPrice(goCtx context.Context, msg *types.MsgFeedPrice) (*types.MsgFeedPriceResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + feeder, found := k.Keeper.GetPriceFeeder(ctx, msg.Provider) + if !found { + return nil, types.ErrNotAPriceFeeder + } + + if !feeder.IsActive { + return nil, types.ErrPriceFeederNotActive + } + + price := types.Price{ + Provider: msg.Provider, + Asset: msg.Asset, + Price: msg.Price, + Source: msg.Source, + Timestamp: uint64(ctx.BlockTime().Unix()), + BlockHeight: uint64(ctx.BlockHeight()), + } + + k.SetPrice(ctx, price) + return &types.MsgFeedPriceResponse{}, nil +} +``` + +### SetPriceFeeder + +The `SetPriceFeeder` function sets the status of a price feeder. + +```go +func (k msgServer) SetPriceFeeder(goCtx context.Context, msg *types.MsgSetPriceFeeder) (*types.MsgSetPriceFeederResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + _, found := k.Keeper.GetPriceFeeder(ctx, msg.Feeder) + if !found { + return nil, types.ErrNotAPriceFeeder + } + k.Keeper.SetPriceFeeder(ctx, types.PriceFeeder{ + Feeder: msg.Feeder, + IsActive: msg.IsActive, + }) + return &types.MsgSetPriceFeederResponse{}, nil +} +``` + +### RemovePriceFeeder + +The `RemovePriceFeeder` function removes a price feeder. + +```go +func (k msgServer) DeletePriceFeeder(goCtx context.Context, msg *types.MsgDeletePriceFeeder) (*types.MsgDeletePriceFeederResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + _, found := k.Keeper.GetPriceFeeder(ctx, msg.Feeder) + if !found { + return nil, types.ErrNotAPriceFeeder + } + k.RemovePriceFeeder(ctx, msg.Feeder) + return &types.MsgDeletePriceFeederResponse{}, nil +} +``` + +### FeedMultiplePrices + +The `FeedMultiplePrices` function allows a price feeder to submit multiple prices at once. + +```go +func (k msgServer) FeedMultiplePrices(goCtx context.Context, msg *types.MsgFeedMultiplePrices) (*types.MsgFeedMultiplePricesResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + feeder, found := k.Keeper.GetPriceFeeder(ctx, msg.Creator) + if !found { + return nil, types.ErrNotAPriceFeeder + } + + if !feeder.IsActive { + return nil, types.ErrPriceFeederNotActive + } + + for _, price := range msg.Prices { + price.Provider = msg.Creator + price.Timestamp = uint64(ctx.BlockTime().Unix()) + price.BlockHeight = uint64(ctx.BlockHeight()) + k.SetPrice(ctx, price) + } + + return &types.MsgFeedMultiplePricesResponse{}, nil +} +``` diff --git a/x/oracle/spec/README.md b/x/oracle/spec/README.md new file mode 100644 index 000000000..60df69c07 --- /dev/null +++ b/x/oracle/spec/README.md @@ -0,0 +1,29 @@ +# Elys Oracle Module + +## Contents + +1. **[Concepts](01_concepts.md)** +2. **[Usage](02_usage.md)** +3. **[Keeper](03_keeper.md)** +4. **[Protobuf Definitions](04_protobuf_definitions.md)** +5. **[Functions](05_functions.md)** + +## References + +Resources: + +- [Elys Network Documentation](https://docs.elys.network) +- [Cosmos SDK Documentation](https://docs.cosmos.network) +- [GitHub Repository for Elys Network](https://github.com/elys-network/elys) + +## Overview + +The `oracle` module in the Elys Network is designed to provide decentralized price feeds and manage asset information efficiently. It supports querying and setting asset prices from various sources like Band and Elys, ensuring reliable and accurate price data across the network. + +## Key Features + +- **Decentralized Price Feeds**: Manage and query prices from multiple sources. +- **Asset Information Management**: Store and retrieve detailed asset information. +- **Price Feeder Management**: Add, remove, and set status for price feeders. + +For more detailed information, please refer to the individual sections listed in the contents above.