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

[M-02] DoS via Gas Exhaustion in batchCreateContingentPool function

Summary

The batchCreateContingentPool function is vulnerable to a Denial of Service (DoS) attack through gas exhaustion due to unbounded array processing, potentially preventing users from creating pools if an attacker submits a transaction with an excessively large array.

Vulnerability Details

The batchCreateContingentPool function processes an array of PoolParams without imposing any limit on the array size. This design allows an attacker to submit a transaction with an extremely large array of pool parameters, causing the transaction to consume more gas than the block gas limit allows. When this happens, the transaction will fail, and no pools can be created through this function.

Impacted code:

function batchCreateContingentPool(
PoolParams[] calldata _poolParams
) external override nonReentrant returns (bytes32[] memory) {
uint256 _length = _poolParams.length;
bytes32[] memory _poolIds = new bytes32[]();
for (uint256 i = 0; i < _length; i++) {
_poolIds[i] = _createContingentPool(_poolParams[i]);
}
return _poolIds;
}

Impact

I've rated this as MEDIUM because it doesn't result in direct loss of funds, the core functionality (creating individual pools) remains accessible through non-batch functions, and it primarily affects gas efficiency and convenience rather than security. However, the attack is relatively simple to execute, it requires minimal resources from the attacker, and the function is publicly accessible. Despite gas limits being a well-known constraint, there are no existing controls to prevent the attack.

For example:

// Create an array of PoolParams exceeding block gas limit
PoolParams[] memory largeArray = new PoolParams[](); // Size chosen to exceed limit
for(uint i = 0; i < 1000; i++) {
largeArray[i] = PoolParams({
// valid parameters
referenceAsset: "TEST",
expiryTime: uint96(block.timestamp + 1 days),
floor: 1000,
inflection: 2000,
cap: 3000,
gradient: 1,
collateralAmount: 1000,
collateralToken: address(0x1234),
dataProvider: address(0x5678),
capacity: type(uint256).max,
longRecipient: address(0x9ABC),
shortRecipient: address(0xDEF0),
permissionedERC721Token: address(0)
});
}
// Attempt to create pools in batch - will fail due to gas limit
await aaveDIVAWrapper.batchCreateContingentPool(largeArray);

Recommendations

Implement a maximum limit on the number of pools that can be created in a single batch transaction. This can be done by adding a constant and a check at the beginning of the function:

// Add constant at contract level
uint256 private constant MAX_BATCH_SIZE = 50;
function batchCreateContingentPool(
PoolParams[] calldata _poolParams
) external override nonReentrant returns (bytes32[] memory) {
uint256 _length = _poolParams.length;
require(_length <= MAX_BATCH_SIZE, "Batch size exceeds limit");
bytes32[] memory _poolIds = new bytes32[]();
for (uint256 i = 0; i < _length; i++) {
_poolIds[i] = _createContingentPool(_poolParams[i]);
}
return _poolIds;
}

Here the maximum batch size can be processed within block gas limits under worst-case conditions.

Updates

Lead Judging Commences

bube Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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