Skip to content

Commit

Permalink
Merge pull request #114 from GenerationSoftware/gen-1779-88-consider-…
Browse files Browse the repository at this point in the history
…yield-fee-amount-with-mintlimit-when-returning

Include yield fee mint limit in asset liquidation balance
  • Loading branch information
trmid authored Jun 28, 2024
2 parents 41ed556 + c33bfa6 commit d888632
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 1 deletion.
11 changes: 10 additions & 1 deletion src/PrizeVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -686,13 +686,22 @@ contract PrizeVault is TwabERC20, Claimable, IERC4626, ILiquidationSource, Ownab
/// @dev Supports the liquidation of either assets or prize vault shares.
function liquidatableBalanceOf(address _tokenOut) external view returns (uint256) {
uint256 _totalDebt = totalDebt();
uint256 _yieldFeePercentage = yieldFeePercentage;
uint256 _maxAmountOut;
if (_tokenOut == address(this)) {
// Liquidation of vault shares is capped to the mint limit.
_maxAmountOut = _mintLimit(_totalDebt);
} else if (_tokenOut == address(_asset)) {
// Liquidation of yield assets is capped at the max yield vault withdraw plus any latent balance.
_maxAmountOut = _maxYieldVaultWithdraw() + _asset.balanceOf(address(this));

// If a yield fee will be minted, then the liquidation will also be capped based on the remaining mint limit.
if (_yieldFeePercentage != 0) {
uint256 _maxAmountBasedOnFeeMintLimit = _mintLimit(_totalDebt).mulDiv(FEE_PRECISION, _yieldFeePercentage);
if (_maxAmountBasedOnFeeMintLimit < _maxAmountOut) {
_maxAmountOut = _maxAmountBasedOnFeeMintLimit;
}
}
} else {
return 0;
}
Expand All @@ -705,7 +714,7 @@ contract PrizeVault is TwabERC20, Claimable, IERC4626, ILiquidationSource, Ownab
// The final balance is computed by taking the liquid yield and multiplying it by
// (1 - yieldFeePercentage), rounding down, to ensure that enough yield is left for
// the yield fee.
return _liquidYield.mulDiv(FEE_PRECISION - yieldFeePercentage, FEE_PRECISION);
return _liquidYield.mulDiv(FEE_PRECISION - _yieldFeePercentage, FEE_PRECISION);
}

/// @inheritdoc ILiquidationSource
Expand Down
44 changes: 44 additions & 0 deletions test/unit/PrizeVault/Liquidate.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,50 @@ contract PrizeVaultLiquidationTest is UnitBaseSetup {
vault.claimYieldFeeShares(supplyCapLeft - amountOut);
}

function testLiquidatableBalanceOf_hasBalanceAtShareLimitWhenNoFee() public {
vault.setYieldFeePercentage(0); // no fee

// make a large deposit to use all of the shares:
underlyingAsset.mint(address(alice), type(uint96).max);
vm.startPrank(alice);
underlyingAsset.approve(address(vault), type(uint96).max);
vault.deposit(type(uint96).max, alice);
vm.stopPrank();

underlyingAsset.mint(address(vault), 1e18);
uint256 availableYield = vault.availableYieldBalance();
assertApproxEqAbs(availableYield, 1e18 - vault.yieldBuffer(), 1);

assertEq(vault.liquidatableBalanceOf(address(underlyingAsset)), availableYield); // can still liquidate
}

function testLiquidatableBalanceOf_respectsFeeShareLimitWithAssetBalance() public {
vault.setYieldFeePercentage(1e8); // 10% fee

uint256 supplyCapLeft = 100; // this means that with a 10% fee, we should be able to liquidate 900 assets so that the yield fee is minted up to the supply cap, but no further

// make a large deposit to use most of the shares:
underlyingAsset.mint(address(alice), type(uint96).max);
vm.startPrank(alice);
underlyingAsset.approve(address(vault), type(uint96).max - supplyCapLeft);
vault.deposit(type(uint96).max - supplyCapLeft, alice);
vm.stopPrank();

underlyingAsset.mint(address(vault), 1e18);
uint256 availableYield = vault.availableYieldBalance();
assertApproxEqAbs(availableYield, 1e18 - vault.yieldBuffer(), 1);

assertGt(availableYield, 900);

assertEq(vault.liquidatableBalanceOf(address(underlyingAsset)), 900); // capped at 900 since that results in our max 100 yield fee mint

// ensure a liquidation can occur at the max:
vault.setLiquidationPair(address(this));
vm.expectEmit();
emit TransferYieldOut(address(this), address(underlyingAsset), alice, 900, 100);
vault.transferTokensOut(address(0), alice, address(underlyingAsset), 900);
}

/* ============ transferTokensOut ============ */

function testTransferTokensOut_noFee() public {
Expand Down

0 comments on commit d888632

Please sign in to comment.