# PartyBFacetImpl.chargeFundingRate should check whether quoteIds is empty array to prevent partyANonces from being increased, causing some operations of partyA to fail

PartyB calls chargeFundingRate with empty quoteIds to bump partyANonces, invalidating partyA's signed forceClosePosition/deallocate signatures and blocking them.

- Payout: Contest reward
- Severity: medium
- Program: Symmetrical
- Credited: nobody2018
- Disclosed: 2023-08-28
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-08-symmetrical-judging/issues/41
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-08-symmetrical%3AM-5
- Tags: domain:web3 impact:dos kind:contest platform:sherlock sev:medium tech:evm tech:solidity technique:source-review vuln:business-logic vuln:dos vuln:signature-replay

**Target:** PartyBFacetImpl.chargeFundingRate in symmio-core Solidity contracts
**Root cause:** chargeFundingRate only requires quoteIds.length == rates.length, so an empty array passes the loop and still increments partyANonces[partyA] at line 394. PartyA's Muon-signed operations embed that nonce, so any bump invalidates their signatures.
**Steps:**
1. PartyA calls requestToClosePosition and waits forceCloseCooldown.
2. PartyB front-runs PartyA's forceClosePosition by calling chargeFundingRate(partyA, [], [], upnlSig) with a valid pair upnl signature.
3. Loop over quoteIds is skipped; require(partyAAvailableBalance>=0 && partyBAvailableBalance>=0) passes; partyANonces[partyA] += 1.
4. PartyA's forceClosePosition reverts in LibMuon.verifyPairUpnlAndPrice because the signed nonce is stale.
5. Repeat each time PartyA retries until price moves in PartyB's favor.
**How found:** Code reading of chargeFundingRate: noticed the length-equality check permits empty arrays and that the nonce increment sits outside the loop, then traced which PartyA functions consume partyANonces via LibMuon signature verification.
**Exploitation:** Malicious PartyB monitors the mempool for PartyA's forceClosePosition or deallocate tx, submits chargeFundingRate with empty quoteIds and a fresh Muon upnl signature, incrementing partyANonces and invalidating PartyA's signature; cost is only gas.
**Escalation:** Same nonce-bump primitive also blocks deallocate and transferAllocation, letting PartyB hold positions open until price favors it.
**Insight:** When a function increments a signature nonce, check whether the guarded loop can be skipped (empty array, zero iterations) so the nonce bump becomes a cheap griefing primitive against the counterparty's signed actions.
