Summary
createContingentPool
is Susceptible to MEV Sandwich Attacks Due to No Slippage Protection
Vulnerability Details
The createContingentPool
function lacks MEV protection mechanisms like minimum output and deadline parameters, allowing MEV bots to sandwich user transactions by manipulating pool parameters and extracting value from pool creation transactions.
function _createContingentPool(PoolParams calldata _poolParams) internal returns (bytes32) {
address _wToken = _collateralTokenToWToken[_poolParams.collateralToken];
if (_wToken == address(0)) {
revert CollateralTokenNotRegistered();
}
_handleTokenOperations(_poolParams.collateralToken, _poolParams.collateralAmount, _wToken);
bytes32 _poolId = IDIVA(_diva).createContingentPool(
IDIVA.PoolParams({
referenceAsset: _poolParams.referenceAsset,
expiryTime: _poolParams.expiryTime,
floor: _poolParams.floor,
inflection: _poolParams.inflection,
cap: _poolParams.cap,
gradient: _poolParams.gradient,
collateralAmount: _poolParams.collateralAmount,
collateralToken: _wToken,
dataProvider: _poolParams.dataProvider,
capacity: _poolParams.capacity,
longRecipient: _poolParams.longRecipient,
shortRecipient: _poolParams.shortRecipient,
permissionedERC721Token: _poolParams.permissionedERC721Token
})
);
return _poolId;
}
Proof of Concept
describe("MEV Sandwich Attack", function() {
it("Should demonstrate MEV sandwich attack vulnerability", async function() {
const { s, collateralTokenContract } = await loadFixture(setup);
await s.aaveDIVAWrapper
.connect(s.owner)
.registerCollateralToken(collateralToken);
await s.aaveDIVAWrapper
.connect(s.owner)
.createContingentPool({
...s.createContingentPoolParams,
floor: parseUnits("90"),
cap: parseUnits("110"),
collateralAmount: parseUnits("100", s.collateralTokenDecimals)
});
await s.aaveDIVAWrapper
.connect(s.impersonatedSigner)
.createContingentPool({
...s.createContingentPoolParams,
collateralAmount: parseUnits("1000", s.collateralTokenDecimals)
});
await s.aaveDIVAWrapper
.connect(s.owner)
.createContingentPool({
...s.createContingentPoolParams,
floor: parseUnits("100"),
cap: parseUnits("200"),
collateralAmount: parseUnits("100", s.collateralTokenDecimals)
});
});
});
Impact
Front-running pool creation leads to direct financial loss
MEV sandwich attacks can manipulate pool parameters
Users receive suboptimal position token amounts
Tools Used
Hardhat
Recommendations
Add minimum output validation and deadline checks to prevent sandwich attacks and ensure users receive their expected minimum position tokens.
struct PoolParams {
+ uint256 minLongTokens;
+ uint256 minShortTokens;
+ uint256 deadline;
}
function _createContingentPool(PoolParams calldata _poolParams) internal returns (bytes32) {
+ require(block.timestamp <= _poolParams.deadline, "Transaction expired");
address _wToken = _collateralTokenToWToken[_poolParams.collateralToken];
if (_wToken == address(0)) {
revert CollateralTokenNotRegistered();
}
_handleTokenOperations(_poolParams.collateralToken, _poolParams.collateralAmount, _wToken);
bytes32 poolId = IDIVA(_diva).createContingentPool(...);
+ (uint256 longTokens, uint256 shortTokens) = IDIVA(_diva).getPositionTokenAmounts(poolId);
+ require(longTokens >= _poolParams.minLongTokens, "Insufficient long tokens");
+ require(shortTokens >= _poolParams.minShortTokens, "Insufficient short tokens");
return poolId;
}