-
Notifications
You must be signed in to change notification settings - Fork 11
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
Bug fix: kickWithDeposit
likely push LUP
below HTP
affecting healthy loans
#894
Conversation
|
||
if (bucket.bankruptcyTime < lender.depositTime) vars.lenderLP = lender.lps; | ||
uint256 lenderLP = bucket.bankruptcyTime < lender.depositTime ? lender.lps : 0; | ||
uint256 bucketDeposit = Deposits.valueAt(deposits_, index_); |
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 should add a check that index_
is greater to or equal to the lup
here -- otherwise the provisional removal of the deposit would not actually lower the lup. In that case, the lender can just call removeQuoteToken
if they want
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.
3022ec8
to
586c305
Compare
586c305
to
375f52d
Compare
); | ||
// set LUP to current pool value | ||
kickResult_.lup = vars.currentLup; |
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.
Technically, this won't be correct, as the pool's debt will increase slightly. I believe to be totally correct we should recompute the LUP here including the kick penalty 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.
makes sense, though should be done for regular kick too, will add this with a commit
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.
done in _kick
function for both types of kick https://github.com/ajna-finance/contracts/pull/894/files#diff-54056532b4b7aac8940fbec13725e98ceceb358bef02e1285edad2741dff83bdR368
kickWithDeposit
to not remove any deposit and to require bond to be postedkickWithDeposit
should not remove deposits and require bond to be posted
9e61b1b
to
93d5f0f
Compare
93d5f0f
to
f38431e
Compare
kickWithDeposit
should not remove deposits and require bond to be postedkickWithDeposit
likely push LUP
below HTP
affecting collateralized loans
kickWithDeposit
likely push LUP
below HTP
affecting collateralized loanskickWithDeposit
likely push LUP
below HTP
affecting healthy loans
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.
LGTM! One suggestion to rename kickWithDeposit
to kickToRemoveDeposit
.
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.
LGTM, have a comment regarding bankruptcy
vars.bucketUnscaledDeposit = Deposits.unscaledValueAt(deposits_, index_); | ||
vars.bucketScale = Deposits.scale(deposits_, index_); | ||
vars.bucketDeposit = Maths.wmul(vars.bucketUnscaledDeposit, vars.bucketScale); | ||
vars.lenderLP = bucket.bankruptcyTime < lender.depositTime ? lender.lps : 0; |
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.
kickWithDeposit
could be called in the same block as bucket bankruptcy. It would use lender.lps
even though the bucket is bankrupt. Recommend adding a revert like we have in moveQuoteToken
->
// cannot move in the same block when target bucket becomes insolvent
if (vars.toBucketBankruptcyTime == block.timestamp) revert BucketBankruptcyBlock();`
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.
if bucket bankruptcy happens in same block but after kick with deposit is called then vars.lenderLP
will be 0 making entitled amount to be 0 and tx to revert with InsufficientLiquidity
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 was thinking before, what if a bucket bankruptcy occurs in the same block but before kickWithDeposit
is called.
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 don't think block when kick happens is the constraint here but the block / time of last deposit?
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 was misinterpretting the logic...
if bucket.bankruptcyTime < lender.depositTime ? lender.lps : 0;
-> if the bucket was bankrupted in the same block this would be 0 as it should be.
All good : )
a733350
to
8843778
Compare
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.
LGTM
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.
lgtm
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 do not understand the gas numbers in the report. Why is there a kickWithDeposit
post-change, and why did gas cost increase?
Otherwise LGTM.
index_, | ||
vars.amountToDebitFromDeposit, | ||
vars.redeemedLP, | ||
kickResult_.lup |
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.
Quite happy to eliminate all this logic.
|
||
_assertPool( | ||
PoolParams({ | ||
htp: 0, | ||
lup: 0.000000099836282890 * 1e18, | ||
poolSize: 8_002.290256823112434920 * 1e18, | ||
poolSize: 8_083.134379679494060567 * 1e18, |
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.
Makes sense because bond isn't coming out of deposit. Confirmed old pool size + bond escrowed (line 486) = new pool size.
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.
LGTM
This PR also fix the issue where LUP wasn't recalculated after kick (that is with new debt including kick penalty) which is now done in Post |
Description of change
High level
Current approach removes deposits but since it performs a remove-quote-token like action is lacking check to:
LUP
belowHTP
Without these changes, after kicking max loan
LUP
would likely fall belowHTP
hence drawing many more loans undercolalteralized / kickable, which is not desired.Introducing these changes renders function unusable as in most cases one of the two reverts would kick in.
New simplified approach of kick with deposit function (renamed to
lenderKick
):LUP
and no remove-quote-token like check required.LUP
(hence kickable)._kick
procedure as regular kick (with entitled amount as additional debt)Additionally, the
LUP
was not recalculated in order to include additional kick penalty debt.Description of bug or vulnerability and solution
kickWithDeposit
likely pushLUP
belowHTP
affecting healthy loanskickWithDeposit
remove logic to remove from depositsPriceBelowLUP
if bucket price is lower than current LUP - in this case lender should callremoveQuoteToken
functionLP
) and caped by bucket deposit sizeInsufficientLiquidity
if calculated entitled amount is 0_kick
function passing entitled amount as additional debt to be used when proposedLUP
is calculated. Same logic applies, if deposit is not enough to render loan undercollateralized then tx reverts withBorrowerOk
error_kick
function recalculateLUP
including debt resulted from kick penalty (for both regular kick and kick with deposit actions) - introducedKickResult.poolDebt
struct member, returned and used inPool
contractRemoveQuoteToken
event emitted bykickWithDeposit
QT3
invariant updated to reflect that bonds are always guaranteed (previously this invariant failed when using deposits to cover bonds in a pool without enough liquidity)_kickWithDeposit
changed to receive only the bond amount (that should be transferred from kicker) and to removeRemoveQuoteToken
emit checkContract size
Pre Change
Post Change
Gas usage
Pre Change
Post Change