Blazing Trading Suite
Smart Contract Security Assessment
July 20, 2024

SUMMARY
ABSTRACT
Dedaub was commissioned to perform a security audit of the** Blazing Trading Suite** protocol. The auditors reported 3 high-severity issues, 1 medium-severity issue, 6 low-severity issues, and 3 advisory issues. The auditors have also identified 4 protocol-level considerations that do not currently result in security issues but would harden the protocol further if addressed.
BACKGROUND
The Blazing Trading Suite protocol provides a wrapper around Uniswap V2 and Uniswap V3 pools, providing many useful convenience functions for interacting with these pools.
The codebase is divided into three parts, a minimal version of Blazing Trading Suite called helper, and more comprehensive versions of Blazing Trading Suite called V2 and V3, which interact with Uniswap V2 and V3 respectively.
The functionality provided by Blazing Trading Suite includes dispersing native and ERC20 tokens to different addresses, providing bribes for miners, checking the liquidity of pools, checking whether pools are honeypots and checking the taxes levied by the pools. Blazing Trading Suite also allows orchestrating multi-hop swaps, by specifying the amountIn
or amountOut
expected from the transaction. Blazing Trading Suite also supports the transfer of funds through the PERMIT2 scheme. Fees are collected by the protocol in return for using Blazing Trading Suite.
The protocol is highly optimised and uses low-level code to promote gas savings. The auditors found the code to be well-structured and well-documented.
SETTING & CAVEATS
This audit report mainly covers the contracts of the blazing-contract repository of the Blazing Trading Suite Protocol at commit 89970eea6047d9f9eeb9998543a118fde5a69ab6
.
Two auditors worked on the codebase for 12 days on the following contracts:
- helper/
- BlazingHelperV1.sol
- BlazingHelperV2.sol
- base/
- Dispatcher.sol
- HelperParameters.sol
- LockAndMsgSender.sol
- interfaces/
- IBlazingHelper.sol
- libraries/
- BytesLib.sol
- Commands.sol
- Constants.sol
- modules/
- payments/
- Payments.sol
- PaymentsImmutables.sol
- v2/
- BlazingRouterV21.sol
- BlazingRouterV22.sol
- base/
- Dispatcher.sol
- LockAndMsgSender.sol
- ProtocolTaxesManager.sol
- RouterParameters.sol
- interfaces/
- IBlazingRouter.sol
- IDexPairMinimal.sol
- IWETH9.sol
- libraries/
- BytesLib.sol
- Commands.sol
- Constants.sol
- Multichain.sol
- modules/
- dex/
- DexHelper.sol
- SwapRouter.sol
- payments/
- Payments.sol
- PaymentsImmutables.sol
- Permit2Payments.sol
- protection/
- Protection.sol
- v3/
- BlazingRouterV31.sol
- BlazingRouterV32.sol
- base/
- Dispatcher.sol
- LockAndMsgSender.sol
- ProtocolTaxesManager.sol
- RouterParameters.sol
- interfaces/
- IBlazingRouter.sol
- IDexPairMinimal.sol
- IWETH9.sol
- libraries/
- BytesLib.sol
- Commands.sol
- Constants.sol
- Multichain.sol
- modules/
- dex/
- DexHelper.sol
- DexPath.sol
- SwapRouter.sol
- payments/
- Payments.sol
- PaymentsImmutables.sol
- Permit2Payments.sol
- protection/
- Protection.sol
After the code was audited, the auditors examined fixes to the issues in this report contained in the following commit numbers:
fed07499c4d88e1293bee4e99abbec374d847755
b54ee152d73624ec8ff7a30e27a251fbb952b82a
5b0ca96edab2abe9e63705ca2d811c65f80791411
Following this the auditors updated the report to reflect which issues were resolved and the manner in which they were resolved.
The audit’s main target is security threats, i.e., what the community understanding would likely call "hacking", rather than the regular use of the protocol. Functional correctness (i.e. issues in "regular use") is a secondary consideration. Typically it can only be covered if we are provided with unambiguous (i.e. full-detail) specifications of what is the expected, correct behavior. In terms of functional correctness, we often trusted the code’s calculations and interactions, in the absence of any other specification. Functional correctness relative to low-level calculations (including units, scaling and quantities returned from external protocols) is generally most effectively done through thorough testing rather than human auditing.
PROTOCOL-LEVEL CONSIDERATIONS
The following protocol-level considerations represent some general observations about the protocol. While the auditors did not link these to an immediate threat to the protocol, we suggest that the team consider the following best practice to further harden the protocol and reduce its possible attack surface.
Dismissed
The team has indicated that it already has control over which pools will be used in the router because all of the transaction calldata will be created from the Blazing Trading Suite backend.
In general, the Blazing Trading Suite protocol allows users to interact with arbitrary pools. Some of these pools can have malicious behaviours and transferring control to them can expose the protocol to reentrancy attacks. Although no specific attack was identified, we suggest whitelisting the pools which the protocol is allowed to interact with.
Partially resolved
The team has added a check to ensure that only InvalidNonce() errors are accepted. The fix was applied only to BlazingRouterV21 as this will be the production version.
Dispatcher::permit2PermitDispatch
accepts a failed call to PERMIT2.permit
if a valid allowance is already set, in order to prevent DoS scenarios in which an adversary intercepts the signature and calls permit himself in order to make the "duplicate" permit fail. Although we understand the motivation, and this behaviour does not by itself create an immediate threat, this is still not a safe practice and could potentially facilitate an attack scenario in combination with other vulnerabilities. While a valid permit included in a transaction shows the intention to spend the corresponding funds, if the permit is invalid, the user's intention is much less clear. The contract will even accept permits with wrong signatures (not just duplicates), and tolerating wrong signatures makes it easier to exploit vulnerabilities.
We recommend limiting the accepted errors as much as possible. For instance, the contract could accept only InvalidNonce()
errors from Permit2
, which indicate a possible replay attack, but _not_ incorrect signatures. Moreover, the contract could check that the expiration of the existing allowance is exactly that of the submitted permit, not just greater or equal, again trying to accept duplicate permits while minimising other accepted errors.
Acknowledged
The team has indicated that this issue is not a priority at the moment, but that it could be revisited in the future.
The contract's balance is used to store two unrelated things: taxes and user funds for the currently executed swaps. This mix could potentially lead to a loss of funds if an accounting bug is found, either in the current code or in future iterations. Although we did not identify accounting issues, the risk would be substantially lowered by keeping taxes in a separate contract that never receives user funds.
Resolved
The fix was applied only to BlazingRouterV21 as this will be the production version.
BlazingRouter::execute
considers any funds which are owned by the contract and which are not fees as belonging to the user, even if the funds were not obtained in the current transaction.
This can allow an adversary to artificially inflate the contract's balance at any moment, by transferring an arbitrary amount of native token to the contract (via selfdestruct
), knowing that he can recover these funds in the next transaction.
Although we did not identify a specific attack, the possibility of arbitrarily inflating the contract's balance is commonly exploited in combination with other vulnerabilities, hence it would be preferable to avoid it.
An alternative could be to consider that only funds obtained in the current transaction belong to the user, and keep the remaining funds in the contract, making it financially difficult for the adversary to inflate the balance.
VULNERABILITIES & FUNCTIONAL ISSUES
This section details issues affecting the functionality of the contract. Dedaub generally categorises issues according to the following severities, but may also take other considerations into account such as impact or difficulty in exploitation:
- User or system funds can be lost when third-party systems misbehave.
- DoS, under specific conditions.
- Part of the functionality becomes unusable due to a programming error.
- Breaking important system invariants but without apparent consequences.
- Buggy functionality for trusted users where a workaround exists.
- Security issues which may manifest when the system evolves.
Issue resolution includes “dismissed” or “acknowledged” but no action taken, by the client, or “resolved”, per the auditors.
CRITICAL SEVERITY
[No critical severity issues]
HIGH SEVERITY
The BlazingRouterV21 execute
function reverts if currentBalance < newProtocolTaxesBalance
. If there is any bug in the protocol, the execute
function will freeze and brick the entire protocol. This also affects the BlazingRouterV22
, BlazingRouterV31
and BlazingRouterV32
contracts.
Resolved
Gaps have been introduced in BlazingRouterV21. BlazingHelperV1 and BlazingHelperV2 are no longer UUPSUpgradable. BlazingRouterV22 and BlazingRouterV23 do not contain this fix as they are not production versions.
The contracts use the UUPS pattern but do not use “gaps” to leave space for future state variables. As a consequence, adding a state variable to any base contract will break the state layout after the upgrade.
MEDIUM SEVERITY
Dismissed
The team has indicated that this parameter is handled by the Blazing Trading Suite backend, and that thus no further action is necessary.
The /helper/modules/payments/Payments contract has a disperseChainCurrency
function which loops over a recipients array to disperse the chain currency to users. This function is called by the /helper/base/Dispatcher::disperseChainCurrencyDispatch function which indicates that it is supposed to be able to handle a maximum of 838_860 recipients. We advise metering this function to ensure that the disperseChainCurrency
function does not run out of gas over such a large number of recipients before deployment. The same issue affects Payments::disperseToken
.
LOW SEVERITY
Resolved
This issue was resolved in BlazingRouterV21. BlazingRouterV22 and BlazingRouterV23 do not contain this fix as they are not production versions.
The BlazingRouterV21 contract inherits from Initializable and OwnableUpgradable. However, its parent /v2/base/LockAndMsgSender already inherits from Initializable, and its parent /v2/base/ProtocolTaxesManager already inherits from Initializable and from OwnableUpgradable. This issue also affects BlazingRouterV22, BlazingRouterV31 and BlazingRouterV32 (the latter two relative to the /v3/base contracts).
The /v2/base/Dispatcher inherits from Payments, but its parent /v2/modules/payments/Permit2Payments already inherits from the /v2/modules/payments/Payments contract. Also affects /v3/base/Dispatcher.
The /v2/modules/Protection contract has a checkHoneyPot
function which reverts if the interaction with the pool fails with a reason which is not 64 bytes long. However this exposes the users to honeypots with a reason which is 64 bytes long.
The /v2/modules/Protection contract has a function called checkLiquidity
which checks that the final pool on a swap path has liquidity between certain lower and upper bounds. However, it does not check that the intermediate pools also have a certain liquidity, which may be misleading to the caller of the function. Also affects /v3/modules/Protection.
Acknowledged
The team has indicated that this will be handled on the backend.
Although not enforced, the comments in Dispatcher::permit2PermitDispatch
suggest that expiration = 0
will always be used. However, this does not necessarily increase security; the permit will be valid for just the current block, but it will be accepted in _any_ block. In a hypothetical scenario in which the adversary wants to use the permit in some attack, if the transaction is not executed (so the permit
remains valid), it will stay valid forever and the adversary can submit it himself at any moment, the only constraint being that he will need to execute his attack in the same block (a quite soft constraint).
In some scenarios, for instance transactions with a forced block or known deadline, it might be actually preferable to set the expiration to that specific block, severely limiting the lifespan of the permit.
OTHER / ADVISORY ISSUES
This section details issues that are not thought to directly affect the functionality of the project, but we recommend considering them.
The /helper/modules/payments/Payments contract has two functions disperseChainCurrency
and disperseToken
which should check whether the recipients and the values array have the same length if the useSameAmount
flag is false.
The /v2/base/ProtocolTaxesManager function is an onlyOwner setter function, but does not have any validations on the tax amounts being set. Also affects /v3/base/ProtocolTaxesManager.
The /v3/libraries/BytesLib toLastPool
function assigns a hex value to the offsetValue variable and a decimal value to the lastPoolOffsetSub variable. We recommend choosing one representation for consistency.
The code is compiled with Solidity ^0.8.20
. For deployment, we recommend no floating pragmas, but a specific version, to be confident about the baseline guarantees offered by the compiler. Version 0.8.20
, in particular, has some known bugs, which we do not believe affect the correctness of the contracts.
DISCLAIMER
The audited contracts have been analyzed using automated techniques and extensive human inspection in accordance with state-of-the-art practices as of the date of this report. The audit makes no statements or warranties on the security of the code. On its own, it cannot be considered a sufficient assessment of the correctness of the contract. While we have conducted an analysis to the best of our ability, it is our recommendation for high-value contracts to commission several independent audits, a public bug bounty program, as well as continuous security auditing and monitoring through Dedaub Security Suite.
ABOUT DEDAUB
Dedaub offers significant security expertise combined with cutting-edge program analysis technology to secure some of the most prominent protocols in DeFi. The founders, as well as many of Dedaub's auditors, have a strong academic research background together with a real-world hacker mentality to secure code. Protocol blockchain developers hire us for our foundational analysis tools and deep expertise in program analysis, reverse engineering, DeFi exploits, cryptography and financial mathematics.