diff --git a/src/interfaces/ISize.sol b/src/interfaces/ISize.sol index 3d6eaee4..ce72d6ec 100644 --- a/src/interfaces/ISize.sol +++ b/src/interfaces/ISize.sol @@ -103,7 +103,6 @@ interface ISize is ISizeView, ISizeAdmin, IMulticall { /// @notice Repay a debt position by transferring the amount due of borrow tokens to the protocol, which are deposited to the Variable Pool for the lenders to claim /// Partial repayment are currently unsupported /// @dev The Variable Pool liquidity index is snapshotted at the time of the repayment in order to calculate the accrued interest for lenders to claim - /// The liquidator overdue reward is cleared from the borrower debt upon repayment /// @param params RepayParams struct containing the following fields: /// - uint256 debtPositionId: The id of the debt position to repay function repay(RepayParams calldata params) external payable; @@ -122,7 +121,7 @@ interface ISize is ISizeView, ISizeAdmin, IMulticall { /// @param params LiquidateParams struct containing the following fields: /// - uint256 debtPositionId: The id of the debt position to liquidate /// - uint256 minimumCollateralProfit: The minimum collateral profit that the liquidator is willing to accept from the borrower (keepers might choose to pass a value below 100% of the cash they bring and take the risk of liquidating unprofitably) - /// @return liquidatorProfitCollateralToken The amount of collateral tokens the liquidator received from the liquidation + /// @return liquidatorProfitCollateralToken The amount of collateral tokens the the fee recipient received from the liquidation function liquidate(LiquidateParams calldata params) external payable @@ -137,7 +136,7 @@ interface ISize is ISizeView, ISizeAdmin, IMulticall { /// @notice Liquidate a debt position with a replacement borrower /// @dev This function works exactly like `liquidate`, with an added logic of replacing the borrower on the storage - /// When liquidating with replacement, nothing changes from the lender's perspective, but a spread is created between the previous borrower rate and the new borrower rate. + /// When liquidating with replacement, nothing changes from the lenders' perspective, but a spread is created between the previous borrower rate and the new borrower rate. /// As a result of the spread of these borrow aprs, the protocol is able to profit from the liquidation. Since the choice of the borrower impacts on the protocol's profit, this method is permissioned /// @param params LiquidateWithReplacementParams struct containing the following fields: /// - uint256 debtPositionId: The id of the debt position to liquidate @@ -153,10 +152,10 @@ interface ISize is ISizeView, ISizeAdmin, IMulticall { returns (uint256 liquidatorProfitCollateralToken, uint256 liquidatorProfitBorrowToken); /// @notice Compensate a borrower's debt with his credit in another loan - /// The compensation can not exceed both 1) the credit the lender of `debtPositionToRepayId` to the borrower and 2) the credit the lender of `creditPositionToCompensateId` + /// The compensation can not exceed both 1) the credit the lender of `creditPositionWithDebtToRepayId` to the borrower and 2) the credit the lender of `creditPositionToCompensateId` // @dev The caller may pass type(uint256).max as the creditPositionId in order to represent "mint a new DebtPosition/CreditPosition pair" /// @param params CompensateParams struct containing the following fields: - /// - uint256 debtPositionToRepayId: The id of the debt position to repay + /// - uint256 creditPositionWithDebtToRepayId: The id of the credit position ID with debt to repay /// - uint256 creditPositionToCompensateId: The id of the credit position to compensate /// - uint256 amount: The amount of tokens to compensate (in decimals, e.g. 1_000e6 for 1000 aUSDC) function compensate(CompensateParams calldata params) external payable; diff --git a/src/libraries/AccountingLibrary.sol b/src/libraries/AccountingLibrary.sol index 68d598d8..9f77613c 100644 --- a/src/libraries/AccountingLibrary.sol +++ b/src/libraries/AccountingLibrary.sol @@ -141,7 +141,7 @@ library AccountingLibrary { /// The credit amount cannot be reduced below the minimum credit. /// This operation breaks the initial sum of credit equal to the debt position future value. /// If the loan is in REPAID status, this is expected, as lenders grdually claim their credit. - /// If the loan is in ACTIVE status, a debt reduction must be performed together with a credit reduction (See reduceDebtAndCredit). + /// If the loan is in ACTIVE/OVERDUE status, a debt reduction must be performed together with a credit reduction (See reduceDebtAndCredit). /// @param state The state object /// @param creditPositionId The credit position id function reduceCredit(State storage state, uint256 creditPositionId, uint256 amount) public { @@ -176,6 +176,8 @@ library AccountingLibrary { } /// @notice Get the swap fee for a given cash amount and tenor + /// @dev The intention for the swap fee is to for it to be charged on the "issuance value" of the credit and it is a predefined APR + /// The issuance value is defined as the amount of credit sold discounted by the chosen rate /// @param state The state object /// @param cash The cash amount /// @param tenor The tenor @@ -265,7 +267,7 @@ library AccountingLibrary { ); fees = Math.mulDivUp(cashAmountOut, swapFeePercent, PERCENT) + state.feeConfig.fragmentationFee; } else { - // for maxCashAmountOutFragmentation < amountOut < maxCashAmountOut we are in an inconsistent situation + // for maxCashAmountOutFragmentation < cashAmountOut < maxCashAmountOut we are in an inconsistent situation // where charging the swap fee would require to sell a credit that exceeds the max possible credit revert Errors.NOT_ENOUGH_CASH(maxCashAmountOutFragmentation, cashAmountOut); @@ -306,7 +308,7 @@ library AccountingLibrary { creditAmountOut = Math.mulDivDown(netCashAmountIn, PERCENT + ratePerTenor, PERCENT); fees = getSwapFee(state, netCashAmountIn, tenor) + state.feeConfig.fragmentationFee; } else { - revert Errors.NOT_ENOUGH_CREDIT(maxCashAmountIn, cashAmountIn); + revert Errors.NOT_ENOUGH_CASH(maxCashAmountIn, cashAmountIn); } } diff --git a/src/libraries/CapsLibrary.sol b/src/libraries/CapsLibrary.sol index c1f12a50..cd6e2538 100644 --- a/src/libraries/CapsLibrary.sol +++ b/src/libraries/CapsLibrary.sol @@ -62,7 +62,9 @@ library CapsLibrary { /// @dev Reverts if the Variable Pool does not have enough liquidity /// This safety mechanism prevents takers from matching orders that could not be withdrawn from the Variable Pool. /// Nevertheless, the Variable Pool may still fail to withdraw the cash due to other factors (such as a pause, etc), - /// which is understood as an acceptable risk. + /// which is understood as an acceptable risk, since it can be mitigated by a multicall. + /// This check can be bypassed with a sandwitch attack that supplies just enough to make the pool liquid again, + /// which we understand as an acceptable risk, since it can be mitigated by a multicall. /// @param state The state struct /// @param amount The amount of cash to withdraw function validateVariablePoolHasEnoughLiquidity(State storage state, uint256 amount) public view {