# TimeswapV2LiquidityToken should not use totalSupply()+1 as tokenId

TimeswapV2LiquidityToken derives new tokenId from totalSupply()+1, so after a burn a new position reuses an existing tokenId, colliding distinct LP positions.

- Payout: Contest reward
- Severity: high
- Program: Timeswap
- Credited: mookimgo
- Disclosed: 2023-03-10
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-01-timeswap-findings/issues/219
- Library page: https://bugbountylibrary.com/r/c4%3A2023-01-timeswap%3AH-02
- Tags: domain:web3 impact:integrity kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** TimeswapV2LiquidityToken / TimeswapV2Token ERC1155 tokenId assignment
**Root cause:** New position tokenId is set to totalSupply()+1, but totalSupply (ERC1155Enumerable _allTokens.length) can decrease when a tokenId's supply is fully burned, so the counter is not monotonic and can be reused.
**Steps:**
1. Mint liquidity for token0/token1 -> tokenId 1 (totalSupply=1).
2. Mint liquidity for token2/token3 -> tokenId 2 (totalSupply=2).
3. Burn all liquidity of tokenId 1; with ERC1155Enumerable patched, totalSupply drops to 1.
4. Mint liquidity for token4/token5 -> id = totalSupply()+1 = 2, colliding with existing tokenId 2.
5. Observe `_timeswapV2LiquidityTokenPositionIds(key3) == 2 == id2` in forge test.
**How found:** Code reading of the mint path: comment says 'if the position does not exist, create it' but id = totalSupply()+1; traced totalSupply to ERC1155Enumerable._allTokens.length and noticed it decreases on full burn, making the id non-monotonic. Also spotted the latent ERC1155Enumerable bug where _removeTokenEnumeration checks _idTotalSupply[id]==0 before subtracting amount, so removal never fires.
**Exploitation:** Requires ERC1155Enumerable's _removeTokenEnumeration to be fixed (currently the removal never triggers, masking the bug). Once fixed, an attacker mints, burns a position to shrink totalSupply, then mints a new position that reuses an existing tokenId, causing distinct LP positions to share a tokenId and enabling balance/accounting manipulation across positions.
**Insight:** Never derive an identifier from a supply/length counter that can shrink; trace whether the counter is monotonic. Also, a bug in a dependency can mask a bug in your code — audit the invariant assuming the dependency is fixed.
