This document details our collaborative engineering effort with BendDAO regarding their contracts.
The audit does not ensure that it has identified every security issue in the smart contracts, and it should not be seen as a confirmation that there are no more vulnerabilities. While we have conducted an analysis to the best of our ability, it is our recommendation for high-value contracts to commission several independent audits, a public bug bounty program, as well as continuous onchain security auditing and monitoring through Fuzzland Blaz+ Analysis and Alert. Additionally, this report should not be interpreted as personal financial advice or recommendations.
In the smart contract system, the executeCrossLiquidateERC20
function is a key component designed to handle liquidation logic. By analyzing the test case test_Should_LiquidateUSDTself
, we found that when the liquidator and the borrower are the same participant, triggering this function will lead to a discrepancy between the total cross supply totalCrossSupply
after liquidation and the expected value.
POC:
totalCrossSupply
is 0, but it is actually 10,000,000,000,000,000,000.totalCrossBorrow
, where the expected value is 2,866,274,286, but the actual value is 18,558,267,614.walletBalance
do not match, with a discrepancy of 10,000,000,000,000,000,000 at one checkpoint. // test\\integration\\TestIntCrossLiquidateERC20.t.sol
function test_Should_LiquidateUSDTself() public {
prepareUSDT(tsDepositor1);
prepareWETH(tsBorrower1);
TestUserAccountData memory accountDataBeforeBorrow = getUserAccountData(address(tsBorrower1), tsCommonPoolId);
// borrow some eth
uint8[] memory borrowGroups = new uint8[](1);
borrowGroups[0] = tsLowRateGroupId;
uint256[] memory borrowAmounts = new uint256[](1);
uint256 usdtCurPrice = tsPriceOracle.getAssetPrice(address(tsUSDT));
borrowAmounts[0] = (accountDataBeforeBorrow.availableBorrowInBase * (10 ** tsUSDT.decimals())) / usdtCurPrice;
actionCrossBorrowERC20(
address(tsBorrower1),
tsCommonPoolId,
address(tsUSDT),
borrowGroups,
borrowAmounts,
new bytes(0)
);
// make some interest
advanceTimes(365 days);
// drop down eth price to lower heath factor
uint256 wethCurPrice = tsPriceOracle.getAssetPrice(address(tsWETH));
uint256 wethNewPrice = (wethCurPrice * 80) / 100;
tsCLAggregatorWETH.updateAnswer(int256(wethNewPrice));
TestUserAccountData memory accountDataAfterBorrow = getUserAccountData(address(tsBorrower1), tsCommonPoolId);
assertLt(accountDataAfterBorrow.healthFactor, 1e18, 'ACC:healthFactor');
// liquidate some eth
tsBorrower1.approveERC20(address(tsUSDT), type(uint256).max);
actionCrossLiquidateERC20(
address(tsBorrower1),
tsCommonPoolId,
address(tsBorrower1),
address(tsWETH),
address(tsUSDT),
borrowAmounts[0],
false,
new bytes(0)
);
}
// log
checkAssetData begin
checkAssetData group 0
checkAssetData group 1
checkAssetData group 2
checkAssetData group 3
checkAssetData end
checkUserAssetData begin
Error: UAD:totalCrossSupply
Error: a ~= b not satisfied [uint]
Left: 0
Right: 10000000000000000000
Max Delta: 1
Delta: 10000000000000000000
checkUserAssetData group 0
checkUserAssetData group 1
checkUserAssetData group 2
checkUserAssetData group 3
checkUserAssetData end
actionCrossLiquidateERC20 check: liquidator & debt
checkAssetData begin
checkAssetData group 0
checkAssetData group 1
checkAssetData group 2
checkAssetData group 3
checkAssetData end
checkUserAssetData begin
checkUserAssetData group 0
checkUserAssetData group 1
Error: UAD:totalCrossBorrow
Error: a ~= b not satisfied [uint]
Left: 2866274286
Right: 18558267614
Max Delta: 1
Delta: 15691993328
checkUserAssetData group 2
checkUserAssetData group 3
checkUserAssetData end
actionCrossLiquidateERC20 check: borrower & collateral
checkUserAssetData begin
Error: UAD:walletBalance
Error: a ~= b not satisfied [uint]
Left: 1000000000000000000000000
Right: 999990000000000000000000
Max Delta: 1
Delta: 10000000000000000000
checkUserAssetData group 0
checkUserAssetData group 1
checkUserAssetData group 2
checkUserAssetData group 3
checkUserAssetData end
actionCrossLiquidateERC20 check: borrower & debt
checkUserAssetData begin
Error: UAD:walletBalance
Error: a ~= b not satisfied [uint]
Left: 1000887578372
Right: 1016579571700
Max Delta: 1
Delta: 15691993328
checkUserAssetData group 0
checkUserAssetData group 1
checkUserAssetData group 2
checkUserAssetData group 3
checkUserAssetData end
>>>>actionCrossLiquidateERC20 end