# Funds are permanently stuck in OptimisticListingSeaport.sol contract if active proposal is executed after new proposal is pending.

Overwriting vaultOrderHash when a new proposal is made bricks _verifySale, permanently locking sale proceeds in OptimisticListingSeaport.

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

**Target:** OptimisticListingSeaport.sol vault order hash / cash() settlement
**Root cause:** vaultOrderHash is stored per-vault, not per-listing, so propose() overwrites the hash of an already-active listing; _verifySale then checks the wrong order and cash() reverts forever.
**Steps:**
1. User A calls `propose()`, setting proposedListing and `vaultOrderHash[_vault]=X`.
2. After PROPOSAL_PERIOD, `list()` promotes the listing to activeListings.
3. Another user calls `propose()` again, overwriting `vaultOrderHash[_vault]=Y`.
4. The active listing's Seaport order is filled and validated on-chain.
5. `cash()` calls `_verifySale`, which queries `getOrderStatus(Y)` instead of X, so it never returns true.
6. `cash()` reverts with NotSold() permanently; proceeds stuck in contract.
**How found:** Code reading: noticed vaultOrderHash is a single per-vault slot written in propose() and only read in _verifySale; reasoned that a second propose() overwrites it, and that re-proposing identical params can't restore the hash because block.timestamp differs.
**Exploitation:** Any user can grief by submitting a new proposal after an active listing exists; the sale still settles on Seaport but the contract can no longer verify it, so cash() is bricked and ETH proceeds are locked.
**Insight:** When a settlement/verification function reads a mutable per-entity pointer (hash, id, nonce) that a permissionless entrypoint can overwrite, check whether an in-flight/active state can be invalidated by a later call; per-entity should be per-listing.
