Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for token price oracle #400

Merged
merged 4 commits into from
Mar 10, 2023
Merged

Add support for token price oracle #400

merged 4 commits into from
Mar 10, 2023

Conversation

vihu
Copy link
Member

@vihu vihu commented Mar 2, 2023

  • Add price oracle skeleton
  • Update file_info
  • Add settings
  • Update Cargo.toml and Cargo.lock

@vihu vihu force-pushed the rg/price branch 3 times, most recently from 1801f86 to eabd6ed Compare March 7, 2023 07:03
@vihu vihu changed the title [WIP] [DNM] Add price workspace Add support for token price oracle Mar 7, 2023
@vihu vihu marked this pull request as ready for review March 7, 2023 07:04
triggered = {workspace = true}
pyth-sdk-solana = "0.7.1"
solana-client = ">= 1.9, < 1.15"
solana-program = ">= 1.9, < 1.15"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need all of these?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, client for the RpcClient and program for the pubkey. pyth-sdk doesn't seem to automatically fetch these.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like you should be able to omit the solana-program dependency since pyth-sdk-solana depends on that generally, but it only lists solana-client as a dev dependency

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing just the solana-program doesn't seem to work either.

price/docker-compose.yml Outdated Show resolved Hide resolved
price/pkg/settings-template.toml Outdated Show resolved Hide resolved
price/pkg/settings-template.toml Outdated Show resolved Hide resolved
price/pkg/settings-template.toml Outdated Show resolved Hide resolved
#[error("unsupported token type: {0}")]
UnsupportedTokenType(i32),
#[error("unable to fetch price")]
UnableToFetch,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an underlying error when UnableToFetch hits?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't look like it, get_price_no_older_than just returns None afaict.

price/src/main.rs Outdated Show resolved Hide resolved
price/src/price_service.rs Outdated Show resolved Hide resolved
file_store/src/file_info.rs Outdated Show resolved Hide resolved
price/src/settings.rs Outdated Show resolved Hide resolved
price/src/price_service.rs Outdated Show resolved Hide resolved
price/docker-compose.yml Outdated Show resolved Hide resolved
triggered = {workspace = true}
pyth-sdk-solana = "0.7.1"
solana-client = ">= 1.9, < 1.15"
solana-program = ">= 1.9, < 1.15"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like you should be able to omit the solana-program dependency since pyth-sdk-solana depends on that generally, but it only lists solana-client as a dev dependency

Comment on lines 115 to 130
.map(|key| SolPubkey::from_str(key).expect("unable to parse")),
BlockchainTokenTypeV1::Hst => self
.cluster
.hst_price_key
.as_ref()
.map(|key| SolPubkey::from_str(key).expect("unable to parse")),
BlockchainTokenTypeV1::Mobile => self
.cluster
.mobile_price_key
.as_ref()
.map(|key| SolPubkey::from_str(key).expect("unable to parse")),
BlockchainTokenTypeV1::Iot => self
.cluster
.iot_price_key
.as_ref()
.map(|key| SolPubkey::from_str(key).expect("unable to parse")),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this makes sense to me as a "halt and catch fire scenario" and theoretically quick enough to fix if encountered but can we have the panic error explain which key we failed to fetch for when we have more than just the HNT price key and we aren't necessarily sure which one we failed to parse?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated with panic!, cc: @madninja cuz panic! Open to other suggestions instead of panicking but as @jeffgrunewald said we want to catch this ASAP and fix it when tokens come alive. f8ab0b3

price/README.md Outdated Show resolved Hide resolved
file_store/src/cli/dump.rs Outdated Show resolved Hide resolved
price/src/price_generator.rs Outdated Show resolved Hide resolved
Comment on lines +99 to +107
mobile_price_generator
.run(price_sink.clone(), &shutdown, BlockchainTokenTypeV1::Mobile)
.map_err(Error::from),
iot_price_generator
.run(price_sink.clone(), &shutdown, BlockchainTokenTypeV1::Iot)
.map_err(Error::from),
hst_price_generator
.run(price_sink, &shutdown, BlockchainTokenTypeV1::Hst)
.map_err(Error::from),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since these generators are just going to be reaching a None else case when they check for a pricing account key do we even want to run them before those tokens have prices to be fetched? I would see running them if we were going to default to writing out a $0 pricing report but since we're not it seems like we could skip them.

for that matter, and since we are only accessing these prices via the written reports would it be easier to have a single PriceGenerator struct that loops over all "active" tokens based on configuration, stores only the last price in a map in its state and spawns a thread with a join handle for each active token, passing the previous price to the thread and A) checking for a newer price, B) writing out the report to the file sink with the current timestamp and C) returning either the previous or newer price via the join handle to the PriceGenerator?

then you only need to grab current time once and it doesn't need to be mutable, you simplify the state of the PriceGenerator process, there's only one continuous thread you need to worry about shutting down and it's just a matter of adding a token string to a config list in Settings to start checking for additional prices

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah we thought about having a single PriceGenerator, but it doesn't really matter if the timestamps for different token types (as they become available) within the reports are the same as long as they are there. I believe it's already pretty simple as is imo and the state is minimal.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it matter if one price gets successfully updated and others do not? ie is there any intra dependencies on the prices being current on the consumer side ? If iot gets updated but for whatever reason hnt fails to update and continues failing for a while and whilst there may be steep changes in the hnt price

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good question but I'd say not something we have to solve for first pass at least. So in the scenario where HNT updated and IOT failed, we'll presumably continue to serve the same data for IOT till we:

a) either have some redundancy with our RPC endpoints (assuming it was an RPC failure to fetch IOT in the above example)
b) or we kind of "derive" IOT price from HNT in some way

@madninja What are your thoughts on this? I could look into adding support for multiple RPC endpoints I suppose. And maybe do a mean of the prices fetched from multiple RPC endpoints?

vihu added 4 commits March 7, 2023 15:00
- Temp update Cargo.toml and Cargo.lock
- Update file info and dump cli
- Add docker-compose.yml for local testing
@vihu vihu merged commit a7ac570 into main Mar 10, 2023
@vihu vihu deleted the rg/price branch March 10, 2023 21:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants