Summary
During liquidation only record yield accrued from IONIC, however those yields are not utilized/there is no way to withdraw them.
Root Cause
The case where we update treasury.updateInterestFromExternalProtocol we use treasury.withdrawFromExternalProtocolDuringLiq(user, index), which essentially gives us only the extra yield accrued:
function withdrawFromExternalProtocolDuringLiq(address user, uint64 index) external onlyCoreContracts returns (uint256)
{
uint256 balanceBeforeWithdraw = address(this).balance;
uint256 redeemAmount = withdrawFromIonicDuringLiq(user, index);
if (address(this).balance < redeemAmount + balanceBeforeWithdraw) {
revert Treasury_WithdrawExternalProtocolDuringLiqFailed();
}
@>> return (redeemAmount - (borrowing[user].depositDetails[index].depositedAmount * 50) / 100);
} Reference during liquidation:
// Update treasury data
treasury.updateTotalVolumeOfBorrowersAmountinWei(depositDetail.depositedAmountInETH);
treasury.updateTotalVolumeOfBorrowersAmountinUSD(depositDetail.depositedAmountUsdValue);
treasury.updateDepositedCollateralAmountInWei(depositDetail.assetName, depositDetail.depositedAmountInETH);
treasury.updateDepositedCollateralAmountInUsd(depositDetail.assetName, depositDetail.depositedAmountUsdValue);
@>> treasury.updateTotalInterestFromLiquidation(totalInterestFromLiquidation);
treasury.updateYieldsFromLiquidatedLrts(yields);
treasury.updateDepositDetails(user, index, depositDetail);
globalVariables.updateCollateralData(depositDetail.assetName, collateralData);
globalVariables.setOmniChainData(omniChainData);
// If the liquidation amount to get from other is greater than zero,
// Get the amount from other chain.
if (liqAmountToGetFromOtherChain > 0) {
// Call the oftOrCollateralReceiveFromOtherChains function in global variables
globalVariables.oftOrCollateralReceiveFromOtherChains{value: msg.value}(
IGlobalVariables.FunctionToDo(3),
IGlobalVariables.USDaOftTransferData(address(treasury), liqAmountToGetFromOtherChain),
// Since we don't need ETH, we have passed zero params
IGlobalVariables.CollateralTokenTransferData(address(0), 0, 0, 0),
IGlobalVariables.CallingFunction.BORROW_LIQ,
admin
);
}
// If the collateral is ETH, withdraw the deposited ETH in external protocol
if (depositDetail.assetName == IBorrowing.AssetName.ETH) {
@>> treasury.updateInterestFromExternalProtocol(treasury.withdrawFromExternalProtocolDuringLiq(user, index));
}As it can be seen above updateTotalInterestFromLiquidation is also updated, but we have a way to withdraw it in Treasury.sol:
function withdrawInterest(
address toAddress,
uint256 amount
) external onlyOwner {
require(toAddress != address(0) && amount != 0,"Input address or amount is invalid");
require(amount <= (totalInterest + totalInterestFromLiquidation),"Treasury don't have enough interest");
totalInterest -= amount;
bool sent = usda.transfer(toAddress, amount);
require(sent, "Failed to send Ether");
}As mentioned unfortunately we don't handle the yield from IONIC in any way, as the interestFromExternalProtocolDuringLiquidation property in Treasury.sol is unused:
function updateInterestFromExternalProtocol(uint256 amount) external onlyCoreContracts {
interestFromExternalProtocolDuringLiquidation += amount;
}Impact
- No way to withdraw or use the yield generated from IONIC, its just left unused.
Mitigation
Either integrate a way to use the yield from IONIC, or a way to be withdrawn.