# OptimisticListingSeaport.propose sets pendingBalances of newly added proposer instead of previous one

OptimisticListingSeaport.propose credits collateral to the new proposer's pendingBalances instead of the previous proposer, letting new proposers propose for free.

- Payout: Contest reward
- Severity: high
- Program: Tessera
- Credited: Lambda
- Disclosed: 2023-04-18
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-12-tessera-findings/issues/12
- Library page: https://bugbountylibrary.com/r/c4%3A2022-12-tessera%3AH-04
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** OptimisticListingSeaport.propose (Solidity contract)
**Root cause:** pendingBalances is updated using proposedListing.proposer after _setListing already overwrote proposedListing with the new proposer, so the credit goes to the wrong account.
**Steps:**
1. Call propose() as bob with collateral _collateral.
2. Observe pendingBalances(vault, bob) == _collateral instead of 0.
3. The previous proposer's collateral is never credited to them, while the new proposer gets a free pending balance.
**How found:** Code reading of propose(): noticed pendingBalances update reads proposedListing.proposer after _setListing mutated proposedListing, then confirmed with a Foundry test asserting pendingBalances(vault, bob) == 0.
**Exploitation:** A proposer repeatedly calls propose(); each call credits their own pendingBalances with the collateral while the prior proposer's collateral is stranded, enabling free proposals and collateral loss for the previous proposer.
**Insight:** When a storage struct is overwritten by a setter before a later field read, check whether the read now returns the new value rather than the pre-update one; ordering of state mutation vs. accounting reads is a common source of miscredited balances.
