Powerful Honeysuckle Anteater
High
Adversary could always keep the USDT reserves as 0 by using flashloan attack on the redeemUSDT function
The redeemUSDT()
function in CDS allows users to exchange USDA for USDT. However, there is no limit on how much an individual user can withdraw, and the function is not restricted to dCDS depositors. This means an adversary could use a flash loan to drain all the USDT, consistently keeping the USDT reserves empty.
redeemUSDT()
just checks if we have the USDa balance we want to exchange reference:
function redeemUSDT(
CDSInterface.Interfaces memory interfaces,
uint256 burnedUSDaInRedeem,
uint128 usdaAmount,
uint64 usdaPrice,
uint64 usdtPrice
) external returns (uint256) {
if (usdaAmount == 0) revert CDSInterface.CDS_NeedsMoreThanZero();
@>> if (interfaces.usda.balanceOf(msg.sender) < usdaAmount) {
revert CDSInterface.CDS_Insufficient_USDa_Balance();
}
// Increment burnedUSDaInRedeem
burnedUSDaInRedeem += usdaAmount;
IGlobalVariables.OmniChainData memory omniChainData = interfaces.globalVariables.getOmniChainData();
omniChainData.burnedUSDaInRedeem += usdaAmount; //
// burn usda
bool transfer = interfaces.usda.burnFromUser(msg.sender, usdaAmount);
if (!transfer) revert CDSInterface.CDS_TransferFailed(IBorrowing.AssetName.USDa);
// calculate the USDT USDa ratio
uint128 usdtAmount = ((usdaPrice * usdaAmount) / usdtPrice);
interfaces.treasury.approveTokens(IBorrowing.AssetName.TUSDT, address(interfaces.cds), usdtAmount);
// Transfer usdt to user
@>> bool success = interfaces.usdt.transferFrom(address(interfaces.treasury), msg.sender, usdtAmount);
if (!success) revert CDSInterface.CDS_TransferFailed(IBorrowing.AssetName.TUSDT);
interfaces.globalVariables.setOmniChainData(omniChainData);
return burnedUSDaInRedeem;
}
- Adversary takes ETH flashloan.
- Adversary swaps the ETH for USDA on a Uniswap or other liquidity pool.
- Adversary calls
redeemUSDT()
in CDS contract and gets all the USDT out, by depositing USDA - Adversary sells USDT for ETH to repay the loan.
- Done. For small amount of fees paid for the flashloan, the adversary just emptied the whole USDT reserve of the treasury.
This limits the ability of the protocol to control the peg stability mechanisms. The USDT redeemability was added exactly for this particular reason: https://docs.autonomint.com/autonomint/autonomint-1/autonomint/stablecoin-peg-stability#utilizing-usdt-deposited-in-dcds-for-immediate-re-deemability
Managing Stablecoin Demand 5.Immediate re-deemability - Users can re-deem USDa to get USDT immediately in case the price falls below $1
Consider adding limit on how much can be withdrawn per transaction, as well as per user. Also, consider limiting the function only to dCDS depositors.