Omniscia BlazeSwap Audit
BlazeSwapBasePair Manual Review Findings
BlazeSwapBasePair Manual Review Findings
BSB-01M: Inexplicable Usage of Unchecked Mathematical Operations
Type | Severity | Location |
---|---|---|
Mathematical Operations | BlazeSwapBasePair.sol:L168-L170 |
Description:
The linked unchecked
code block is ill-advised as the reserve multiplications can in certain edge cases overflow and should be prevented from doing so, as is the case in the original Uniswap implementation.
Impact:
An overflow in the referenced calculation can cause abnormal fee amounts that would in turn negatively impact all fee recipients the BlazeSwap pair supports.
Example:
168unchecked {169 if (feeOn) kLast = uint256(reserve0) * reserve1; // reserve0 and reserve1 are up-to-date170}
Recommendation:
We advise the unchecked
specifier to be omitted from the referenced calculation to ensure it is performed safely.
Alleviation:
The BlazeSwap team evaluated this exhibit and assessed that an overflow in the referenced case cannot occur given that the maximum result of two uint112
numbers multiplied between them would fit within a uint224
which is a type lower in accuracy than the uint256
that the result is currently stored in. As a result, we consider this exhibit as nullified.
BSB-02M: Incorrect K System Fee Assumptions
Type | Severity | Location |
---|---|---|
Mathematical Operations | BlazeSwapBasePair.sol:L206 |
Description:
The _recordSwapFees
function contains incorrect assumptions as to the Uniswap K-based fee system as it performs a subtraction of two values that have been multiplied between them without any safety checks.
Impact:
An underflow that should otherwise be ignored can currently lead to swaps failing incorrectly. Fees accrued in the pendingFeeTotal
variable may also be ultimately unclaimable depending on the design behind the fee share system.
Example:
199function _recordSwapFees(200 uint112 oldReserve0,201 uint112 oldReserve1,202 bool splitFee203) private {204 if (kLast != 0) {205 (uint112 newReserve0, uint112 newReserve1, ) = getReserves();206 uint256 feeShare = uint256(newReserve0) * newReserve1 - uint256(oldReserve0) * oldReserve1;207 pendingFeeTotal += feeShare;208 if (splitFee) {209 (address splitFeeRecipient, uint256 splitFeeBips) = IBlazeSwapBaseManager(manager).getTradingFeeSplit(210 msg.sender211 );212 if (splitFeeRecipient != address(0) && splitFeeBips > 0) {213 uint256 splitFeeShare = (feeShare * splitFeeBips) / 100_00;214 if (feeShare > 0) {215 uint256 oldFeeShare = pendingFeeShare[splitFeeRecipient];216 if (oldFeeShare == 0) {217 pendingFeeAccount.push(splitFeeRecipient);218 }219 pendingFeeShare[splitFeeRecipient] += splitFeeShare;220 }221 }222 }223 }224}
Recommendation:
We advise each multiplication sum to be stored to a dedicated variable and the function to continue execution only when uint256(newReserve0) * newReserve1
is greater-than (>
) the value of uint256(oldReserve0) * oldReserve1
as otherwise it will cause an underflow to halt the transaction contrary to the _mintFee
implementation. Additionally, the pendingFeeTotal
calculated is not based on the square root of the values and instead uses a dry sum delta which may not be ultimately satisfied by the fee tracked by _mintFee
. As a result, we advise the specialized swap fee system to be re-evaluated, expanded in documentation and potentially re-written as it currently appears dis-joint with the actual fees generated by the BlazeSwap model.
Alleviation:
The BlazeSwap team evaluated this exhibit and deemed the current calculations to be correct as the constant product formula of Uniswap V2 that BlazeSwap is derived from guarantees that the new reserve product will be greater than the old reserve product. Additionally, the fee tracked here is the delta in the product rather than the squared root end-fee as those calculations are meant to be carried out in the _mintFee
function by design. As a result of BlazeSwap's assessment, we consider this exhibit nullified.