-
Notifications
You must be signed in to change notification settings - Fork 86
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
Loans: linear accrual on settlement price #1739
Conversation
/// - If not set, then the price is a linear accrual using the latest | ||
/// settlement price. | ||
/// See [`ExternalActivePricing::current_price()`] | ||
pub current_price: Option<T::Balance>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we could use the valuation method of the internal pricing here too. Removing the Option. ANd I would name it current_value.
cc: @denniswell
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Valuation method is just the present value for internal pricing loans. So we should do the same for external pricing loans too if go with this change.
This is related to my question:
Should we modify present_value() to now use current_price instead of latest_settlement_price?
For external pricing loans present_value = quantity * latest_settlemente_price
. So maybe we do not need to use another field here and just update how present_value
is computed using now current_price
instead of latest_settlement_price
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah sorry, my bad! I think that is the best idea!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we still want to put current_price
here to allow the UI just to draw the price. Otherwise, they should divide the present_value / outstanding_quantity to obtain it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that is confusing more ATM. The total value is anyways of greatest interest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think all that is relevant mostly is the value anyways.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding this topic, I would say that if Apps needs to draw the price, leave the current_price
as it is. Otherwise, if they need it and we do not offer it by the RuntimeAPI, then they need to perform not-trivial computations, and future changes to present_value will break that.
@onnovisser are you drawing right now the settlementPrice
of an external loan?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lemunozm can we remove that one here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we decide after getting feedback from https://kflabs.slack.com/archives/C04GARZ532T/p1709024010720729 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Onno is out, which is who is taking care of it, I think, so probably we do not have feedback soon regarding this.
Seeing the apps code, they need to fetch the price as current_price
now to fulfill this part: https://github.com/centrifuge/apps/blob/beea676a936a14597f270e931387a4df1ce7ca0d/centrifuge-app/src/utils/getLatestPrice.ts#L10 which is later used to draw in the loan page.
I would say we need to keep this here. Do you have any argument against this, @mustermeiszer? I do not see you very in favor of adding it.
pub fn present_value_cached<Prices>( | ||
&self, | ||
cache: &Prices, | ||
maturity: Seconds, | ||
) -> Result<T::Balance, DispatchError> | ||
where | ||
Prices: DataCollection<T::PriceId, Data = PriceOf<T>>, | ||
{ | ||
let price = match cache.get(&self.info.price_id) { | ||
Ok(data) => data.0, | ||
Err(_) => self.latest_settlement_price, | ||
Err(_) => self.linear_accrual_price(maturity)?, | ||
}; | ||
Ok(self.outstanding_quantity.ensure_mul_int(price)?) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...the externally priced loan will fail to obtain the "real value" and will generate the missing price for itself using the linear accrual method.
Later, faking or not the update_portfolio()
with a list of prices is independent of this process (probably in another PR where we change the PoolNAV
trait).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But this way we can not fake the oracle prices, in cases where we want to simulate the nav execution with new oracles. And this would mean closing an epoch is not protected if the oracle is outdated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But this way we can not fake the oracle prices
We can because when we fake them, the value will come from the Ok()
branch (line 205).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Say since last epoch execution, no loan price was updated. IIUC, this PR does not affect the update_portfolio
outcome. Asking because the PoolFees NAV is dependent on the Loans NAV.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, it affects. Because now, when there are no oracles, the price is the linear accrual instead of settlement_price
. Ideally, after this change, we should do a portfolio_update()
to consolidate the changes in the present value affected by this.
We could even add it as part of the migration. WDYT @mustermeiszer?
Just calling to update the portfolio
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I am following? Why should there be a problem for the PoolFees NAV?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if it is for PoolFees. But it can be for pallet-loans
because we are modifying how the present_value()
is computed but we are not updating the portfolio with this new computation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mustermeiszer The PoolFees NAV is dependent on the Loans NAV. So I wanted to check whether it is an issue if the Loans NAV is not updated with the present_value
computation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But it can be for pallet-loans because we are modifying how the present_value() is computed but we are not updating the portfolio with this new computation
Finally added. If finally you think we shouldn't, I can revert it. Commit: b760ad6
This PR is ready for review. It only needs the migration. |
I was thinking that maybe it could be useful to pass enum Prices {
Custom(Collection), // Pass a custom collection with custom prices.
FromRegistry, // Use the collection from the registry (it means from oracles). Standard behavior
UsingLinearAccrual, // Use prices computed from `settlement_prices` with linear accrual. It can be useful if the collection is outdated and you want to pass "orientative" prices.
} WDYT? (would be in a following PR to not mix too many things here) |
I would pass prices and stuff to a different api. |
I am not following. Do you mean to add a new extrinsic for faking prices? And leave the |
no, I meant another runtime-api. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two changes I would like to see, but not blocking.
Will the adaption of the runtime-api to not error out happen in another PR?
/// - If not set, then the price is a linear accrual using the latest | ||
/// settlement price. | ||
/// See [`ExternalActivePricing::current_price()`] | ||
pub current_price: Option<T::Balance>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lemunozm can we remove that one here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As always, looks really clean! I would like the migration to be done via OnRuntimeUpgrade
instead of the current hooks
approach.
pub fn present_value_cached<Prices>( | ||
&self, | ||
cache: &Prices, | ||
maturity: Seconds, | ||
) -> Result<T::Balance, DispatchError> | ||
where | ||
Prices: DataCollection<T::PriceId, Data = PriceOf<T>>, | ||
{ | ||
let price = match cache.get(&self.info.price_id) { | ||
Ok(data) => data.0, | ||
Err(_) => self.latest_settlement_price, | ||
Err(_) => self.linear_accrual_price(maturity)?, | ||
}; | ||
Ok(self.outstanding_quantity.ensure_mul_int(price)?) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Say since last epoch execution, no loan price was updated. IIUC, this PR does not affect the update_portfolio
outcome. Asking because the PoolFees NAV is dependent on the Loans NAV.
Thanks! I guess you then agree with the two open threads @mustermeiszer |
Description
Fixes #1738
Changes and Descriptions
current_price
to RuntimeAPI loans portfolio for cases where the loan is external priced.T::PriceRegistry::collection()
fails due to outdated collection.Add UT for this case(Not added but fixed current failing test because of these changes)settlement_price_updated
field.