Pryzm Oracle Feeder
Introduction
The pryzm feeder is an extension of the RefractedLabs oracle feeder, responsible for providing reliable, up-to-date information about external data sources. Validators rely on this information to make informed decisions about the network state and required actions.
There are three modules that are fed by the pryzm feeder; amm, assets, and icstaking. This document will introduce the service and plugin implementations for each module.
Packages
amm
This package provides the amm module with time-weighted average prices (TWAP) of OraclePricePair
s defined by that module. It monitors the configured data sources to fetch spot prices for each asset required to calculate the TWAP for all active OraclePricePair
s. The information, also known as the amm OraclePayload
, is packaged into a ModuleVote
within the AmmPlugin
which is ultimately received by the amm module through a vote submitted by the oracle feeder.
💡 At present, the only data sources that are supported in the amm package are Osmosis and Pryzm. However, the design allows for the addition of other data sources.
💡 An OraclePricePair
is comprised of a list of internal pairs that define the necessary route steps for calculating the price.
Osmo Monitoring Service
This service retrieves the required price data and computes the spot price for each internal pair (route step) of every active OraclePricePair
per Osmosis block. This data is then stored in a database, which the AmmPlugin
queries in order to calculate the TWAP price once during every voting period.
Pryzm Monitoring Service
The service retrieves the spot price for each internal pair (route step) of every active OraclePricePair
per Pryzm block. This data is then stored in a database, which the AmmPlugin
queries to calculate the TWAP price once during every voting period.
Amm Plugin
When a call is made to the getModuleVotes
method, the plugin queries the stored price data and calculates the TWAP price for each OraclePricePair
in the interval:
💡 For each OraclePricePair
, a NamespaceVote
is prepared, with the pair asset_id
serving as the namespace name. A single ModuleVote
is then returned by the plugin, which contains the NamespaceVote
s for all the OraclePricePair
s.
Amm Oracle Payload
The expected payload structure that the amm module requires from the plugin is as follows:
message OraclePayload {
repeated OraclePayloadDataSourceBlockHeight data_source_block_heights = 1;
string price = 2;
repeated Pair pairs = 3;
string quote_token = 4;
}
message OraclePayloadDataSourceBlockHeight {
string data_source = 1;
ibc.core.client.v1.Height block_height = 2;
}
message Pair {
string base = 1;
string quote = 2;
string pool_id = 3; //refers to the data source pool (e.g. osmosis gamm pool)
string data_source = 4;
}
A sample payload has the following structure:
{
"data_source_block_heights": [
{
"data_source": "osmo",
"block_height": {
"revision_number": 0,
"revision_height": 11
}
}
],
"price": "1.358064516129032258",
"pairs": [
{
"base": "lp/pool/1",
"quote": "q",
"pool_id": "1",
"data_source": "osmo"
},
{
"base": "q",
"quote": "usdc",
"pool_id": "1",
"data_source": "osmo"
}
],
"quote_token": "ibc/D189335C6E4A68B513C10AB227BF1C1D38C746766278BA3EEB4FB14124F1D858"
}
assets
This package feeds the assets module with exchange rates for all retractable assets by monitoring the configured LCDs and fetching exchange rates into the database. The exchange rates, which are a part of the assets OraclePayload
, are then packed into a ModuleVote
inside the AssetsPlugin
. This ModuleVote
is ultimately received by the assets module through a vote submission that is committed by the oracle feeder.
Assets Host Chain Monitoring Service
This service queries the exchange rates for all active RefractableAssets
for each host chain block. This information is then stored in a database that is queried by the AssetsPlugin
once during every voting period.
Assets Plugin
When a call is made to the getModuleVotes
method, the plugin queries the most recent stored exchange rate before the current for each RefractableAsset
. If the plugin is not synchronized with the corresponding host chain up to a block with the following constraint, it will consider an abstain vote for a RefractableAsset
:
💡 For each RefractableAsset
, a NamespaceVote
is prepared, with the asset id
serving as the namespace name. A single ModuleVote
is then returned by the plugin, which contains the NamespaceVote
s for all the RefractableAsset
s.
Assets Oracle Payload
The expected payload structure that the assets module requires from the assets plugin is as follows:
message OraclePayload {
ibc.core.client.v1.Height block_height = 1;
string exchange_rate = 2;
}
A sample payload has the following structure:
{
"block_height": {
"revision_number": 0,
"revision_height": 11
},
"exchange_rate": "1.4"
}
icstaking
This package feeds the icstaking module with states for all host chains defined in the module by monitoring the configured chains and fetching and calculating the required data into the database. The states, also known as OraclePayload
, are then packed into a ModuleVote
inside the IcstakingPlugin
. This ModuleVote
is ultimately received by the icstaking
module through a vote submission that is committed by the oracle feeder.
Icstaking Host Chain Monitoring Service
This service queries the required data for all HostChains
for each chain block. This information is then stored in a database that is queried by the IcstakingPlugin
once during every voting period.
Icstaking Plugin
When a call is made to the getModuleVotes
method, the plugin queries the most recent stored state before the current for each HostChain
. If the plugin is not synchronized with the corresponding host chain up to a block with the following constraint, it will consider an abstain vote for a HostChain
:
💡 For each HostChain
, a NamespaceVote
is prepared, with the host chain id
serving as the namespace name. A single ModuleVote
is then returned by the plugin, which contains the NamespaceVote
s for all the HostChain
s.
Icstaking Oracle Payload
The expected payload structure that the icstaking module requires from the icstaking plugin is as follows:
message OraclePayload {
ibc.core.client.v1.Height block_height = 1 [(gogoproto.nullable) = false];
// list of validators and their state containing the delegation amount
repeated ValidatorState validator_states = 2;
// balance of delegation interchain account
string delegation_account_balance = 3;
// balance of reward interchain account
string reward_account_balance = 4;
// balance of sweep interchain account
string sweep_account_balance = 5;
// the largest undelegation epoch number for which the undelegation is completed and is ready to be swept to PRYZM
// reporting this with zero means that none of incomplete undelegations are completed.
uint64 last_completed_undelegation_epoch = 6;
}
message ValidatorState {
string validator_address = 1;
string delegated_amount = 2;
string total_tokens = 3;
string total_shares = 4;
}
A sample payload has the following structure:
{
"block_height": {
"revision_number": 0,
"revision_height": 11
},
"validator_states": [
{
"validator_address": "val1",
"delegated_amount": "1000000",
"total_tokens": "3000000",
"total_shares": "3000000"
},
{
"validator_address": "val2",
"delegated_amount": "2000000",
"total_tokens": "4000000",
"total_shares": "4000000"
}
],
"delegation_account_balance": "440",
"reward_account_balance": "330",
"sweep_account_balance": "220",
"last_completed_undelegation_epoch": 15
}
Quick Start
Using Docker
You can use the provided docker-compose file. Download the file or clone the repository and run:
docker compose up -d
💡 In order to configure the application, copy the contents of the configuration given here into a file named config.yaml
next to the docker-compose.yml
file and customize it as required.
Using source
-
Install:
-
Clone the source code, install dependencies, and compile:
git clone https://github.com/pryzm-finance/pryzm-feeder
cd pryzm-feeder
pnpm install
pnpm compile -
Configure the feeder by modifying the
config.yaml
file. -
Start the feeder:
pnpm start <optional_config_file_path>
Note that if the config file path is not given in the above command, it is considered as
./config.yaml
.
Build docker image
You can also build a docker image from source using the following command:
pnpm dockerize
Configuration
The following is a sample for the config.yaml file:
log:
level: 'debug'
dirname: 'logs'
filename: 'feeder.log'
maxSize: '1kb'
maxFiles: 10
telemetry:
enable: true
serverPort: 2121
feeder: "<your_feeder_address>"
feederMnemonic: "<your_feeder_address_mnemonic>"
validator: "<your_validator_valoper_address>"
voteReservedTimeMillis: 3000
chain:
rpcUrl: "<your_rpc_endpoint>"
lcdUrl: "<your_lcd_endpoint>"
grpcWebUrl: "<your_grpc_endpoint>"
wsUrl: "ws://<your_rpc_endpoint>"
wsTimeout: 5000
addressPrefix: "pryzm"
denom: "upryzm"
broadcastTimeoutMs: 5000
gasPrice: "0.02upryzm"
preVoteFee: 2
combinedVoteFee: 2
blockCommitTimeoutMillis: 10000
databaseService:
disable: false
database:
name: "pryzm-feeder"
host: "localhost"
port: 5432
user: "postgres"
password: "postgres"
migrationPath: "./migrations"
ammPlugin:
disable: false
osmoMonitoringService:
disable: false
datasource: "osmo"
lcdUrl: "<public_osmosis_lcd_address>"
fetchIntervalSeconds: 1
# startFromLatestBlock: true
chainBlockCommitTimeoutSeconds: 6 # seconds
pryzmMonitoringService:
disable: false
datasource: "pryzm"
grpcWebUrl: "<your_grpc_endpoint>"
fetchIntervalSeconds: 1
# startFromLatestBlock: true
chainBlockCommitTimeoutSeconds: 5 # seconds
assetsPlugin:
disable: false
assetsHostChainMonitoringService:
disable: false
exchangeRatesFetchIntervalSeconds: 1
assets:
- assetId: "cudummy"
lcd: "https:///cudummy"
contract: "address"
base64StateQuery: query # base64 string for {'state': {}}
icStakingPlugin:
disable: false
icStakingHostChainMonitoringService:
disable: false
monitoringIntervalSeconds: 1
chains:
- id: "uluna"
lcdUrl: "<terra_testnet_lcd_api>"
- id: "uosmo"
lcdUrl: "<osmo_testnet_lcd_api>"
- id: "ujunox"
lcdUrl: "<juno_testnet_lcd_api>"
databaseService : database : migrationPath
Path to the directory containing database migration files.
osmoMonitoringService
Contains the required configuration for monitoring Osmosis as a data source.
pryzmMonitoringService
Contains the required configuration for monitoring Pryzm as a data source.
assetsHostChainMonitoringService
The required configuration for monitoring the exchange rate for a list of assets.
icStakingHostChainMonitoringService
The required configuration for monitoring a list of host chains.
Test
To run the tests, run the following command:
pnpm test