# Improper implementation of the `PositionMarginProcess.updatePositionFromBalanceMargin()` function.

Elfi Protocol's updatePositionFromBalanceMargin computes margin updates from stale USD ratios instead of current marginToken price, letting users update positions at inflated prices.

- Payout: Contest reward
- Severity: high
- Program: Elfi Protocol
- Credited: 0x486776
- Disclosed: 2024-05-09
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2024-05-elfi-protocol-judging/issues/159
- Library page: https://bugbountylibrary.com/r/sherlock%3A2024-05-elfi-protocol%3AH-28
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:high tech:solidity technique:source-review vuln:accounting-error vuln:business-logic vuln:oracle-manipulation

**Target:** Perpetual futures PositionMarginProcess contract (Solidity)
**Root cause:** updatePositionFromBalanceMargin derives changeAmount and initialMarginInUsdFromBalance purely from ratios of stored initialMarginInUsd/initialMargin, never consulting the current marginToken price, so stale higher prices persist.
**Steps:**
1. Open a position with marginToken at price P1, setting initialMarginInUsd and initialMarginInUsdFromBalance.
2. marginToken price drops to P2 << P1.
3. Call the deposit/withdraw path invoking updatePositionFromBalanceMargin with amount>0.
4. Observe borrowMargin and initialMarginInUsdFromBalance computed from stored USD ratios (L314/L318), not P2.
5. Position's initialMarginInUsdFromBalance is updated as if token still worth P1.
**How found:** Code reading of PositionMarginProcess.sol L303-L338; noticed all math uses percentage ratios of stored initialMarginInUsd and never references current marginToken price.
**Exploitation:** User updates position margin accounting using the stale higher price, inflating initialMarginInUsdFromBalance relative to actual token value, gaining favorable margin accounting versus current market price.
**Insight:** In perp/DEX margin accounting, any function converting between token amounts and USD must re-read the oracle price; ratio-only math on stored USD fields silently freezes the price at last update.
