Attackers can trigger precision loss issues by calling the deposit and withdraw functions in the PerpetualVault contract to manipulate share prices and steal assets deposited by other users.
contracts/PerpetualVault.sol#L215-280
After the PerpetualVault contract is deployed, be the first to perform a deposit operation (amount = minDepositAmount = 1e8). At this time, shares will be minted in the _mint function according to _shares = depositInfo[depositId].amount * 1e8;, obtaining share = 1e16.
The attacker then sends a large amount of collateralToken to the contract (assume amount = 1e16), raising the share price to 1e16 share = 1e16 + 1e8 amount.
After the attacker raises the share price, perform another deposit operation (amount = 2 * 1e8). The share amount will be calculated according to _shares = amount * totalShares / totalAmountBefore;. The resulting share amount is 1.
Contract state at this point: 1e16 + 1 share = 1e16 + 3e8 amount
The attacker then calls the withdraw function to retrieve the first funds (share = 1e16). According to amount = collateralToken.balanceOf(address(this)) * shares / totalShares;, the calculated amount = 1e16 + 3e8
Contract state at this point: 1 share = 0 amount
The attacker sends another large amount of collateralToken to the contract (assume amount = 1e16), raising the share price to 1 share = 1e16 amount.
When victim users unknowingly make a deposit operation (amount = 1e15) after the attacker raises the share price, the share amount will be calculated according to _shares = amount * totalShares / totalAmountBefore;. The user receives 0 shares at this time. (As long as the user's deposit amount is less than 1e16, the obtained share will be 0).
Contract state at this point: 1 share = 1e16 + 1e15 amount
Finally, the attacker calls the withdraw function to retrieve the second funds (share = 1). According to amount = collateralToken.balanceOf(address(this)) * shares / totalShares;, the calculated amount = 1e16 + 1e15.
Contract state at this point: 0 share = 0 amount, and the attacker has obtained the victim user's deposit of 1e15.
Attackers can manipulate the share price to prevent other users from obtaining share when depositing assets, thereby stealing user assets.
This attack scenario can be executed using a sandwich attack when discovering a user performing the first deposit operation, placing the user's deposit operation in the middle to profit.
It is recommended to refer to Compound or AAVE's approach, where the project team makes the first deposit when creating a new PerpetualVault.
Prevent tokens from getting stuck. This is a simple donation to every shareholder, and therefore, every share has more value (profit), leading to fewer shares for future users. If this is not intended by the user, it is merely a mistake! For totalAmountBefore > amount * totalShares, Here is the worst-case scenario (with the minimum amount): first deposit 0.001000 (e4) USDC → 1e12 shares. Second deposit: 0.001 (e4) USDC * 1e12 / 0.001 (e4) USDC. So, the attacker would need to donate 1e16 tokens, meaning 1e10 USDC → 10 billion $. Even in the worst case, it's informational.
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.