Internalizer::_transfer()
unsafe data type conversion may cause serious problems
Type conversion truncates the high bits that exceed the bit width of the target type. Therefore, when you convert a uint256 type maximum value (type(uint256).max) to a uint128 type, the converted value is actually the maximum value of the uint128 type (type(uint128).max).
When you convert type(uint256).max to a uint128 type, only the lower 128 bits are retained and the upper 128 bits are truncated. Therefore, the converted value is the maximum value of uint128 and there will be no error message.
The maximum value of the uint256 type is 2^256 - 1
, which is 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
.
The maximum value of the uint128 type is 2^128 - 1
, which is 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
.
Since Internalizer::_transfer()
is used to override Fertilizer1155::_transfer()
, Internalizer::_transfer()
will be executed when Fertilizer1155::safeTransferFrom()
, Fertilizer1155::safeBatchTransferFrom()
and other methods are called.
Let's take Fertilizer1155::safeTransferFrom()
as an example:
Inaccurate event logs: The transfer amounts recorded by emit TransferBatch(operator, from, to, ids, amounts);
do not match the actual amounts transferred. This can cause inaccurate states recorded by external systems that rely on these event logs for state tracking or auditing (such as blockchain browsers, indexers).
Inconsistent state updates: Due to the truncation of amounts, the actual updated amounts in _balances are less than expected, which may cause the internal state of the contract to be inconsistent with the external expected state, further leading to fund mismatches or account balance errors.
Possible security vulnerabilities: Attackers may exploit this to bypass certain checks or restrictions by passing an amount exceeding type(uint128).max, especially when other logic depends on these amounts.
When calling _transfer
in Fertilizer1155::safeTransferFrom()
, if amount exceeds type(uint128).max, the following may happen:
For the from
account:
If amount exceeds type(uint128).max
, _amount will be truncated to type(uint128).max, and require will still check the original amount, which may cause incorrect state updates.
For the to
account:
The actual amount received by the to account is _amount (the truncated amount), not the expected amount.
https://github.com/Cyfrin/2024-05-beanstalk-the-finale/blob/8c8710df547f7d7c5dd82c5381eb6b34532e4484/protocol/contracts/tokens/Fertilizer/Internalizer.sol#L71-L85
https://github.com/Cyfrin/2024-05-beanstalk-the-finale/blob/8c8710df547f7d7c5dd82c5381eb6b34532e4484/protocol/contracts/tokens/Fertilizer/Fertilizer1155.sol#L77
https://github.com/Cyfrin/2024-05-beanstalk-the-finale/blob/8c8710df547f7d7c5dd82c5381eb6b34532e4484/protocol/contracts/tokens/Fertilizer/Fertilizer1155.sol#L19-L48
https://github.com/Cyfrin/2024-05-beanstalk-the-finale/blob/8c8710df547f7d7c5dd82c5381eb6b34532e4484/protocol/contracts/tokens/Fertilizer/Fertilizer1155.sol#L50-L75
Internalizer::_transfer()
unsafe data type conversion may cause serious problems
Manual Review
Perform checks before conversion
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.