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

Oracle V2 implementation #1629

Merged
merged 42 commits into from Dec 21, 2023
Merged

Oracle V2 implementation #1629

merged 42 commits into from Dec 21, 2023

Conversation

lemunozm
Copy link
Contributor

@lemunozm lemunozm commented Nov 28, 2023

Description

Main new requirements:

  • Different feeders for different prices in different collections.
  • Feeders are permissionless, and the admin chooses the feeders for a pool.
  • The collection is updated under demand.
  • We prioritize low PoV against DB rate access.

See the specs here

Changes and Descriptions

  • Add ValueProvider trait to pass values through the oracle structure.
  • Add OracleConverterBridge to convert from Quantity to Balance
  • Add PoolAdminCheck type implementing PreConditions to carry the evaluation of a pool admin easily.
  • pallet-oracle-feed: a pallet that just store feeding values
    • Implementation
    • Testing
    • Benchmarking
  • pallet-oracle-data-collection: a pallet that compose collections aggregating values.
    • Implementation
    • Testing
    • Benchmarking
  • Add to development runtime (and compiling)
  • Add to altair runtime
  • Add to centrifuge runtime

This PR not:

  • Attach pallet-loans logic to these new pallets
  • Remove old oracle infrastructure
  • Modify oracle integration tests
  • Perform any migration

@lemunozm lemunozm added Q5-hard Can be done by an experienced coder with a good knowledge of the codebase. P5-soon Issue should be addressed soon. D2-notify Pull request can be merged and notification about changes should be documented. I8-enhancement An additional feature. labels Nov 28, 2023
@lemunozm lemunozm self-assigned this Nov 28, 2023
Copy link
Contributor Author

@lemunozm lemunozm left a comment

Choose a reason for hiding this comment

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

Highlighting the most important things:

pallets/oracle-data-collection/src/lib.rs Outdated Show resolved Hide resolved
pallets/oracle-data-collection/src/lib.rs Show resolved Hide resolved
pallets/oracle-data-collection/src/lib.rs Outdated Show resolved Hide resolved
pallets/oracle-feed/src/lib.rs Show resolved Hide resolved
pallets/oracle-data-collection/src/lib.rs Outdated Show resolved Hide resolved
pallets/oracle-data-collection/src/lib.rs Outdated Show resolved Hide resolved
pallets/oracle-data-collection/src/lib.rs Show resolved Hide resolved
pallets/oracle-data-collection/src/lib.rs Outdated Show resolved Hide resolved
pallets/oracle-data-collection/src/lib.rs Outdated Show resolved Hide resolved
pallets/oracle-data-collection/src/lib.rs Outdated Show resolved Hide resolved
Copy link
Collaborator

@mustermeiszer mustermeiszer left a comment

Choose a reason for hiding this comment

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

First round. Sorry for stalling. Looks goood, but need to look at the details again.

runtime/centrifuge/src/lib.rs Outdated Show resolved Hide resolved
pallets/oracle-feed/src/lib.rs Outdated Show resolved Hide resolved
pallets/oracle-feed/src/lib.rs Outdated Show resolved Hide resolved
@lemunozm
Copy link
Contributor Author

lemunozm commented Dec 15, 2023

@mustermeiszer here is the root support: 29bfc7d

I've needed to propagate that to pallet-oracle-data-collection to be able to fetch fed value by root

pallets/oracle-feed/src/lib.rs Show resolved Hide resolved
pallets/oracle-feed/src/lib.rs Outdated Show resolved Hide resolved
pallets/oracle-feed/src/lib.rs Outdated Show resolved Hide resolved
pallets/oracle-feed/src/lib.rs Outdated Show resolved Hide resolved
@lemunozm
Copy link
Contributor Author

lemunozm commented Dec 19, 2023

@mustermeiszer when you say Origin, do you mean something like:

#[pallet::origin]
pub type Origin = FeederOrigin;

?

@lemunozm
Copy link
Contributor Author

Ok, I think we do not want that, just reuse the current RuntimeOrigin.

Copy link
Contributor

@wischli wischli left a comment

Choose a reason for hiding this comment

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

First round with a lot of nits and some questions from my side. Feel free to ignore all the nits. Looks really good!

pallets/oracle-data-collection/src/benchmarking.rs Outdated Show resolved Hide resolved
pallets/oracle-data-collection/src/lib.rs Outdated Show resolved Hide resolved
pallets/oracle-data-collection/src/lib.rs Outdated Show resolved Hide resolved
pallets/oracle-data-collection/src/lib.rs Outdated Show resolved Hide resolved
pallets/oracle-feed/src/tests.rs Show resolved Hide resolved
runtime/altair/src/lib.rs Outdated Show resolved Hide resolved
impl pallet_oracle_feed::Config for Runtime {
type FirstValuePayFee = FeeToTreasury<Fees, FirstValueFee>;
type OracleKey = OracleKey;
type OracleValue = Quantity;
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it really Quantity? I would have imagined Rate for loans or Ratio for the orderbook

Copy link
Contributor Author

@lemunozm lemunozm Dec 19, 2023

Choose a reason for hiding this comment

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

Rate sure not because it has 27 decimals with a few integer parts. It could be a Ratio which is exactly the same type as Quantity (both alias the same exact type). We should probably unify these types to avoid confusion.

Regarding the name, I think you're right, and Ratio fits better to specify a "price"

Copy link
Collaborator

Choose a reason for hiding this comment

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

@lemunozm can you make this an enum already? I think we will have non ratio types in the future. WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Make sense to avoid future migrations

Copy link
Contributor Author

@lemunozm lemunozm Dec 20, 2023

Choose a reason for hiding this comment

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

@mustermeiszer thinking about this. Do you think it would be interesting to have different pallet instances for pallet-oracle-feed in case of different values instead of an OracleValue enum?

I say this to avoid, for example, a feeder feeding with a Key as Isin and a Value as a non-ratio type, mixing keys with non-related values.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

After another thought, definitely I think it's better to use different pallet instances to maintain always well-formed key-value correlations on-chain. If some consumer needs different value types, we can always compound them into an enum using a runtime type that implements ValueProvider in the runtime. Similar to what we already do with OracleConverterBridge.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I am really undecided here.

PRO:

  • strong typed relationship
  • cleaner from a technical perspective

CON:

  • We have 70 pallets right now, the limit is 255 - not really close, but we are already having more pallets than most parachains IIRC
  • External integrations - It is just harder to look at the right place but I might over-value that

I have even thought about allowing this API

		pub fn feed(
lemunozm marked this conversation as resolved.
			origin: OriginFor<T>,
			key: BoundedVec<T::MaxScaleSizeKey>,
			value: BoundedVec<T::MaxScaleSizeValue>,
		) -> DispatchResultWithPostInfo {

and upon fetching/aggregating we decode into the needed type and fail if it is not correct. That would be the most flexible.

For example with currently we have needs for

  • ISIN -> Price
  • (Currency, Currency) -> Price

Should we really have an instance of this pallet for each combination that we need on-chain? There will be more, I can promise that ^^

Copy link
Contributor Author

@lemunozm lemunozm Dec 21, 2023

Choose a reason for hiding this comment

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

🤔

Should we really have an instance of this pallet for each combination that we need on-chain?

I think both relations above can be in the same pallet instance. The pallet instance can have the Key as an enum but the Value as Price. That way, any Key enum variant will map always to a correct Value type.

The number of instances will depend only on the number of different kinds of values, not keys. Mostly, I can see Price, Balance, and maybe some id or similar (?).

The API with encoding values seems pretty scary to me 😅

WDYT?

Copy link
Collaborator

Choose a reason for hiding this comment

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

The encoding is always ensured when fetching the keys. Basically anywas what we are already doing when accceotinbg an extrinsic, but just during a runtime call. It is then an invalid key.

But lets go with instances if you think it is better. Should we already make the current key then an enum?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should we already make the current key then an enum?

It currently is!

runtime/altair/src/lib.rs Show resolved Hide resolved
runtime/common/src/changes.rs Outdated Show resolved Hide resolved
@lemunozm
Copy link
Contributor Author

Thanks for your deep review @wischli, I'll go into detail with your comments once I give the support for RuntimeOrigin to the PR

Copy link
Contributor Author

@lemunozm lemunozm left a comment

Choose a reason for hiding this comment

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

@mustermeiszer latest changes for the RuntimeOrigin support: 72f3e09

runtime/common/src/oracle.rs Show resolved Hide resolved
Copy link
Contributor

@wischli wischli left a comment

Choose a reason for hiding this comment

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

Thanks for adhering to many of my nits and arguing against the other. AFAICS, the last open discussion is about instantiation vs. OracleValue enum. As I am voting for the former, I am approving this PR already. We must not merge before Frederik's approval though.

pallets/oracle-feed/src/lib.rs Show resolved Hide resolved
impl pallet_oracle_feed::Config for Runtime {
type FirstValuePayFee = FeeToTreasury<Fees, FirstValueFee>;
type OracleKey = OracleKey;
type OracleValue = Quantity;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think instantiating the pallet-oracle-feed makes more sense for the mentioned reason. That can be done in a follow up PR. But @mustermeiszer should have the stronger say here.

Copy link
Collaborator

@mustermeiszer mustermeiszer left a comment

Choose a reason for hiding this comment

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

Look great, just need to decide on the instance vs. enum vs. generic scale for key-value in oracle.

impl pallet_oracle_feed::Config for Runtime {
type FirstValuePayFee = FeeToTreasury<Fees, FirstValueFee>;
type OracleKey = OracleKey;
type OracleValue = Quantity;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I am really undecided here.

PRO:

  • strong typed relationship
  • cleaner from a technical perspective

CON:

  • We have 70 pallets right now, the limit is 255 - not really close, but we are already having more pallets than most parachains IIRC
  • External integrations - It is just harder to look at the right place but I might over-value that

I have even thought about allowing this API

		pub fn feed(
lemunozm marked this conversation as resolved.
			origin: OriginFor<T>,
			key: BoundedVec<T::MaxScaleSizeKey>,
			value: BoundedVec<T::MaxScaleSizeValue>,
		) -> DispatchResultWithPostInfo {

and upon fetching/aggregating we decode into the needed type and fail if it is not correct. That would be the most flexible.

For example with currently we have needs for

  • ISIN -> Price
  • (Currency, Currency) -> Price

Should we really have an instance of this pallet for each combination that we need on-chain? There will be more, I can promise that ^^

Comment on lines +190 to +192
pub struct OracleConverterBridge<Origin, Provider, Pools, AssetRegistry>(
PhantomData<(Origin, Provider, Pools, AssetRegistry)>,
);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Don't we also need a converter for the CachedCollection, or is it implicitly using this one?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes it is implicitly using this one

parameter_types! {
#[derive(Clone, PartialEq, Eq, Debug, TypeInfo, Encode, Decode, MaxEncodedLen)]
pub const MaxFeedersPerKey: u32 = 10;
pub const FirstValueFee: Fee = Fee::Balance(deposit(1, pallet_oracle_feed::util::size_of_feed::<Runtime>()));
Copy link
Collaborator

Choose a reason for hiding this comment

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

This means 1 CFG per value?

Copy link
Contributor

Choose a reason for hiding this comment

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

1.65 CFG for each first value, yes. See here for context: #1629 (comment)

Copy link
Collaborator

@mustermeiszer mustermeiszer left a comment

Choose a reason for hiding this comment

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

Thanks! All thinks sort out from my side.

@lemunozm lemunozm merged commit 1552ccf into main Dec 21, 2023
9 checks passed
@lemunozm lemunozm deleted the oracle-v2 branch December 21, 2023 13:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
D2-notify Pull request can be merged and notification about changes should be documented. I8-enhancement An additional feature. P5-soon Issue should be addressed soon. Q5-hard Can be done by an experienced coder with a good knowledge of the codebase.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants