HardhatDeFi
15,000 USDC
View results
Submission Details
Severity: high
Invalid

`createContingentPool` is Susceptible to MEV Sandwich Attacks Due to No Slippage Protection

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 {
// ... existing params ...
+ 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;
}
Updates

Lead Judging Commences

bube Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.