Skip to content

Commit

Permalink
Memorialize borrower threshold price on kick (#976)
Browse files Browse the repository at this point in the history
* Memorialize borrower threshold price at time of kick to calculate bpf on take

* Fix tests

* Record borrower threshold price inside _recordAuction method

* Remove redundant conversions

* Fix natspec

* Fix unit tests

* Remove redundant variable
  • Loading branch information
prateek105 committed Nov 17, 2023
1 parent d10936d commit b59a93b
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 63 deletions.
1 change: 1 addition & 0 deletions src/interfaces/pool/commons/IPoolState.sol
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ struct Liquidation {
address next; // next liquidated borrower in auctions queue
uint160 bondSize; // [WAD] liquidation bond size
uint96 neutralPrice; // [WAD] Neutral Price when liquidation was started
uint256 thresholdPrice; // [WAD] Threshold Price when liquidation was started
}

/// @dev Struct holding kicker state.
Expand Down
11 changes: 9 additions & 2 deletions src/libraries/external/KickerActions.sol
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ library KickerActions {
uint256 referencePrice; // [WAD] used to calculate auction start price
uint256 bondFactor; // [WAD] bond factor of kicked auction
uint256 bondSize; // [WAD] bond size of kicked auction
uint256 thresholdPrice; // [WAD] borrower threshold price at kick time
}

/// @dev Struct used for `lenderKick` function local vars.
Expand Down Expand Up @@ -321,6 +322,8 @@ library KickerActions {
borrower.npTpRatio
);

vars.thresholdPrice = Maths.wdiv(vars.borrowerDebt, vars.borrowerCollateral);

// record liquidation info
_recordAuction(
auctions_,
Expand All @@ -329,7 +332,8 @@ library KickerActions {
vars.bondSize,
vars.bondFactor,
vars.referencePrice,
vars.neutralPrice
vars.neutralPrice,
vars.thresholdPrice
);

// update escrowed bonds balances and get the difference needed to cover bond (after using any kick claimable funds if any)
Expand Down Expand Up @@ -390,6 +394,7 @@ library KickerActions {
* @param bondFactor_ Bond factor of the newly kicked auction.
* @param referencePrice_ Used to calculate auction start price.
* @param neutralPrice_ Current pool `Neutral Price`.
* @param thresholdPrice_ Borrower threshold price.
*/
function _recordAuction(
AuctionsState storage auctions_,
Expand All @@ -398,7 +403,8 @@ library KickerActions {
uint256 bondSize_,
uint256 bondFactor_,
uint256 referencePrice_,
uint256 neutralPrice_
uint256 neutralPrice_,
uint256 thresholdPrice_
) internal {
// record liquidation info
liquidation_.kicker = msg.sender;
Expand All @@ -407,6 +413,7 @@ library KickerActions {
liquidation_.bondSize = SafeCast.toUint160(bondSize_);
liquidation_.bondFactor = SafeCast.toUint96(bondFactor_);
liquidation_.neutralPrice = SafeCast.toUint96(neutralPrice_);
liquidation_.thresholdPrice = thresholdPrice_;

// increment number of active auctions
++auctions_.noOfAuctions;
Expand Down
7 changes: 1 addition & 6 deletions src/libraries/external/TakerActions.sol
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,6 @@ library TakerActions {
liquidation,
0,
borrower_.t0Debt,
borrower_.collateral,
params_.inflator
);

Expand Down Expand Up @@ -431,7 +430,6 @@ library TakerActions {
liquidation,
_priceAt(params_.index),
borrower_.t0Debt,
borrower_.collateral,
params_.inflator
);

Expand Down Expand Up @@ -683,15 +681,13 @@ library TakerActions {
* @param liquidation_ Liquidation struct holding auction details.
* @param bucketPrice_ Price of the bucket, or 0 for non-bucket takes.
* @param t0Debt_ Borrower t0 debt.
* @param collateral_ Borrower collateral.
* @param inflator_ The pool's inflator, used to calculate borrower debt.
* @return vars The prepared vars for take action.
*/
function _prepareTake(
Liquidation memory liquidation_,
uint256 bucketPrice_,
uint256 t0Debt_,
uint256 collateral_,
uint256 inflator_
) internal view returns (TakeLocalVars memory vars) {

Expand All @@ -708,8 +704,7 @@ library TakerActions {
vars.bucketPrice = bucketPrice_;
vars.bondFactor = liquidation_.bondFactor;
vars.bpf = _bpf(
vars.borrowerDebt,
collateral_,
liquidation_.thresholdPrice,
neutralPrice,
liquidation_.bondFactor,
bucketPrice_ == 0 ? vars.auctionPrice : bucketPrice_
Expand Down
20 changes: 8 additions & 12 deletions src/libraries/helpers/PoolHelper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -400,32 +400,28 @@ import { Maths } from '../internal/Maths.sol';
/**
* @notice Calculates bond penalty factor.
* @dev Called in kick and take.
* @param debt_ Borrower debt.
* @param collateral_ Borrower collateral.
* @param neutralPrice_ `NP` of auction.
* @param bondFactor_ Factor used to determine bondSize.
* @param auctionPrice_ Auction price at the time of call or, for bucket takes, bucket price.
* @return bpf_ Factor used in determining bond `reward` (positive) or `penalty` (negative).
* @param thresholdPrice_ Borrower tp at time of kick.
* @param neutralPrice_ `NP` of auction.
* @param bondFactor_ Factor used to determine bondSize.
* @param auctionPrice_ Auction price at the time of call or, for bucket takes, bucket price.
* @return bpf_ Factor used in determining bond `reward` (positive) or `penalty` (negative).
*/
function _bpf(
uint256 debt_,
uint256 collateral_,
uint256 thresholdPrice_,
uint256 neutralPrice_,
uint256 bondFactor_,
uint256 auctionPrice_
) pure returns (int256) {
int256 thresholdPrice = int256(Maths.wdiv(debt_, collateral_));

int256 sign;
if (thresholdPrice < int256(neutralPrice_)) {
if (thresholdPrice_ < neutralPrice_) {
// BPF = BondFactor * min(1, max(-1, (neutralPrice - price) / (neutralPrice - thresholdPrice)))
sign = Maths.minInt(
1e18,
Maths.maxInt(
-1 * 1e18,
PRBMathSD59x18.div(
int256(neutralPrice_) - int256(auctionPrice_),
int256(neutralPrice_) - thresholdPrice
int256(neutralPrice_) - int256(thresholdPrice_)
)
)
);
Expand Down
12 changes: 6 additions & 6 deletions tests/forge/unit/Auctions.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ contract AuctionsTest is DSTestPlus {
uint256 neutralPrice = 15 * 1e18;
uint256 bondFactor = 0.1 * 1e18;

assertEq(_bpf(debt, collateral, neutralPrice, bondFactor, price), 0.1 * 1e18);
assertEq(_bpf(9000 * 1e18, collateral, neutralPrice, bondFactor, price), 0.083333333333333333 * 1e18);
assertEq(_bpf(debt, collateral, neutralPrice, bondFactor, 9.5 * 1e18), 0.1 * 1e18);
assertEq(_bpf(9000 * 1e18, collateral, neutralPrice, bondFactor, 9.5 * 1e18), 0.091666666666666667 * 1e18);
assertEq(_bpf(9000 * 1e18, collateral, 10 * 1e18, bondFactor, 10.5 * 1e18), -0.05 * 1e18);
assertEq(_bpf(debt, collateral, 5 * 1e18, bondFactor, 10.5 * 1e18), -0.1 * 1e18);
assertEq(_bpf(Maths.wdiv(debt, collateral), neutralPrice, bondFactor, price), 0.1 * 1e18);
assertEq(_bpf(Maths.wdiv(9000 * 1e18, collateral), neutralPrice, bondFactor, price), 0.083333333333333333 * 1e18);
assertEq(_bpf(Maths.wdiv(debt, collateral), neutralPrice, bondFactor, 9.5 * 1e18), 0.1 * 1e18);
assertEq(_bpf(Maths.wdiv(9000 * 1e18, collateral), neutralPrice, bondFactor, 9.5 * 1e18), 0.091666666666666667 * 1e18);
assertEq(_bpf(Maths.wdiv(9000 * 1e18, collateral), 10 * 1e18, bondFactor, 10.5 * 1e18), -0.05 * 1e18);
assertEq(_bpf(Maths.wdiv(debt, collateral), 5 * 1e18, bondFactor, 10.5 * 1e18), -0.1 * 1e18);
}

/**
Expand Down
16 changes: 8 additions & 8 deletions tests/forge/unit/ERC20Pool/ERC20PoolLiquidationsArbTake.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -281,10 +281,10 @@ contract ERC20PoolLiquidationsArbTakeTest is ERC20HelperContract {
index: _i9_91,
collateralArbed: 2 * 1e18,
quoteTokenAmount: 18.919873153126569032 * 1e18,
bondChange: 0.258201596617264198 * 1e18,
bondChange: 0.258144802096036104 * 1e18,
isReward: true,
lpAwardTaker: 0.909749138101538138 * 1e18,
lpAwardKicker: 0.256861203198864400 * 1e18
lpAwardKicker: 0.256804703513158056 * 1e18
});

_assertLenderLpBalance({
Expand All @@ -296,27 +296,27 @@ contract ERC20PoolLiquidationsArbTakeTest is ERC20HelperContract {
_assertLenderLpBalance({
lender: _lender,
index: _i9_91,
lpBalance: 2_000.256861203198864400 * 1e18, // rewarded with LP in bucket
lpBalance: 2_000.256804703513158056 * 1e18, // rewarded with LP in bucket
depositTime: _startTime + 100 days + 6.5 hours
});
_assertBucket({
index: _i9_91,
lpBalance: 2_001.166610341300402538 * 1e18,
lpBalance: 2_001.166553841614696194 * 1e18,
collateral: 2 * 1e18,
deposit: 1_991.775042137166357167 * 1e18,
deposit: 1_991.774985342645129073 * 1e18,
exchangeRate: 1.005218356846837832 * 1e18
});
// reserves should remain the same after arb take
_assertReserveAuction({
reserves: 24.332908342912459160 * 1e18,
reserves: 24.332979336063994265 * 1e18,
claimableReserves : 0,
claimableReservesRemaining: 0,
auctionPrice: 0,
timeRemaining: 0
});
_assertBorrower({
borrower: _borrower,
borrowerDebt: 0.909519324691559946 * 1e18,
borrowerDebt: 0.909533523321866957 * 1e18,
borrowerCollateral: 0,
borrowert0Np: 0,
borrowerCollateralization: 0
Expand All @@ -332,7 +332,7 @@ contract ERC20PoolLiquidationsArbTakeTest is ERC20HelperContract {
referencePrice: 11.249823884323541351 * 1e18,
totalBondEscrowed: 0.296536979149981005 * 1e18,
auctionPrice: 9.459936576563284516 * 1e18,
debtInAuction: 0.909519324691559946 * 1e18,
debtInAuction: 0.909533523321866957 * 1e18,
thresholdPrice: 0,
neutralPrice: 11.249823884323541351 * 1e18
})
Expand Down
26 changes: 13 additions & 13 deletions tests/forge/unit/ERC20Pool/ERC20PoolLiquidationsTake.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -743,7 +743,7 @@ contract ERC20PoolLiquidationsTakeTest is ERC20HelperContract {
from: _lender,
borrower: _borrower2,
maxCollateral: 577 * 1e18,
bondChange: 27.337468146252670459 * 1e18,
bondChange: 27.331814713911545819 * 1e18,
givenAmount: 6_281.628773838729840580 * 1e18,
collateralTaken: 577 * 1e18,
isReward: true
Expand All @@ -755,23 +755,23 @@ contract ERC20PoolLiquidationsTakeTest is ERC20HelperContract {
borrower: _borrower2,
active: true,
kicker: _lender,
bondSize: 176.453206233100261662 * 1e18,
bondSize: 176.447552800759137022 * 1e18,
bondFactor: 0.015180339887498948 * 1e18,
kickTime: block.timestamp - 22000 seconds,
referencePrice: 11.314108592233961587 * 1e18,
totalBondEscrowed: 176.453206233100261662 * 1e18,
totalBondEscrowed: 176.447552800759137022 * 1e18,
auctionPrice: 10.886704980656377540 * 1e18,
debtInAuction: 3_653.993019025148320626 * 1e18,
thresholdPrice: 8.638281368853778535 * 1e18,
debtInAuction: 3_653.994432383233602314 * 1e18,
thresholdPrice: 8.638284710125847759 * 1e18,
neutralPrice: 11.314108592233961587 * 1e18
})
);
_assertBorrower({
borrower: _borrower2,
borrowerDebt: 3_653.993019025148320626 * 1e18,
borrowerDebt: 3_653.994432383233602314 * 1e18,
borrowerCollateral: 423.000000000000000000 * 1e18,
borrowert0Np: 9.813927120521769770 * 1e18,
borrowerCollateralization: 1.136655711572588218 * 1e18
borrowert0Np: 9.813930916531551927 * 1e18,
borrowerCollateralization: 1.136655271916324406 * 1e18
});
}

Expand Down Expand Up @@ -1129,9 +1129,9 @@ contract ERC20PoolLiquidationsTakeTest is ERC20HelperContract {
from: _lender,
borrower: _borrower2,
maxCollateral: 1_001 * 1e18,
bondChange: 43.529168844258845077 * 1e18,
givenAmount: 10_002.172770738542860841 * 1e18,
collateralTaken: 918.751154597329341626 * 1e18,
bondChange: 43.520176912520187399 * 1e18,
givenAmount: 10_002.175062202988939757 * 1e18,
collateralTaken: 918.751365080156804231 * 1e18,
isReward: true
});

Expand All @@ -1145,7 +1145,7 @@ contract ERC20PoolLiquidationsTakeTest is ERC20HelperContract {
bondFactor: 0,
kickTime: 0,
referencePrice: 0,
totalBondEscrowed: 192.644906931106436280 * 1e18,
totalBondEscrowed: 192.635914999367778602 * 1e18,
auctionPrice: 0,
debtInAuction: 0,
thresholdPrice: 0,
Expand All @@ -1155,7 +1155,7 @@ contract ERC20PoolLiquidationsTakeTest is ERC20HelperContract {
_assertBorrower({
borrower: _borrower2,
borrowerDebt: 0,
borrowerCollateral: 81.248845402670658374 * 1e18,
borrowerCollateral: 81.248634919843195769 * 1e18,
borrowert0Np: 0,
borrowerCollateralization: 1 * 1e18
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -686,12 +686,12 @@ contract ERC721PoolLiquidationsSettleAuctionTest is ERC721HelperContract {
borrower: _borrower2,
kicker: _lender,
index: 2500,
collateralArbed: 2.655448316828858737 * 1e18,
quoteTokenAmount: 10_259.734490617083440664 * 1e18,
bondChange: 0.156330289779736161 * 1e18,
collateralArbed: 2.655448319814158671 * 1e18,
quoteTokenAmount: 10_259.734502151250575171 * 1e18,
bondChange: 0.156285028574074978 * 1e18,
isReward: true,
lpAwardTaker: 0,
lpAwardKicker: 0.094077964443835904 * 1e18
lpAwardKicker: 0.094050726714648058 * 1e18
});
_assertCollateralInvariants();
_assertBorrower({
Expand Down Expand Up @@ -722,9 +722,9 @@ contract ERC721PoolLiquidationsSettleAuctionTest is ERC721HelperContract {
// lender removes collateral
_assertBucket({
index: 2500,
lpBalance: 8_000.094077964443835904 * 1e18,
collateral: 2.655448316828858737 * 1e18,
deposit: 3_034.101455631189732489 * 1e18,
lpBalance: 8_000.094050726714648058 * 1e18,
collateral: 2.655448319814158671 * 1e18,
deposit: 3_034.101398835816938926 * 1e18,
exchangeRate: 1.661709951994811681 * 1e18
});
_addLiquidityNoEventCheck({
Expand All @@ -734,10 +734,10 @@ contract ERC721PoolLiquidationsSettleAuctionTest is ERC721HelperContract {
});
_assertBucket({
index: 2569,
lpBalance: 10_943.614016738084826008 * 1e18,
collateral: 0.344551683171141263 * 1e18,
lpBalance: 10_943.614008562327749549 * 1e18,
collateral: 0.344551680185841329 * 1e18,
deposit: 10_000.000000000000000000 * 1e18,
exchangeRate: 1 * 1e18
exchangeRate: 1.000000000000000001 * 1e18
});
removalIndexes[0] = 2500;
removalIndexes[1] = 2569;
Expand All @@ -751,25 +751,25 @@ contract ERC721PoolLiquidationsSettleAuctionTest is ERC721HelperContract {
});
_assertBucket({
index: 2500,
lpBalance: 1_825.891126179319554280 * 1e18,
lpBalance: 1_825.891092000446926490 * 1e18,
collateral: 0,
deposit: 3_034.101455631189732489 * 1e18,
deposit: 3_034.101398835816938926 * 1e18,
exchangeRate: 1.661709951994811681 * 1e18
});
_assertBucket({
index: 2569,
lpBalance: 10_000.000000000000000002 * 1e18,
lpBalance: 9_999.999999999999999995 * 1e18,
collateral: 0,
deposit: 10_000.000000000000000000 * 1e18,
exchangeRate: 1 * 1e18
exchangeRate: 1.000000000000000001 * 1e18
});
// borrower 2 redeems LP for quote token
_removeAllLiquidity({
from: _borrower2,
amount: 943.614016738084826005 * 1e18,
amount: 943.614008562327749554 * 1e18,
index: 2569,
newLup: MAX_PRICE,
lpRedeem: 943.614016738084826006 * 1e18
lpRedeem: 943.614008562327749554 * 1e18
});
}

Expand Down

0 comments on commit b59a93b

Please sign in to comment.