Tadle

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

Missing Zero-Value Check in addTokenBalance Function

Summary

The addTokenBalance function within the TokenManager.sol contract does not include a check to prevent zero-value _amount parameters. This allows the function to emit events and modify state with potentially unintended zero-value transactions.

Vulnerability Details

This is the addTokenBalance function code block.

function addTokenBalance(
TokenBalanceType _tokenBalanceType,
address _accountAddress,
address _tokenAddress,
uint256 _amount
) external onlyRelatedContracts(tadleFactory, _msgSender()) {
userTokenBalanceMap[_accountAddress][_tokenAddress][
_tokenBalanceType
] += _amount;
emit AddTokenBalance(
_accountAddress,
_tokenAddress,
_tokenBalanceType,
_amount
);
}

As you can see, this function lacks validation to ensure that the _amount parameter is greater than zero.

https://github.com/Cyfrin/2024-08-tadle/blob/04fd8634701697184a3f3a5558b41c109866e5f8/src/core/TokenManager.sol#L113-L129

Impact

** **Emitting events with a zero-value _amount can clutter logs with unnecessary data, making it difficult to analyze meaningful transactions. And even though adding zero to a balance does not alter the numeric value, it still invokes state change operations that are unnecessary and could increment gas costs.

Proof of Concept

This is the test code.

function test_ask_offer_turbo_usdc() public {
vm.startPrank(user);
preMarktes.createOffer(
CreateOfferParams(
marketPlace,
address(mockUSDCToken),
1000,
0.01 * 1e18,
12000,
300,
OfferType.Ask,
OfferSettleType.Turbo
)
);
address offerAddr = GenerateAddress.generateOfferAddress(0);
preMarktes.createTaker(offerAddr, 500);
address stock1Addr = GenerateAddress.generateStockAddress(1);
preMarktes.listOffer(stock1Addr, 0.006 * 1e18, 12000);
address offer1Addr = GenerateAddress.generateOfferAddress(1);
preMarktes.closeOffer(stock1Addr, offer1Addr);
preMarktes.relistOffer(stock1Addr, offer1Addr);
vm.stopPrank();
vm.prank(user1);
systemConfig.updateMarket(
"Backpack",
address(mockPointToken),
0.01 * 1e18,
block.timestamp - 1,
3600
);
vm.startPrank(user);
mockPointToken.approve(address(tokenManager), 10000 * 10 ** 18);
deliveryPlace.settleAskMaker(offerAddr, 500);
deliveryPlace.closeBidTaker(stock1Addr);
vm.stopPrank();
}

The result is like this.

│ │ │ │ │ └─ ← [Return] UpgradeableProxy: [0x8d2C17FAd02B7bb64139109c6533b7C2b9CADb81]
│ │ │ │ ├─ [534] TadleFactory::relatedContracts(3) [staticcall]
│ │ │ │ │ └─ ← [Return] UpgradeableProxy: [0x3C8Ca53ee5661D29d3d3C0732689a4b86947EAF0]
│ │ │ │ ├─ emit AddTokenBalance(accountAddress: 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf, tokenAddress: MockERC20Token: [0xF62849F9A0B5Bf2913b396098F7c7019b51A820a], tokenBalanceType: 3, amount: 0)
│ │ │ │ └─ ← [Stop]
│ │ │ └─ ← [Return]
│ │ ├─ [28076] UpgradeableProxy::addTokenBalance(5, 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf, MockERC20Token: [0xF62849F9A0B5Bf2913b396098F7c7019b51A820a], 5000000000000000000 [5e18])
│ │ │ ├─ [27549] TokenManager::addTokenBalance(5, 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf, MockERC20Token: [0xF62849F9A0B5Bf2913b396098F7c7019b51A820a], 5000000000000000000 [5e18]) [delegatecall]
│ │ │ │ ├─ [534] TadleFactory::relatedContracts(2) [staticcall]

As you can see, an event with zero amount was emitted.

Tools Used

Manual code review

Recommendations

Add a require statement at the beginning of the addTokenBalance function to check that the _amount parameter is greater than zero.

function addTokenBalance(
TokenBalanceType _tokenBalanceType,
address _accountAddress,
address _tokenAddress,
uint256 _amount
) external onlyRelatedContracts(tadleFactory, _msgSender()) {
require(_amount > 0, "Amount must be greater than zero");
userTokenBalanceMap[_accountAddress][_tokenAddress][
_tokenBalanceType
] += _amount;
emit AddTokenBalance(
_accountAddress,
_tokenAddress,
_tokenBalanceType,
_amount
);
}
Updates

Lead Judging Commences

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

Support

FAQs

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