Description:
The burn
function in the token contract applies burn tax to the amount being burned and attempts to transfer this tax to the feeCollector
address. However, this tax transfer itself triggers the taxation mechanism again through the internal _transfer
function, which calls _update
to apply tax logic. This recursive taxation results in the feeCollector
receiving less than the intended tax amount.
Impact:
This vulnerability has moderate impact with multiple consequences:
Revenue Loss: The feeCollector
consistently receives less than the designated tax amount from burn operations.
Protocol Sustainability Risk: If the protocol relies on these fees for operational expenses or treasury growth, the shortfall could affect long-term sustainability.
Accounting Inconsistencies: The expected vs. actual tax collection creates discrepancies in financial reporting and projections.
Potential for Strategic Exploitation: Sophisticated users might leverage this behavior to minimize effective tax paid when burning large token amounts.
The severity is considered moderate because while it doesn't lead to direct fund loss for users, it represents a persistent financial leakage from the protocol's revenue model.
Proof of Concept:
When a user burns tokens, the process works as follows:
User initiates burning 1,000 tokens with a 5% burn tax rate
The contract calculates tax: 1,000 * 5% = 50 tokens
The contract burns 950 tokens from the user's balance
The contract attempts to transfer 50 tokens to the feeCollector
During this transfer, the _transfer
function calls _update
, which applies taxation logic again
Assuming the same 5% tax rate, the 50 tokens being transferred are taxed again: 50 * 5% = 2.5 tokens
The feeCollector
actually receives 47.5 tokens instead of the intended 50 tokens
The additional 2.5 tokens either remain with the sender or are sent to another fee address, depending on the implementation
This process results in an effective tax rate lower than the configured rate and inconsistent fee collection.
Recommended Mitigation:
Implement a specialized transfer function that bypasses the taxation mechanism when transferring burn taxes to the feeCollector
:
Create a new internal function _transferWithoutTax
that temporarily marks addresses as whitelisted during the transfer operation.
Modify the burn
function to use this specialized transfer function when sending tax to the feeCollector
.
Add appropriate access controls to ensure this tax-free transfer mechanism cannot be exploited by unauthorized parties.
Consider adding events to clearly log burn operations, tax amounts, and actual amounts received by the fee collector for transparency.
Add unit tests specifically verifying that the fee collector receives exactly the expected amount of tax when burns occur.
This approach ensures that burn taxes are collected as intended while maintaining the security of the taxation system for regular transfers.
This is by design, sponsor's words: Yes, burnt amount, done by whitelisted contract or not always occur the tax. The feeCollector is intended to always be whitelisted and the address(0) is included in the _transfer as a bypass of the tax amount, so upon burn->_burn->_update it would have not applied (and would also do another burn...). For this reason, to always apply such tax, the burn function include the calculation (the 2 lines that applies) and a direct transfer to feeCollector a little bit later. This is done purposefully
This is by design, sponsor's words: Yes, burnt amount, done by whitelisted contract or not always occur the tax. The feeCollector is intended to always be whitelisted and the address(0) is included in the _transfer as a bypass of the tax amount, so upon burn->_burn->_update it would have not applied (and would also do another burn...). For this reason, to always apply such tax, the burn function include the calculation (the 2 lines that applies) and a direct transfer to feeCollector a little bit later. This is done purposefully
This is by design, sponsor's words: Yes, burnt amount, done by whitelisted contract or not always occur the tax. The feeCollector is intended to always be whitelisted and the address(0) is included in the _transfer as a bypass of the tax amount, so upon burn->_burn->_update it would have not applied (and would also do another burn...). For this reason, to always apply such tax, the burn function include the calculation (the 2 lines that applies) and a direct transfer to feeCollector a little bit later. This is done purposefully
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.