In the last few months, we’ve observed an increasing number of vulnerabilities in DeFi applications that fall into a common pattern: bidirectional rounding.
If a smart contract has a bidirectional function or functions (e.g., swap between a pair of tokens or mint/redeem a token) and the function uses the same rounding operation over arithmetic results in both directions, then the function is likely vulnerable to two-way trading attacks.
In this article, we explain the key issues of bidirectional rounding and show how sec3 Pro automatically detects this type of rounding vulnerabilities.
The reason is simple: bidirectional rounding may allow attackers to exploit round-off errors to gain profit for free through round-trip trading:
Although profit is small in each round-trip trade (steps 1–2), the round-trip may be repeated many times, eventually leading to significant losses to the protocol.
Let’s consider a real-world example of bidirectional rounding in the spl token-lending program (discovered by Neodyme originally, see “How to Become a Millionaire, 0.000001 BTC at a Time”):
The functions liquidity_to_collateral and collateral_to_liquidity are a pair of bidirectional functions, called by deposit_liquidity and redeem_collateral respectively.
In each direction, given an input collateral_amount or liquidity_amount, the functions compute liquidity_amount or collateral_amount.
However, in both directions, the functions use the same rounding operation try_round_u64 internally:
Since rounding up or down can be controlled by the attacker through the inputs collateral_amount and liquidity_amount, a two-way swap can be made profitable.
The fixes to bidirectional rounding depend on the semantics of the code, but in most common cases can be simple:
The fixes above (i.e., adding to a floor() operation to amount_out and a ceil() operation to fee) ensure that amount_out is always rounded down and fee is always rounded up, thus a round-trip trade is no longer profitable.
For example, the fixes in spl token-lending apply a try_floor_u64() operation to ensure the result is always rounded down:
Note: bidirectional rounding vulnerabilities do not necessarily need two different functions, but can exist in a single function that handles two-way trading, such as swap.
sec3 Pro is the premier security analysis service for Solana smart contracts. To detect bidirectional rounding issues:
The tool first finds out all the bidirectional functions in the whole smart smart including dependencies. For each bidirectional function, it locates rounding signatures (e.g., often Integer multiplications followed by division) and if the result of any rounding operation is not consistently rounded up or down, then the tool flags a potential vulnerability.
The following shows a screenshot of bidirectional rounding reported by Sec3 Pro in our example. The sec3 Pro is available at https://pro.sec3.dev
sec3 is a security research firm that prepares Solana projects for millions of users. sec3’s Launch Audit is a rigorous, researcher-led code examination that investigates and certifies mainnet-grade smart contracts; sec3’s continuous auditing software platform, X-ray, integrates with GitHub to progressively scan pull requests, helping projects fortify code before deployment; and sec3’s post-deployment security solution, WatchTower, ensures funds stay safe. sec3 is building technology-based scalable solutions for Web3 projects to ensure protocols stay safe as they scale.
To learn more about sec3, please visit https://www.sec3.dev