# `updatePositionFromBalanceMargin` function returns "0" if amount to be updated is negative

In Elfi's PositionMarginProcess, zeroing initialMarginInUsdFromBalance before computing changeAmount makes the update return 0, leaving other cross positions' fromBalance too high and letting accounts over-borrow.

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

**Target:** PositionMarginProcess.sol updatePositionFromBalanceMargin (perpetuals margin accounting)
**Root cause:** When addBorrowMarginInUsd exceeds initialMarginInUsdFromBalance, the storage pointer is set to 0 before changeAmount is derived from it, so changeAmount becomes 0 instead of the remaining balance.
**Steps:**
1. Have three cross positions (WBTC, SOL, WETH) with differing marginFromBalance/initialMarginInUsdFromBalance.
2. Close WBTC at a loss producing negative changeToken (e.g. -110).
3. updatePositionFromBalanceMargin loops positions; for SOL addBorrowMarginInUsd=110 > initialMarginInUsdFromBalance=50, so it sets initialMarginInUsdFromBalance=0 then computes changeAmount from the now-zero value -> 0.
4. Loop proceeds to WETH without deducting the 50 already consumed, resetting its initialMarginInUsdFromBalance entirely.
5. Result: aggregate fromBalance understated, allowing excess borrowing.
**How found:** Code reading of the negative-amount branch: noticed the storage pointer is zeroed before changeAmount is computed from it, making the return always 0.
**Exploitation:** Attacker opens multiple cross positions, closes one at a loss to trigger the negative-changeToken path, and exploits the resulting understated fromBalance to borrow beyond allowed limits.
**Insight:** When a storage pointer is mutated before a derived value is computed from it, the derived value silently becomes zero — audit ordering of state writes vs. reads within the same branch.
