Skip to content
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

Memorialize borrower threshold price on kick #976

Merged
merged 9 commits into from
Nov 17, 2023
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
Loading