Skip to content

Commit

Permalink
allowed free liquidity for redeem and withdraw but not borrow
Browse files Browse the repository at this point in the history
  • Loading branch information
lsqrl committed Jan 4, 2024
1 parent 8ed7555 commit eeabbb9
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 10 deletions.
15 changes: 8 additions & 7 deletions src/Vault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,7 @@ contract Vault is IVault, ERC4626, ERC20Permit {
uint256 supply = totalSupply();
uint256 shares = balanceOf(owner);
// super.maxWithdraw but we leverage the fact of having already computed freeLiq which contains balanceOf()
// notice that shares and free liquidity are always at least 1, and freeLiq cannot be withdrawn
return (freeLiq - 1).min(shares.mulDiv(freeLiq + netLoans + _calculateLockedLosses(), supply));
return freeLiq.min(shares.mulDiv(freeLiq + netLoans + _calculateLockedLosses(), supply));
}

// Assets include netLoans but they are not available for withdraw
Expand All @@ -136,9 +135,9 @@ contract Vault is IVault, ERC4626, ERC20Permit {

// convertToShares using the already computed variables
// if the assets the owner can theoretically withdraw are higher than the free liquidity
// we cap them with the convertToShares of the free liquidity - 1, which is always available
if (assets >= freeLiquidityCache && assets > 0) {
maxRedeemCache = (freeLiquidityCache - 1).mulDiv(supply, totalAssetsCache);
// we cap them with the convertToShares of the free liquidity, which is always available
if (assets > freeLiquidityCache && assets > 0) {
maxRedeemCache = freeLiquidityCache.mulDiv(supply, totalAssetsCache);
}

return maxRedeemCache;
Expand Down Expand Up @@ -185,7 +184,7 @@ contract Vault is IVault, ERC4626, ERC20Permit {
) public override(ERC4626, IERC4626) returns (uint256) {
// assets cannot be more than the current free liquidity
uint256 freeLiq = freeLiquidity();
if (assets >= freeLiq) revert InsufficientLiquidity();
if (assets > freeLiq) revert InsufficientLiquidity();

// super.withdraw but we leverage the fact of having already computed freeLiq
uint256 supply = totalSupply();
Expand All @@ -209,7 +208,7 @@ contract Vault is IVault, ERC4626, ERC20Permit {
uint256 supply = totalSupply();

uint256 assets = shares.mulDiv(totalAssetsCache, supply);
if (assets >= freeLiq) revert InsufficientLiquidity();
if (assets > freeLiq) revert InsufficientLiquidity();
// redeem, now all data have been computed
_withdraw(msg.sender, receiver, owner, assets, shares);

Expand All @@ -229,6 +228,8 @@ contract Vault is IVault, ERC4626, ERC20Permit {
if (loan > assets) revert LoanHigherThanAssetsInBorrow();
uint256 freeLiq = freeLiquidity();

// We do not allow loans higher than the free liquidity
// This prevents the vault to go into unhealthy state
if (assets >= freeLiq) revert InsufficientFreeLiquidity();

netLoans += loan;
Expand Down
8 changes: 5 additions & 3 deletions test/Vault.test.sol
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ contract VaultTest is Test {
uint256 shares = 0;

vm.startPrank(receiver);
if (withdrawn >= vault.freeLiquidity()) {
if (withdrawn > vault.freeLiquidity()) {
vm.expectRevert(bytes4(keccak256(abi.encodePacked("InsufficientLiquidity()"))));
vault.withdraw(withdrawn, receiver, receiver);
withdrawn = 0;
Expand Down Expand Up @@ -604,8 +604,10 @@ contract VaultTest is Test {

// withdraw without leaving 1 token unit
uint256 vaultBalance = token.balanceOf(address(vault));
vm.expectRevert(IVault.InsufficientLiquidity.selector);
vault.withdraw(vaultBalance, tokenSink, receiver);
if (vaultBalance < type(uint256).max) {
vm.expectRevert(IVault.InsufficientLiquidity.selector);
vault.withdraw(vaultBalance + 1, tokenSink, receiver);
}
}

function testCannotBorrowMoreThanFreeLiquidity(uint256 amount) public {
Expand Down

0 comments on commit eeabbb9

Please sign in to comment.