AgentSkillsCN

rounding-issues-and-exploits

该技能旨在发现Solidity智能合约中的四舍五入问题或潜在漏洞。在处理涉及资产与代币互转、资产份额铸造或反向操作、利息计算、费用计算,以及与兑换/交易活动相关的数学运算时,应使用此技能。

SKILL.md
--- frontmatter
name: rounding-issues-and-exploits
description: This skill aims to spot rounding issues or exploits inside Solidity smart contracts. This skill should be used when dealing with DeFi smart contracts that include math operations for assets to shares minting or the other way around, interest calculations, fee calculations or math operations related to swapping/ trading activity.

Rounding issues and exploits analysis

Detect vulnerabilities that allow attackers to harm protocol's funds or other user's funds. These attacks are most likely used to steal funds directly from the protocols.

When to Use

  • Reviewing logic that includes yield bearing assets — conversion of assets to shares and vice versa
  • Reviewing logic that includes interest calculation ( e.g. borrow or repay actions )
  • Reviewing logic involving fees calculation and distribution
  • Math operations calculating liquidations and collateral positions state update
  • Any math logic that includes calculations of swapping or trading input or output amounts

When NOT to Use

  • Contracts with no math calculations

Examples of rounding issues and exploits

Case 1: Solidity doesn't support Floating Point Arithmetic

Solidity doesn’t support floats by default which means that 10 / 3 * 5 and 10 * 5 / 3 in Solidity will never have the same output. In the first case the output is 15 and in the second the output is 16. To reduce precision loss we must always first multiply and then divide.

Case 2: Dividing to bigger number will result to 0

Check if there are scenarios where the divisor is actually bigger than the dividend. In Solidity this will be returned as 0 and not reverting. Example:

code
10 / 50 will equal to 0.

Case 3: Can't divide by 0

A division by zero will revert in Solidity. This case should never exist.Example:

code
10 / 0 will revert.

Case 4: Never leave the rounding direction unclear

The rounding dicrection has to be explicitly defined — to be up or down with proper comments why this decision has been made. The accepted approach is to always round up in favour of the protocol:

  • When calculating amounts paid out to users → round down
  • When calculating amounts paid in by users → round up
  • This “protocol-first” approach is what actually OZ's ERC4626 does:
    • When user is depositing though the deposit method then the shares are calculated with down rounding
    • When user is depositing through the mint method then the assets are calculated with the up rounding
    • When user is withdrawing though the withdraw method then the shares are calculated with up rounding
    • When user is withdrawing though the redeem method then the assets are calculated with down rounding
  • The “protocol-first” approach should also be considered when calculating trading fees or withdrawal fees. Round down in this example could lead to user exploiting actions with smaller amounts in order to skip paying any fees. This is why we have to round up here.

Very often mistake is that the developer has used the same rounding direction in opposite method e.g. deposit and withdraw.

Case 5: Wrong percentage calculation

All fees or interest calculations include multiply and division to values lesser than 1. However Solidity doesn't support floats thus making 0.3% fee charge or 3% borrow interest calculations not a straight forward thing to calculate. We need to scale up the percentage values and then divide. For example let's say that we have uint256 tradingFee = 3000. This means that we have to multiply amount with tradingFee and then divide by 10000. It's possible that protocol builder has missed a 0 which leads to false calculation — amount * 3000 / 1000.

Additional Analysis

Beyond the patterns above, apply your full security knowledge to identify any related issues not covered here.