Skip to content

Commit

Permalink
Calculate t0Debt2ToCollateral ratio only for loans not in auction (#…
Browse files Browse the repository at this point in the history
…758)

* Calculate t0Debt2ToCollateral ratio only for loans not in auction:
- drawDebt/repayDebt: check if loan not in auction. If not in auction check if auction settled by pledge collateral/repay action and if so calculate t0Debt2ToCollateral ratio considering debt and collateral pre action as 0
- take/bucketTake: check if loan settled by take action and if so calculate t0Debt2ToCollateral ratio considering debt and collateral pre action as 0
- kick/kickWithDeposit: always calculate t0Debt2ToCollateral ratio considering debt and collateral post action as 0 (as loan will enter in auction queue)
settle: do not calculate t0Debt2ToCollateral ratio as debt and collateral pre settle are not taken into account (loan still auctioned) and loan is removed from auction queue only when there's no more debt (post debt = 0)

- return inAuction flag in DrawDebtResult/RepayDebtResult structs (to be used when checking if loan in auction) and remove inAuction member from local vars structs

Additional fix: on forgiveBadDebt emit BucketBankruptcy before forfeiting LP from bucket, otherwise event will always be emitted with 0. Added unit test to ensure this

Reduce optimizer runs to 50 to fit contract size limit

* Fix I4 invariant to account only borrowers that are not in auction

* Include t0debtInAuction in PoolState struct so to make it available when interest rate is calcualted.
Consistent order of updates:
- in memory pool state struct
- update t0Debt2ToCollateral ratio state
- update pool balances state
- update interest rate state

* Introduce Pool helper functions to save state
- post take/bucketTake action (Use single struct for take/bucketTake result)
- post settle action
Use helper functions in both ERC20 and ERC721 pools

Less duplicate code, smaller contract size, bumped optimizer runs to 500

* Use nonAuctionedT0Debt to calculate EMAs and interest rate

* More tests fix

* Fix deposit take unit tests

* fixes for baselines

* Add NATSpec to _meaningfulDeposit function
Gas optimization: use PoolState.t0DebtInAuction for `_revertIfAuctionDebtLocked` param

* Changes after review: nit space alignment

* T0 debt2 to collateral ema init fix (#760)

* Fix for initialization of emas checking lastUpdateTime, and some baseline fixes.  29 tests failing

* Fix tests

* Check for EMA init only once

---------

Co-authored-by: mwc <[email protected]>
Co-authored-by: grandizzy <[email protected]>

* Changes after review: style

---------

Co-authored-by: mwc <[email protected]>
Co-authored-by: mattcushman <[email protected]>
  • Loading branch information
3 people authored Apr 24, 2023
1 parent 2b31b19 commit 48791b5
Show file tree
Hide file tree
Showing 42 changed files with 855 additions and 850 deletions.
2 changes: 1 addition & 1 deletion brownie-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ compiler:
version: 0.8.14
optimizer:
enabled: true
runs: 100
runs: 500
remappings:
- "@ds-math=lib/ds-math/src/"
- "@openzeppelin/contracts=lib/openzeppelin-contracts/contracts"
Expand Down
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ block_number = 16_295_000
fork_block_number = 16_295_000
rpc_storage_caching = { chains = ["mainnet"], endpoints = "all" }
optimizer = true
optimizer_runs = 100
optimizer_runs = 500

[fuzz]
runs = 300
Expand Down
132 changes: 44 additions & 88 deletions src/ERC20Pool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import {

import {
DrawDebtResult,
BucketTakeResult,
RepayDebtResult,
SettleParams,
SettleResult,
Expand Down Expand Up @@ -125,6 +124,7 @@ contract ERC20Pool is FlashloanablePool, IERC20Pool {
* @dev - decrement `poolBalances.t0DebtInAuction` accumulator
* @dev - increment `poolBalances.pledgedCollateral` accumulator
* @dev - increment `poolBalances.t0Debt` accumulator
* @dev - update `t0Debt2ToCollateral` ratio only if loan not in auction, debt and collateral pre action are considered 0 if auction settled
* @dev === Emit events ===
* @dev - `DrawDebt`
*/
Expand Down Expand Up @@ -153,34 +153,39 @@ contract ERC20Pool is FlashloanablePool, IERC20Pool {

emit DrawDebt(borrowerAddress_, amountToBorrow_, collateralToPledge_, result.newLup);

// adjust t0Debt2ToCollateral ratio
_updateT0Debt2ToCollateral(
result.debtPreAction,
result.debtPostAction,
result.collateralPreAction,
result.collateralPostAction
);

// update pool interest rate state
// update in memory pool state struct
poolState.debt = result.poolDebt;
poolState.t0Debt = result.t0PoolDebt;
if (result.t0DebtInAuctionChange != 0) poolState.t0DebtInAuction -= result.t0DebtInAuctionChange;
poolState.collateral = result.poolCollateral;

// adjust t0Debt2ToCollateral ratio if loan not in auction
if (!result.inAuction) {
_updateT0Debt2ToCollateral(
result.settledAuction ? 0 : result.debtPreAction, // debt pre settle (for loan in auction) not taken into account
result.debtPostAction,
result.settledAuction ? 0 : result.collateralPreAction, // collateral pre settle (for loan in auction) not taken into account
result.collateralPostAction
);
}

// update pool interest rate state
_updateInterestState(poolState, result.newLup);

if (collateralToPledge_ != 0) {
// update pool balances state
if (result.t0DebtInAuctionChange != 0) {
poolBalances.t0DebtInAuction -= result.t0DebtInAuctionChange;
poolBalances.t0DebtInAuction = poolState.t0DebtInAuction;
}
poolBalances.pledgedCollateral += collateralToPledge_;
poolBalances.pledgedCollateral = poolState.collateral;

// move collateral from sender to pool
_transferCollateralFrom(msg.sender, collateralToPledge_);
}

if (amountToBorrow_ != 0) {
// update pool balances state
poolBalances.t0Debt = result.t0PoolDebt;
poolBalances.t0Debt = poolState.t0Debt;

// move borrowed amount from pool to sender
_transferQuoteToken(msg.sender, amountToBorrow_);
Expand All @@ -193,6 +198,7 @@ contract ERC20Pool is FlashloanablePool, IERC20Pool {
* @dev - decrement `poolBalances.t0Debt accumulator`
* @dev - decrement `poolBalances.t0DebtInAuction accumulator`
* @dev - decrement `poolBalances.pledgedCollateral accumulator`
* @dev - update `t0Debt2ToCollateral` ratio only if loan not in auction, debt and collateral pre action are considered 0 if auction settled
* @dev === Emit events ===
* @dev - `RepayDebt`
*/
Expand Down Expand Up @@ -223,33 +229,38 @@ contract ERC20Pool is FlashloanablePool, IERC20Pool {

emit RepayDebt(borrowerAddress_, result.quoteTokenToRepay, collateralAmountToPull_, result.newLup);

// adjust t0Debt2ToCollateral ratio
_updateT0Debt2ToCollateral(
result.debtPreAction,
result.debtPostAction,
result.collateralPreAction,
result.collateralPostAction
);

// update pool interest rate state
// update in memory pool state struct
poolState.debt = result.poolDebt;
poolState.t0Debt = result.t0PoolDebt;
if (result.t0DebtInAuctionChange != 0) poolState.t0DebtInAuction -= result.t0DebtInAuctionChange;
poolState.collateral = result.poolCollateral;

// adjust t0Debt2ToCollateral ratio if loan not in auction
if (!result.inAuction) {
_updateT0Debt2ToCollateral(
result.settledAuction ? 0 : result.debtPreAction, // debt pre settle (for loan in auction) not taken into account
result.debtPostAction,
result.settledAuction ? 0 : result.collateralPreAction, // collateral pre settle (for loan in auction) not taken into account
result.collateralPostAction
);
}

// update pool interest rate state
_updateInterestState(poolState, result.newLup);

if (result.quoteTokenToRepay != 0) {
// update pool balances state
poolBalances.t0Debt = result.t0PoolDebt;
poolBalances.t0Debt = poolState.t0Debt;
if (result.t0DebtInAuctionChange != 0) {
poolBalances.t0DebtInAuction -= result.t0DebtInAuctionChange;
poolBalances.t0DebtInAuction = poolState.t0DebtInAuction;
}

// move amount to repay from sender to pool
_transferQuoteTokenFrom(msg.sender, result.quoteTokenToRepay);
}
if (collateralAmountToPull_ != 0) {
// update pool balances state
poolBalances.pledgedCollateral = result.poolCollateral;
poolBalances.pledgedCollateral = poolState.collateral;

// move collateral from pool to address specified as collateral receiver
_transferCollateral(collateralReceiver_, collateralAmountToPull_);
Expand Down Expand Up @@ -337,6 +348,8 @@ contract ERC20Pool is FlashloanablePool, IERC20Pool {
* @dev - decrement `poolBalances.t0Debt` accumulator
* @dev - decrement `poolBalances.t0DebtInAuction` accumulator
* @dev - decrement `poolBalances.pledgedCollateral` accumulator
* @dev - no update of `t0Debt2ToCollateral` ratio as debt and collateral pre settle are not taken into account (pre debt and pre collateral = 0)
* @dev and loan is removed from auction queue only when there's no more debt (post debt = 0)
*/
function settle(
address borrowerAddress_,
Expand All @@ -358,24 +371,7 @@ contract ERC20Pool is FlashloanablePool, IERC20Pool {
})
);

// update pool balances state
poolBalances.t0Debt -= result.t0DebtSettled;
poolBalances.t0DebtInAuction -= result.t0DebtSettled;
poolBalances.pledgedCollateral -= result.collateralSettled;

// adjust t0Debt2ToCollateral ratio
_updateT0Debt2ToCollateral(
result.debtPreAction,
result.debtPostAction,
result.collateralPreAction,
result.collateralRemaining
);

// update pool interest rate state
poolState.debt -= Maths.wmul(result.t0DebtSettled, poolState.inflator);
poolState.t0Debt -= result.t0DebtSettled;
poolState.collateral -= result.collateralSettled;
_updateInterestState(poolState, Deposits.getLup(deposits, poolState.debt));
_updatePostSettleState(result, poolState);
}

/**
Expand All @@ -384,6 +380,7 @@ contract ERC20Pool is FlashloanablePool, IERC20Pool {
* @dev - decrement `poolBalances.t0Debt` accumulator
* @dev - decrement `poolBalances.t0DebtInAuction` accumulator
* @dev - decrement `poolBalances.pledgedCollateral` accumulator
* @dev - update `t0Debt2ToCollateral` ratio only if auction settled, debt and collateral pre action are considered 0
*/
function take(
address borrowerAddress_,
Expand Down Expand Up @@ -411,28 +408,7 @@ contract ERC20Pool is FlashloanablePool, IERC20Pool {
// round quote token up to cover the cost of purchasing the collateral
result.quoteTokenAmount = _roundUpToScale(result.quoteTokenAmount, _getArgUint256(QUOTE_SCALE));

// update pool balances state
uint256 t0DebtInAuction = poolBalances.t0DebtInAuction;
t0DebtInAuction += result.t0DebtPenalty;
t0DebtInAuction -= result.t0DebtInAuctionChange;

poolBalances.t0Debt = result.t0PoolDebt;
poolBalances.t0DebtInAuction = t0DebtInAuction;
poolBalances.pledgedCollateral -= result.collateralAmount;

// adjust t0Debt2ToCollateral ratio
_updateT0Debt2ToCollateral(
result.debtPreAction,
result.debtPostAction,
result.collateralPreAction,
result.collateralPostAction
);

// update pool interest rate state
poolState.debt = result.poolDebt;
poolState.t0Debt = result.t0PoolDebt;
poolState.collateral -= result.collateralAmount;
_updateInterestState(poolState, result.newLup);
_updatePostTakeState(result, poolState);

_transferCollateral(callee_, result.collateralAmount);

Expand All @@ -453,6 +429,7 @@ contract ERC20Pool is FlashloanablePool, IERC20Pool {
* @dev - decrement `poolBalances.t0Debt` accumulator
* @dev - decrement `poolBalances.t0DebtInAuction` accumulator
* @dev - decrement `poolBalances.pledgedCollateral` accumulator
* @dev - update `t0Debt2ToCollateral` ratio only if auction settled, debt and collateral pre action are considered 0
*/
function bucketTake(
address borrowerAddress_,
Expand All @@ -462,7 +439,7 @@ contract ERC20Pool is FlashloanablePool, IERC20Pool {

PoolState memory poolState = _accruePoolInterest();

BucketTakeResult memory result = TakerActions.bucketTake(
TakeResult memory result = TakerActions.bucketTake(
auctions,
buckets,
deposits,
Expand All @@ -474,28 +451,7 @@ contract ERC20Pool is FlashloanablePool, IERC20Pool {
_bucketCollateralDust(0)
);

// update pool balances state
uint256 t0DebtInAuction = poolBalances.t0DebtInAuction;
t0DebtInAuction += result.t0DebtPenalty;
t0DebtInAuction -= result.t0DebtInAuctionChange;

poolBalances.t0Debt = result.t0PoolDebt;
poolBalances.t0DebtInAuction = t0DebtInAuction;
poolBalances.pledgedCollateral -= result.collateralAmount;

// adjust t0Debt2ToCollateral ratio
_updateT0Debt2ToCollateral(
result.debtPreAction,
result.debtPostAction,
result.collateralPreAction,
result.collateralPostAction
);

// update pool interest rate state
poolState.debt = result.poolDebt;
poolState.t0Debt = result.t0PoolDebt;
poolState.collateral -= result.collateralAmount;
_updateInterestState(poolState, result.newLup);
_updatePostTakeState(result, poolState);
}

/***************************/
Expand Down
Loading

0 comments on commit 48791b5

Please sign in to comment.