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

Fix/linear pricing #1812

Merged
merged 25 commits into from
May 24, 2024
Merged

Fix/linear pricing #1812

merged 25 commits into from
May 24, 2024

Conversation

mustermeiszer
Copy link
Collaborator

@mustermeiszer mustermeiszer commented Apr 15, 2024

Description

Currently, linear pricing is only used with the latest settlement price. Rather we want the linear pricing to be used IF the feature is enabled and then

  • IF oracle use on oracle value
  • IF NO valid oracle use on latest settlement price

Changes and Descriptions

  • Change linear pricing behaviour
  • Feature Creep: Ensure epoch closing is only possible for liquidity and pool admins
    NOTE: We need that is with the current setup Anemoy will set the validity of its oracles to always be valid which would allow anyone to close an epoch.

Communicate with Apps

  • Need to set oracle collection ages to None
  • ONLY pool admins or liquidity pool admins should be able to see close epoch fields
  • ExternalPricing changed. There is now an additional field with_linear_pricing that allows to toggle that feature

Communicate with Embrio

  • Indexing of LoanEvent::Created needs to be filtered by block after the upgrade to include the with_linear_pricing info

Checklist:

  • I have added Rust doc comments to structs, enums, traits and functions
  • I have made corresponding changes to the documentation
  • I have performed a self-review of my code
  • I have added tests that prove my fix is effective or that my feature works

@mustermeiszer
Copy link
Collaborator Author

mustermeiszer commented Apr 15, 2024

@lemunozm either I did something wrong or 7b4ab74 proofs that the implementation of IntoSeconds for Millis does not provide us with type safety.

I think we should make them new types rather. Wdyt?

@mustermeiszer
Copy link
Collaborator Author

@lemunozm I am not sure if I implemented it wrongly, but I can not figure out how to fix the test. ^^

@lemunozm
Copy link
Contributor

I think we should make them new types rather. Wdyt?

Yeah, we should use different types. That was something pending I had in mind to do it.

I can not figure out how to fix the test

I'll check it!

pallets/loans/src/lib.rs Outdated Show resolved Hide resolved
pallets/loans/src/entities/pricing/external.rs Outdated Show resolved Hide resolved
pallets/loans/src/entities/pricing/external.rs Outdated Show resolved Hide resolved
pallets/loans/src/lib.rs Outdated Show resolved Hide resolved
Copy link
Contributor

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

Much cleaner now!

Just a question to double-check

}))
});
let price_value_after_half_year = MARKET_PRICE_VALUE + (NOTIONAL - MARKET_PRICE_VALUE) / 2;
Copy link
Contributor

Choose a reason for hiding this comment

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

I like more how you have tested this!

runtime/common/src/lib.rs Outdated Show resolved Hide resolved
runtime/common/src/lib.rs Outdated Show resolved Hide resolved
@mustermeiszer mustermeiszer enabled auto-merge (squash) April 16, 2024 10:09
lemunozm
lemunozm previously approved these changes Apr 16, 2024
Copy link
Contributor

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

Thanks for tackle my suggestions!

@lemunozm
Copy link
Contributor

Probably clippy will complain with the if let/else structure to change it to a match

@@ -61,6 +61,6 @@ impl<T: Config> RepaidInput<T> {
#[scale_info(skip_type_params(T))]
pub enum PriceCollectionInput<T: Config> {
Empty,
Custom(BoundedBTreeMap<T::PriceId, T::Balance, T::MaxActiveLoansPerPool>),
Custom(BoundedBTreeMap<T::PriceId, (T::Balance, T::Moment), T::MaxActiveLoansPerPool>),
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Custom(BoundedBTreeMap<T::PriceId, (T::Balance, T::Moment), T::MaxActiveLoansPerPool>),
Custom(BoundedBTreeMap<T::PriceId, PriceOf<T>, ::MaxActiveLoansPerPool>),

To fix the clippy issue

lemunozm
lemunozm previously approved these changes Apr 16, 2024
@mustermeiszer mustermeiszer added the D5-breaks-api Pull request changes public api. Document changes publicly. label Apr 16, 2024
lemunozm
lemunozm previously approved these changes Apr 16, 2024
wischli
wischli previously approved these changes Apr 16, 2024
Copy link

codecov bot commented May 6, 2024

Codecov Report

Attention: Patch coverage is 13.92405% with 136 lines in your changes are missing coverage. Please review.

Project coverage is 46.53%. Comparing base (5fc0465) to head (fcddabf).

Current head fcddabf differs from pull request most recent head b6976c8

Please upload reports for the commit b6976c8 to get more accurate results.

Files Patch % Lines
runtime/common/src/migrations/loans.rs 0.00% 65 Missing ⚠️
pallets/loans/src/entities/loans.rs 0.00% 24 Missing ⚠️
pallets/loans/src/entities/pricing/external.rs 44.18% 24 Missing ⚠️
runtime/common/src/pool.rs 0.00% 17 Missing ⚠️
pallets/pool-system/src/benchmarking.rs 0.00% 3 Missing ⚠️
runtime/common/src/lib.rs 0.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1812      +/-   ##
==========================================
- Coverage   46.89%   46.53%   -0.37%     
==========================================
  Files         165      167       +2     
  Lines       12950    13089     +139     
==========================================
+ Hits         6073     6091      +18     
- Misses       6877     6998     +121     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@mustermeiszer mustermeiszer added the D8-migration Pull request touches storage and needs migration code. label May 6, 2024
),
BadOrigin
);
T::AdminOrigin::ensure_origin(origin, &pool_id)?;
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice! I didn't know about EnsureOriginWithArg. Probably, I should have used it in oracle-collection instead of PreConditions there.

Comment on lines 28 to 29
<T as frame_system::Config>::RuntimeOrigin: From<RawOrigin<<T as frame_system::Config>::AccountId>>
+ Into<Result<RawOrigin<<T as frame_system::Config>::AccountId>, T::RuntimeOrigin>>,
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT. I think this is already satisfied by RuntimeOrigin

@lemunozm
Copy link
Contributor

lemunozm commented May 7, 2024

Thanks for the awesome PR description! ❤️ Very helpful

@@ -76,6 +77,9 @@ pub struct ExternalPricing<T: Config> {
/// borrow/repay and the current oracle price.
/// See [`ExternalAmount::settlement_price`].
pub max_price_variation: T::Rate,

/// If the pricing is estimated with a linear pricing model.
pub with_linear_pricing: bool,
Copy link
Contributor

Choose a reason for hiding this comment

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

With this, I think now is much more understandable what's happening 🎉

@mustermeiszer
Copy link
Collaborator Author

Comment on lines 396 to 411
#[cfg(not(feature = "runtime-benchmarks"))]
fn try_origin(o: RuntimeOrigin, _: &PoolId) -> Result<Self::Success, RuntimeOrigin> {
<RuntimeOrigin as Into<Result<RawOrigin<AccountId>, RuntimeOrigin>>>::into(o).and_then(
|r| match r {
RawOrigin::Root => Ok(()),
RawOrigin::Signed(account) => {
if account == DEFAULT_POOL_OWNER {
Ok(())
} else {
Err(RawOrigin::Signed(account).into())
}
}
RawOrigin::None => Err(RawOrigin::None.into()),
},
)
}
Copy link
Contributor

@lemunozm lemunozm May 16, 2024

Choose a reason for hiding this comment

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

Why do we need this special implementation? Do not we want always Ok() for testing?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Mmmh. Good point. If this is covered in the integration test, probably not.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Changed to an all version

)
}

fn current_price_inner(
Copy link
Contributor

Choose a reason for hiding this comment

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

The current on-chain behavior is:

  • If oracle is found, use oracle price
  • If not found, use linear accrual price.

That behavior can not be modeled right now. We need to choose between:

  • Use oracle price or if not use settlement price (with_linear_pricing = false)
  • Use always linear accrual price (with_linear_pricing = true)

Do we want this? Don't we still want to model the current behavior?

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No, we want to change that too.

Get the price:

  • IF oracle → use oracle
  • ELSE → use settlement price

Use the price:

  • IF linear pricing → use linear pricing
  • ELSE → just use price

Copy link
Contributor

Choose a reason for hiding this comment

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

What's the difference between "Get the price" and "Use the price"?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Get is either orale or settlement. Use is just for using whatever came out of the get.

Copy link
Contributor

Choose a reason for hiding this comment

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

I would add new 2 test cases to check a loan configured with use_linear_price = true always uses the linear accrual with oracle value and with settlement price

Copy link
Contributor

Choose a reason for hiding this comment

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

Well, after the changes of this PR all loans comes with use_linear_price = true, so we should check the false version instead

@wischli
Copy link
Contributor

wischli commented May 17, 2024

Copy link
Contributor

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

Some few minor and NITs comments, but LGTM!

pallets/loans/src/tests/portfolio_valuation.rs Outdated Show resolved Hide resolved
pallets/loans/src/tests/repay_loan.rs Outdated Show resolved Hide resolved
pallets/loans/src/tests/repay_loan.rs Outdated Show resolved Hide resolved
Copy link
Contributor

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

Thank you so much for tackling my Nits ❤️

@mustermeiszer mustermeiszer merged commit 1570c34 into main May 24, 2024
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
D5-breaks-api Pull request changes public api. Document changes publicly. D8-migration Pull request touches storage and needs migration code.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants