Oracle
The Oracle module brings up price feeds and exchange rates to Kiichain.
It allows validators to submit price data, which can be used by other modules or smart contracts (EVM and Wasm).
It supports multiple price feeds, allowing for a diverse set of data sources
It provides a mechanism for price data to be aggregated and made available on-chain
Price feeder
Our official implementation for the price feeder is available at Kiichain Price Feeder.
The price must be ran by a validator or a delegated address
The price feeder is responsible for submitting the price data to the Oracle module
More information can be found at the project readme
Core functionality
The Oracle module works as follows:
Validators submit price data for arbitrary assets, which are defined in the module params
The module aggregates the price data submitted by validators and calculates a final exchange rate for each asset
The final exchange rate is stored on-chain and can be queried by other modules or smart contracts
The Exchange Vote is done as following:
A new block is created
Validators submit their votes for the price of each asset in the whitelist through the
MsgExchangeRateVote
message
This message is feeless as long as its the first vote for the validator in the current voting period
The vote can be submitted by the validator itself or a delegated address (feeder address)
By using a delegated address, validators can separate their voting actions from their staking address
The module aggregates the votes and calculates the final exchange rate for each asset
If no vote is submitted by a validator in the current voting period, the module will slash the validator's stake according to the
slash_fraction
parameterThe final exchange rate is stored on-chain and can be queried by other modules or smart contracts
State
These are the most important state types used by the Oracle module:
Params
Params stores the module wide configuration. Its defined as:
// Params defines the parameters for the module
message Params {
option (gogoproto.equal) = true;
option (gogoproto.goproto_stringer) = false; // Allow custom logs
// The number of blocks per voting
uint64 vote_period =1 [(gogoproto.moretags) = "yaml:\"vote_period\""];
// Minimum percentage of validators required to approve a price. For instance, if vote_threshold = "0.5" at least 50% of validators must submit votes
// "cosmossdk.io/math.LegacyDec" = Cosmos SDK decimal data type
string vote_threshold = 2 [
(gogoproto.moretags) = "yaml:\"vote_threshold\"",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];
// Acceptable deviation from the media price (higher and lower)
// "cosmossdk.io/math.LegacyDec" = Cosmos SDK decimal data type
string reward_band = 3 [
(gogoproto.moretags) = "yaml:\"reward_band\"",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];
// List of allowed assets
// DenomList is a custom data type, defined on x/oracle/types/denom.go
repeated Denom whitelist = 4 [
(gogoproto.moretags) = "yaml:\"whitelist\"",
(gogoproto.castrepeated) = "DenomList",
(gogoproto.nullable) = false
];
// How much stake is slashed if a validator fails to submit votes
// "cosmossdk.io/math.LegacyDec" = Cosmos SDK decimal data type
string slash_fraction = 5 [
(gogoproto.moretags) = "yaml:\"slash_fraction\"",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];
// Define the window (in blocks) to vote, if not receive penalties due to bad performance
uint64 slash_window = 6 [(gogoproto.moretags) = "yaml:\"slash_window\""];
// Minimum percentage of voting on windows to avoid slashing. For instance, if min_valid_per_window = 0.8, then a validator must submit votes in 80% of windows to avoid slashing
// "cosmossdk.io/math.LegacyDec" = Cosmos SDK decimal data type
string min_valid_per_window = 7 [
(gogoproto.moretags) = "yaml:\"min_valid_per_window\"",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];
// How far back (in blocks) the module can compute historical price metrics
uint64 lookback_duration = 9 [(gogoproto.moretags) = "yaml:\"lookback_duration\""];
}
Exchange Rates
Exchange rates are the single entry for a price data on the chain. Its stored as a Key-Value pair in the store, where the key is the asset denom and the value is the price data.
The price data is defined as:
// Data type that stores the final calculated exchange rate after all votes were
// aggregated to that single exchange, record the last block height and timestamp when rate was updated
message OracleExchangeRate {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
option (gogoproto.goproto_stringer) = false;
string exchange_rate = 1 [
(gogoproto.moretags) = "yaml:\"exchange_rate\"",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];
string last_update = 2 [
(gogoproto.moretags) = "yaml:\"last_update\"",
(gogoproto.customtype) = "cosmossdk.io/math.Int",
(gogoproto.nullable) = false
];
int64 last_update_timestamp = 3 [(gogoproto.moretags) = "yaml:\"last_update_timestamp\""];
}
FeederDelegation
Feeder delegations is the correlation between a validator and a feeder address. It allows validators to use a different address to submit votes.
The FeederDelegation is defined as:
// FeederDelegation is the structure on the genesis regarding the delegation process
message FeederDelegation {
// feeder_address is the address delegated
string feeder_address = 1;
// validator_address is the validator's address who delegate its voting action
string validator_address = 2;
}
Messages
The Oracle module expose the following messages:
AggregateExchangeRateVote
The MsgAggregateExchangeRateVote
message is used by validators to submit their votes for the price of each asset in the whitelist. It contains the following fields:
// MsgAggregateExchangeRateVote represent the message to submit
// an aggregate exchange rate vote
message MsgAggregateExchangeRateVote{
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
option (cosmos.msg.v1.signer) = "feeder";
option (amino.name) = "oracle/aggregate-exchange-rate-vote";
string exchange_rates = 1 [(gogoproto.moretags) = "yaml:\"exchange_rates\""];
string feeder = 2 [(gogoproto.moretags) = "yaml:\"feeder\""];
string validator = 3 [(gogoproto.moretags) = "yaml:\"validator\""];
}
DelegateFeedConsent
The MsgDelegateFeedConsent
message is used to delegate the right to submit votes to a different address. The message contains the following fields:
// MsgDelegateFeedConsent represents a message to delegate oracle voting
// rights to another address
message MsgDelegateFeedConsent{
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
option (cosmos.msg.v1.signer) = "validator_owner";
option (amino.name) = "oracle/delegate-feed-consent";
string validator_owner = 1 [(gogoproto.moretags) = "yaml:\"validator_owner\""];
string delegate = 2 [(gogoproto.moretags) = "yaml:\"delegate\""];
}
UpdateParams
The MsgUpdateParams
message is used to update the module parameters. Only the governance module can call the message. It contains the following fields:
// MsgUpdateParams is the Msg/UpdateParams request type
message MsgUpdateParams {
option (cosmos.msg.v1.signer) = "authority";
// authority is the address that controls the module (defaults to x/gov)
string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
option (amino.name) = "kiichain/x/oracle/MsgUpdateParams";
// params defines the x/oracle parameters to update
//
// NOTE: All parameters must be supplied.
Params params = 2 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true];
}
Begin block
On each ABCI call, the Oracle module performs the following actions:
Check if we are under a new slash window
Check the slash counters for validators and slash them if they didn't submit enough votes in the previous voting period
Remove the excess feeds
End block
At the end of each block, the Oracle module performs the following actions:
Check if we are under a new voting period
Iterate the votes
Calculate the final exchange rate for each asset in the whitelist
Store the final exchange rate on-chain
Ante handler
The Oracle module ignores fees from validators on their first vote in the current voting period. The following is done:
Check if the message is a
MsgAggregateExchangeRateVote
Check the validator/feeder relationship
If the validator is voting for the first time in the current voting period, ignore the fees
Acknowledgments
Special thanks to the SEI team. Your contributions to the Cosmos SDK ecosystem are greatly appreciated. The original implementation of the Oracle module can be found in the SEI repository
Last updated
Was this helpful?