# OperatorProposal.sol: Leftover ETH is not refunded to the msg.sender

OperatorProposal forwards operatorValue ETH to the operator but never refunds unused ETH returned by the operator, stranding the executor's funds in the Party contract.

- Payout: Contest reward
- Severity: medium
- Program: PartyDAO
- Credited: HollaDieWaldfee
- Disclosed: 2023-06-23
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-04-party-findings/issues/5
- Library page: https://bugbountylibrary.com/r/c4%3A2023-04-party%3AM-10
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity vuln:accounting-error

**Target:** OperatorProposal.sol proposal execution contract
**Root cause:** OperatorProposal sends data.operatorValue to the operator and returns immediately after execute(); any ETH the operator refunds back to the proposal contract is retained rather than forwarded to msg.sender.
**Steps:**
1. Executor calls execute with msg.value >= data.operatorValue while allowOperatorsToSpendPartyEth=false.
2. OperatorProposal calls `data.operator.execute{value: data.operatorValue}(...)`.
3. CollectionBatchBuyOperator spends only totalEthUsed and refunds `unusedEth = msg.value - totalEthUsed` back to OperatorProposal via `payable(msg.sender).transferEth(unusedEth)`.
4. OperatorProposal hits `return ""` without forwarding the refunded ETH to the executor, so the balance stays in the Party contract.
**How found:** Code reading of OperatorProposal's execute flow against CollectionBatchBuyOperator's refund logic; noticed the operator refunds to msg.sender (the proposal) but the proposal never forwards it, and confirmed with the sponsor that refunds are expected when allowOperatorsToSpendPartyEth=false.
**Exploitation:** Any executor who over-funds an OperatorProposal (e.g. batch buy where some purchases fail or cost less than operatorValue) permanently loses the unused ETH, which accrues to the Party. No attacker needed; loss occurs on normal use.
**Insight:** When a contract forwards value to a callee that can refund excess, trace where the refund lands: if the callee refunds to msg.sender (the intermediary), the intermediary must explicitly forward it or funds are stranded.
