-
Notifications
You must be signed in to change notification settings - Fork 17
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
Apply and mint interest #85
Conversation
Rebasing apply_and_mint_interest on top of trove_ERC721.
a68384f
to
2e111ce
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.
My first batch of comments. Mostly I think I would try to refactor a bit, so that we unify calls to the ActivePool
and consolidate all the logic there, but not sure if that’s possible, or if the result would have a lot of if-else
that would make things worse.
// It does *not* include the Trove's individual accrued interest - this gets accounted for in the aggregate accrued interest. | ||
// The net Trove debt change could be positive or negative in a repayment (depending on whether its redistribution gain or repayment amount is larger), | ||
// so this function accepts both the increase and the decrease to avoid using (and converting to/from) signed ints. | ||
function mintAggInterest(uint256 _troveDebtIncrease, uint256 _troveDebtDecrease) public { |
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 it would be a good idea to merge this function with the ones for G (increase/decrease recorded debt).
At least the external
end point (we can keep internally the functions as they are). For 2 reasons:
- Gas efficiency (only 1 call)
- Less prone to error, to make sure both trackers are consistent.
I wonder if we could even haveS
there too.
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 I see there are calls with (0,0)
as argument, maybe we could have a public
function mintAggInterestNoDebtChange
that would be called by the more generic mintAggInterest
which also calls the increaseBoldDebt
and decreaseBoldDebt
.
This generic one could also accept the accrued interest as a parameter, to update S
if non-zero.
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've refactored the D, G and S updates into a single call in this PR. Let me know what you think. It's still a bit unintuitive. This should get simpler if/when we optimize redistribution gains - then we can just update each tracker once with all the changes (debt change, accrued interest, pending gains).
contracts/src/BorrowerOperations.sol
Outdated
|
||
vars.BoldFee; | ||
vars.netDebt = _boldAmount; | ||
vars.BoldFee; // TODO |
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.
This can be removed, right? Or is it for the initial period pre-payment?
} | ||
|
||
// --- Effects & interactions --- | ||
|
||
contractsCache.activePool.mintAggInterest(vars.compositeDebt, 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.
Even if we don’t merge the endpoints, I would put the 3 calls to ActivePool
together in this function.
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.
Some more minor comments and doubts I had left for TroveManager.
return Troves[_troveId].lastDebtUpdateTime; | ||
} | ||
|
||
function troveIsStale(uint256 _troveId) external view returns (bool) { |
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 is this used for?
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.
Currently only in Foundry tests - so it doesn't strictly need to be in core contracts, though I recall the ToB audit recommending we make convenience getters like this part of the core system. I don't mind removing it though if you prefer.
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.
No, it’s fine then. It will only mean some little amount of gas for us deploying, so let’s leave it if it’s useful.
What was making me wonder is that the constant for the stale time is not used anywhere else, right? So this getter seems like meaningless or arbitrary. I want to make sure I’m not missing anything.
@@ -74,7 +77,8 @@ contract TroveManager is ERC721, LiquityBase, Ownable, CheckContract, ITroveMana | |||
uint stake; | |||
Status status; | |||
uint128 arrayIndex; | |||
uint256 annualInterestRate; | |||
uint256 annualInterestRate; | |||
uint64 lastDebtUpdateTime; |
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 just moving lastDebtUpdateTime
one position up would save gas, as it would packed with status
and arrayIndex
. And we wouldn’t touch the original v1 vars.
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.
Nice, sounds good
@@ -475,6 +500,8 @@ contract TroveManager is ERC721, LiquityBase, Ownable, CheckContract, ITroveMana | |||
( |
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.
Unrelated to this PR, but it seems that the comment “..., and close the trove” above is outdated. We may take the opportunity to fix it.
contracts/src/TroveManager.sol
Outdated
|
||
// TODO - Gas: combine these into one call to activePool? | ||
// Remove the liquidated recorded debt from the sum | ||
activePoolCached.decreaseRecordedDebtSum(totals.totalRecordedDebtInSequence); |
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.
According to the spec, aren’t we missing redistribution gains 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.
Yes, I think you're right. Good catch!
|
||
return (currentETH, currentBoldDebt); | ||
} | ||
|
||
function applyPendingRewards(uint256 _troveId) external override { |
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.
Are we removing the override
for any particular reason?
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 no that's an oversight (I guess you mean in the new getAndApplyRedistributionGains
). Added it back in.
contracts/src/TroveManager.sol
Outdated
Troves[_troveId].coll = Troves[_troveId].coll + pendingETHReward; | ||
Troves[_troveId].debt = Troves[_troveId].debt + pendingBoldDebtReward; | ||
|
||
_updateTroveRewardSnapshots(_troveId); | ||
|
||
// Transfer from DefaultPool to ActivePool | ||
//TODO: Update agg. recorded debt and agg. weighted debt sum with the redistribution gains |
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’s the point of this? Is it just to have more up to date values? This function is inside a loop in redeemCollateral
, so that may not be so efficient.
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.
Hmm AFAIK this is a relic and not relevant. I'll delete. As mentioned above, eventually we would hopefully do away with separately applying redist. gains, and update the trackers with all changes in one go.
contracts/src/TroveManager.sol
Outdated
entireColl = recordedColl + pendingETHReward; | ||
} | ||
|
||
function getTroveEntireDebt(uint256 _troveId) public view returns (uint256) { |
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.
No big deal, but these ones can be converted to external
.
Rebase of branch from #76 on top of branch from #81
We now have 3 aggregate trackers on the ActivePool, as per the simple compounding specification:
aggRecordedDebt (D)
recordedDebtSum (G)
weightedRecordedDebtSum (S)
G
is the original ActivePool debt tracker from Liquity v1. We keep it for now as a) it may be useful for computing a size-weighted average interest rate on the front end, and b) would be needed if we decide to add an emergency base interest rate to every position.Pseudocode for aggregate trackers in different operations
As in v1, we always apply any redistribution debt gain before handling interest accounting.
The redistribution gain is already included in G before we alter G from the specific operation.
The prefix “old” means the respective debt with no redistribution gains or interest applied, and “new” implies all debt changes (redist. gains, interest, debt drawn/repaid) are included.
openTrove:
closeTrove:
adjustTrove:
And for the individual Trove:
new_recorded_trove_debt = old_recorded_trove_debt + accrued_trove_interest + trove_debt_change
applyTroveInterestPermissionless:
adjustTroveInterestRate:
SP deposit/withdrawal:
D += agg_accrued_interest
Liquidation - Normal Mode, offset
This is effectively the same as closing the Trove:
Liquidation - Normal Mode, redistribution:
This is effectively the same as closing the Trove, except we add the entire debt to the DefaultPool:
Also:
DefaultPool.debt += (old_recorded_trove_debt + redistribution_gain + accrued_trove_interest)
TODOs:
** Liquidations in Recovery Mode**
Minting/applying interest has been implemented for RM liquidations to make tests pass, but if we keep RM we should double-check that minting/applying interest is correct for for every logical case of RM.
Redemption:
This is effectively a downward debt adjustment (since we will no longer close Troves on redemption):
This will be implemented in combination with #55 and #48, since these significantly change redemption logic anyway.
Testing TODOs:
D + S*delta_t == sum_individual_entire_trove_debts
)