`D3VaultFunding.userWithdraw()` doen not have mindTokenAmount
`D3VaultFunding.userWithdraw()` doen not have mindTokenAmount, and use `_getExchangeRate` directly.This is vulnerable to a sandwich attack.\\nAs we can see, `D3VaultFunding.userWithdraw()` doen not have mindTokenAmount, and use `_getExchangeRate` directly.\\n```\\nfunction userWithdraw(address to, address user, address token, uint256 dTokenAmount) external nonReentrant allowedToken(token) returns(uint256 amount) {\\n        accrueInterest(token);\\n        AssetInfo storage info = assetInfo[token];\\n        require(dTokenAmount <= IDToken(info.dToken).balanceOf(msg.sender), Errors.DTOKEN_BALANCE_NOT_ENOUGH);\\n\\n        amount = dTokenAmount.mul(_getExchangeRate(token));//@audit does not check amount value\\n        IDToken(info.dToken).burn(msg.sender, dTokenAmount);\\n        IERC20(token).safeTransfer(to, amount);\\n        info.balance = info.balance - amount;\\n\\n        // used for calculate user withdraw amount\\n        // this function could be called from d3Proxy, so we need "user" param\\n        // In the meantime, some users may hope to use this function directly,\\n        // to prevent these users fill "user" param with wrong addresses,\\n        // we use "msg.sender" param to check.\\n        emit UserWithdraw(msg.sender, user, token, amount);\\n    }\\n```\\n\\nAnd the `_getExchangeRate()` result is about `cash` , `info.totalBorrows`, info.totalReserves,info.withdrawnReserves,dTokenSupply,This is vulnerable to a sandwich attack leading to huge slippage\\n```\\nfunction _getExchangeRate(address token) internal view returns (uint256) {\\n        AssetInfo storage info = assetInfo[token];\\n        uint256 cash = getCash(token);\\n        uint256 dTokenSupply = IERC20(info.dToken).totalSupply();\\n        if (dTokenSupply == 0) { return 1e18; }\\n        return (cash + info.totalBorrows - (info.totalReserves - info.withdrawnReserves)).div(dTokenSupply);\\n    } \\n```\\n
Add `mindTokenAmount` parameter for `userWithdraw()` function and check if `amount < mindTokenAmount`
This is vulnerable to a sandwich attack.
```\\nfunction userWithdraw(address to, address user, address token, uint256 dTokenAmount) external nonReentrant allowedToken(token) returns(uint256 amount) {\\n        accrueInterest(token);\\n        AssetInfo storage info = assetInfo[token];\\n        require(dTokenAmount <= IDToken(info.dToken).balanceOf(msg.sender), Errors.DTOKEN_BALANCE_NOT_ENOUGH);\\n\\n        amount = dTokenAmount.mul(_getExchangeRate(token));//@audit does not check amount value\\n        IDToken(info.dToken).burn(msg.sender, dTokenAmount);\\n        IERC20(token).safeTransfer(to, amount);\\n        info.balance = info.balance - amount;\\n\\n        // used for calculate user withdraw amount\\n        // this function could be called from d3Proxy, so we need "user" param\\n        // In the meantime, some users may hope to use this function directly,\\n        // to prevent these users fill "user" param with wrong addresses,\\n        // we use "msg.sender" param to check.\\n        emit UserWithdraw(msg.sender, user, token, amount);\\n    }\\n```\\n