-
Notifications
You must be signed in to change notification settings - Fork 22
feat: lending minimum loan #6155
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
base: main
Are you sure you want to change the base?
Conversation
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the ✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
fc5c46e
to
a8cd6be
Compare
1daee51
to
ab3dd07
Compare
ab3dd07
to
c0bfb53
Compare
|
||
use crate::LENDING_DEFAULT_CONFIG as CONFIG; | ||
/// Default config with minimum loan/update amounts set to zero | ||
fn config() -> LendingConfiguration { |
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.
Why does this have to be a function? You could still keep it as CONFIG
constant iniialising it to
LendingConfiguration {
// Set the loan minimums to zero by default for tests
minimum_loan_amount_usd: 0,
minimum_update_loan_amount_usd: 0,
..LENDING_DEFAULT_CONFIG
}
Then most of the rest of the test code wouldn't need to change.
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 did try this already, it has an error:
destructor of
general_lending::LendingConfiguration cannot be evaluated at compile-time
.
Seems like it should be possible but i'm not sure how to so it.
fn test_loan_minimum_is_enforced() { | ||
const MIN_LOAN_AMOUNT_USD: AssetAmount = 1_000; | ||
const MIN_LOAN_AMOUNT_ASSET: AssetAmount = MIN_LOAN_AMOUNT_USD / SWAP_RATE; | ||
const COLLATERAL_ASSET: Asset = Asset::Eth; |
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 would just use the global COLLATERAL_ASSET
(which also happens to be Asset::Eth). Otherwise re-defining it makes it look like the asset is important.
|
||
T::Balance::credit_account(borrower_id, loan_asset, excess_amount); | ||
} else { | ||
let config = LendingConfig::<T>::get(); |
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.
Should probably read config once at the top.
pub fee_swap_max_oracle_slippage: BasisPoints, | ||
/// If set for a pool/asset, this configuration will be used instead of the default | ||
pub pool_config_overrides: BTreeMap<Asset, LendingPoolConfiguration>, | ||
/// Minimum amount of principle that a loan must have at all times. |
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.
/// Minimum amount of principle that a loan must have at all times. | |
/// Minimum amount of principal that a loan must have at all times. |
You will need to update |
86f8adb
to
0469763
Compare
|
||
const ORIGINATION_FEE: AssetAmount = | ||
portion_of_amount(DEFAULT_ORIGINATION_FEE, PRINCIPAL) * SWAP_RATE; | ||
let origination_fee = CONFIG.origination_fee(LOAN_ASSET) * PRINCIPAL * SWAP_RATE; |
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.
What was the reason for this change?
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.
left over from when config was not const. I will revert it.
let mut total_collateral_usd = 0; | ||
for (asset, amount) in assets_amounts { | ||
total_collateral_usd = | ||
total_collateral_usd.saturating_add(usd_value_of::<T>(*asset, *amount)?); |
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.
You can use saturating_accrue
if repayment_amount < loan.owed_principal { | ||
ensure!( | ||
repayment_amount >= | ||
amount_from_usd_value::<T>( |
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.
IMO using usd_value_of
here and below would be more natural (e.g. it is slightly more efficient as it doesn't need to invert the price).
/// All fee swaps from lending will be executed with this oracle slippage limit | ||
pub fee_swap_max_oracle_slippage: BasisPoints, | ||
/// Minimum equivalent amount of principal that a loan must have at all times. | ||
pub minimum_loan_amount_usd: AssetAmount, |
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 want all amounts to be in U256 (so they are encoded as hex). See how it is done for liquidation_swap_chunk_size_usd
.
9ea4a43
to
e4dda45
Compare
b99f2df
to
403b6c2
Compare
f3aa026
to
f97ebaa
Compare
f97ebaa
to
599839a
Compare
|
||
loan.owed_principal.saturating_accrue(extra_principal); | ||
|
||
ensure!( |
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 this should be done in new_loan
rather than expand_loan
? I know this covers an additional edge case where we have a small loan to begin with, but not sure if we should be preventing the user from addint to a small loan if we already have it (it is not making anything worse). Then putting it in new_loan
would look more natural.
Error::<T>::LiquidationInProgress | ||
); | ||
|
||
let total_collateral_usd = total_usd_value_of::<T>(&collateral)?; |
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.
Would it be better to simply check collateral == loan_account.collateral
instead of calculating total usd value of loan_account.collateral
? I know it won't make a big difference performance wise, but from readability standopint I think it would be an improvement.
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 for which collateral asset do we check? it could be any of them, and checking each to see if its below the loans corresponding collateral asset would change the behaviour.
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.
So the current/desired behaviour is to ensure that the value of the collateral removed is at least minimum_update_collateral_amount_usd
, but we make an exception for the case where the user wants to remove all collateral, right? What I'm suggesting is that we can check if the exception rule applies by comparing the map of assets provided to loan_account.collateral
instead of computing their values. You still need to compute the value of added collateral in the non-exceptional case of course.
However, this does make be think that we might want to interpret empty collateral
as "withdraw everything" (it might be tricky to provide the exact amount considering that we charge interest).
#[pallet::storage] | ||
pub type LendingConfig<T: Config> = | ||
StorageValue<_, LendingConfiguration, ValueQuery, LendingConfigDefault>; | ||
pub type LendingConfig<T: Config> = StorageValue<_, LendingConfiguration, ValueQuery>; |
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.
We discussed this before I believe. Do we need this change? I think I'd rather provide LendingConfigDefault here explicitly rather than implementing Default which seems like it is not needed anywhere else.
Pull Request
Closes: PRO-2545
Checklist
Please conduct a thorough self-review before opening the PR.
Summary
To prevent spam, we have added 3 new minimums in the config:
minimum_loan_amount_usd
: Minimum equivalent amount of principal that a loan must be left with after expanding or repaying (unless fully repaying).minimum_update_loan_amount_usd
: Minimum equivalent amount of principal that can be used to expand or repay an existing loan (unless fully repaying).minimum_update_collateral_amount_usd
: Minimum equivalent amount of collateral that can be added or removed from a loan account (unless fully removing).Added tests to cover all new code. Added to the config RPC. Added to the update config extrinsic.