Tadle

Tadle
DeFiFoundry
27,750 USDC
View results
Submission Details
Severity: low
Invalid

Long-Term Data Accumulation Affecting Contract Efficiency

Summary

The PreMarkets contract in the Tadle protocol lacks mechanisms to manage long-term data accumulation in its storage mappings. This design could lead to gradually increasing gas costs and reduced contract efficiency over time, potentially impacting the protocol's long-term viability and user experience.

Vulnerability Detail

The vulnerability stems from the continuous addition of data to storage mappings without any mechanism for data removal or archiving. Specifically, the issue is present in the createOffer function of the PreMarkets contract:

function createOffer(CreateOfferParams calldata params) external payable {
// ... (input validation)
address makerAddr = GenerateAddress.generateMakerAddress(offerId);
address offerAddr = GenerateAddress.generateOfferAddress(offerId);
address stockAddr = GenerateAddress.generateStockAddress(offerId);
if (makerInfoMap[makerAddr].authority != address(0x0)) {
revert MakerAlreadyExist();
}
if (offerInfoMap[offerAddr].authority != address(0x0)) {
revert OfferAlreadyExist();
}
if (stockInfoMap[stockAddr].authority != address(0x0)) {
revert StockAlreadyExist();
}
offerId = offerId + 1;
// ... (update makerInfoMap, offerInfoMap, and stockInfoMap)
}

This function creates new entries in makerInfoMap, offerInfoMap, and stockInfoMap for each new offer. The offerId is incremented with each new offer, ensuring unique addresses for each entry. However, there is no mechanism to remove or archive old data from these mappings.

The storage for these mappings is defined in the PerMarketsStorage contract:

contract PerMarketsStorage is UpgradeableStorage {
uint256 public offerId;
mapping(address => OfferInfo) public offerInfoMap;
mapping(address => StockInfo) public stockInfoMap;
mapping(address => MakerInfo) public makerInfoMap;
// ...
}

Impact

While this accumulation is unlikely to cause immediate issues or reach block gas limits in the short term, it could have the following long-term impacts:

  1. Gradually increasing gas costs: As the mappings grow, operations that involve reading from or writing to these mappings will consume more gas, making transactions more expensive for users over time.

  2. Reduced contract efficiency: Large data structures can lead to slower execution times and higher computational costs for contract operations.

  3. Potential for reached gas limits: In an extreme scenario, after a very long period of continuous use, certain operations might become too gas-intensive to execute within a single block.

Tool used

Manual Review

Recommendation

To address this vulnerability, consider implementing the following measures:

  1. Data Archiving Mechanism: Implement a function to move old, settled, or cancelled offers to a separate archival storage after a certain period. This could be triggered periodically or when certain conditions are met.

function archiveOldOffers(uint256 thresholdTimestamp) external onlyOwner {
for (uint256 i = 0; i < offerId; i++) {
address offerAddr = GenerateAddress.generateOfferAddress(i);
OfferInfo storage offer = offerInfoMap[offerAddr];
if (offer.timestamp < thresholdTimestamp &&
(offer.offerStatus == OfferStatus.Settled ||
offer.offerStatus == OfferStatus.Canceled)) {
// Move to archive storage and delete from main storage
archiveOfferInfo(offerAddr, offer);
delete offerInfoMap[offerAddr];
}
}
}
  1. Implement Pagination: For functions that might need to iterate over large datasets, implement pagination to limit gas consumption per transaction.

function getOffers(uint256 start, uint256 limit) external view returns (OfferInfo[] memory) {
OfferInfo[] memory offers = new OfferInfo[](limit);
uint256 counter = 0;
for (uint256 i = start; i < offerId && counter < limit; i++) {
address offerAddr = GenerateAddress.generateOfferAddress(i);
if (offerInfoMap[offerAddr].authority != address(0)) {
offers[counter] = offerInfoMap[offerAddr];
counter++;
}
}
return offers;
}
  1. Data Cleanup: Implement a function to remove completely settled or long-cancelled offers that are no longer needed.

function cleanupOldOffers(uint256 thresholdTimestamp) external onlyOwner {
for (uint256 i = 0; i < offerId; i++) {
address offerAddr = GenerateAddress.generateOfferAddress(i);
OfferInfo storage offer = offerInfoMap[offerAddr];
if (offer.timestamp < thresholdTimestamp &&
offer.offerStatus == OfferStatus.Settled) {
delete offerInfoMap[offerAddr];
// Also clean up associated maker and stock info
// ...
}
}
}
Updates

Lead Judging Commences

0xnevi Lead Judge
about 1 year ago
0xnevi Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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