Skip to main content
Version: v0.4

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 OraclePricePairs 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 OraclePricePairs. 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:

[VotePeriodEndTimeTwapDuration,VotePeriodEndTime][VotePeriodEndTime-TwapDuration, VotePeriodEndTime]

💡 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 NamespaceVotes for all the OraclePricePairs.

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 VotePeriodEndTimeVotePeriodEndTimefor 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:

BlockTimeVotePeriodEndTimeBlockTime\geq VotePeriodEndTime

💡 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 NamespaceVotes for all the RefractableAssets.

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 VotePeriodEndTimeVotePeriodEndTimefor 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:

BlockTimeVotePeriodEndTimeBlockTime\geq VotePeriodEndTime

💡 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 NamespaceVotes for all the HostChains.

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

  1. Install:

    • node version v18.15.0+
    • pnpm version 7.30.0+
  2. Clone the source code, install dependencies, and compile:

    git clone https://github.com/pryzm-finance/pryzm-feeder
    cd pryzm-feeder
    pnpm install
    pnpm compile
  3. Configure the feeder by modifying the config.yaml file.

  4. 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