Description:Description\
Conversion between assets (USDE) and shares (EUI) is vulnerable to price manipulation through rounding errors that exceed the intended 1 basis point threshold. This allows malicious users to artificially inflate the share price through strategic deposits and withdrawals. The InvestToken contract fails to properly handle rounding errors during conversions between USDE (assets) and EUI (shares), allowing the share price to be manipulated beyond the intended 1 basis point threshold.
The core issue lies in the bidirectional conversion between assets and shares
function deposit(uint256 assets, address receiver) public returns (uint256 shares) {
shares = convertToShares(assets); // @FOUND - Uses potentially rounded down value
usde.burn(msg.sender, assets);
_mint(receiver, shares);
}
The double conversion between assets and shares can compound rounding errors
Each conversion step potentially loses precision through rounding
The total loss can exceed the intended 1 basis point maximum threshold
Users receive fewer assets than they should when withdrawing
The lost value accumulates in the protocol rather than being returned to users
Vulnerability Details The share price can be manipulated because:
Initial deposit converts assets to shares with potential rounding down
Subsequent withdrawals convert shares back to assets with additional rounding
These compounded rounding errors exceed the 1bp safety threshold
Impact on Other Users
// Victim deposits same amount
victim.deposit(1000000 USDE);
// Receives even fewer shares due to inflated share price
// e.g. 999700 EUI shares
This creates a cascading effect where each deposit/withdraw cycle can further amplify the price manipulation, exceeding the intended 1bp safety threshold and causing increasing losses for subsequent users.
The attack is particularly dangerous because:
It requires minimal capital to execute
Effects compound over time
Losses accumulate in the protocol rather than being distributed
No existing safeguards prevent multiple manipulation cycles
Attack Scenario\
Alice deposits 10000 USDE
System converts to 9999 shares (rounds down)
Bob deposits 1000 USDE
Due to the previous rounding, Bob receives fewer shares than expected
When Bob withdraws, they receive less than their initial deposit
Attachments
Proof of Concept (PoC) File
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
import {Test, console2} from "forge-std/Test.sol";
import {InvestToken} from "../src/InvestToken.sol";
import {IUSDE} from "../src/interfaces/IUSDE.sol";
import {IYieldOracle} from "../src/interfaces/IYieldOracle.sol";
import {IValidator} from "../src/interfaces/IValidator.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
contract InvestTokenTest is Test {
InvestToken public implementation;
InvestToken public investToken;
address public attacker = address(0x1);
address public victim = address(0x2);
Logs:
```mock
Ran 1 test for test/InvestTokenTest.sol:InvestTokenTest
[PASS] testRoundingManipulation() (gas: 65218)
Logs:
=== Initial State ===
=== After Attacker Deposit ===
Deposited USDE: 1000000
Received Shares: 999900
=== After Attacker Withdraw ===
Withdrawn Shares: 999900
Received USDE: 999900
Loss: 100
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.75ms (905.50µs CPU time)
Initial Deposit:
Attacker deposits 1,000,000 USDE
Receives 999,900 shares (100 USDE lost in first conversion)
Withdrawal:
Attacker withdraws 999,900 shares
Receives 999,900 USDE
Total loss: 100 USDE (0.01%)
We can see:
The conversion mechanism introduces rounding errors
These errors result in real value loss for users
The loss is measurable and reproducible
The vulnerability can be exploited to manipulate share prices through repeated deposit/withdraw cycles.
Github username: @0xbrett8571 Twitter username: 0xbrett8571 Submission hash (on-chain): 0x26853c658ca90e0c3a05bfeb37d999a0dca9bc14545a53c949722bb1bd04ebb8 Severity: medium
Description: Description\ Conversion between assets (USDE) and shares (EUI) is vulnerable to price manipulation through rounding errors that exceed the intended 1 basis point threshold. This allows malicious users to artificially inflate the share price through strategic deposits and withdrawals. The InvestToken contract fails to properly handle rounding errors during conversions between USDE (assets) and EUI (shares), allowing the share price to be manipulated beyond the intended 1 basis point threshold.
The core issue lies in the bidirectional conversion between assets and shares
Vulnerability Details The share price can be manipulated because:
Impact on Other Users
This creates a cascading effect where each deposit/withdraw cycle can further amplify the price manipulation, exceeding the intended 1bp safety threshold and causing increasing losses for subsequent users.
The attack is particularly dangerous because:
Attack Scenario\
Attachments
import {Test, console2} from "forge-std/Test.sol"; import {InvestToken} from "../src/InvestToken.sol"; import {IUSDE} from "../src/interfaces/IUSDE.sol"; import {IYieldOracle} from "../src/interfaces/IYieldOracle.sol"; import {IValidator} from "../src/interfaces/IValidator.sol"; import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
contract InvestTokenTest is Test { InvestToken public implementation; InvestToken public investToken; address public attacker = address(0x1); address public victim = address(0x2);
}
Initial Deposit:
Withdrawal:
We can see:
The vulnerability can be exploited to manipulate share prices through repeated deposit/withdraw cycles.
This ensures rounding losses stay within the intended threshold by adding explicit validation.