# Fixed Term Bond tokens can be minted with non-rounded expiry

BondFixedTermTeller.deploy() skipped the daily expiry rounding used in _handlePayout, letting anyone pre-deploy a tokenId with an arbitrary expiry and lock that day's bond at an unexpected timestamp.

- Payout: Contest reward
- Severity: medium
- Program: Bond
- Credited: obront
- Disclosed: 2022-11-05
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2022-11-bond-judging/issues/32
- Library page: https://bugbountylibrary.com/r/sherlock%3A2022-11-bond%3AM-2
- Tags: domain:web3 impact:integrity kind:contest platform:sherlock sev:medium tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** BondFixedTermTeller.sol deploy() / _deploy() tokenId expiry logic
**Root cause:** deploy() computes tokenId from expiry_/1 days but stores the raw expiry_ in TokenMetadata, whereas _handlePayout() rounds expiry down to the nearest day before both computing tokenId and deploying.
**Steps:**
1. Call `deploy(underlying, expiry_)` directly with an expiry_ not aligned to a day boundary (e.g. a future timestamp mid-day).
2. tokenId = keccak256(underlying, expiry_/1 days) is created and marked active with the unrounded expiry_ stored.
3. Subsequent _handlePayout for that day finds tokenMetadata[tokenId].active == true and reuses the attacker-chosen expiry, so the day's bond expires at the attacker's timestamp.
**How found:** Code reading: noticed _handlePayout rounds expiry to days before computing tokenId, then compared the external deploy() path and saw it passes expiry_ unrounded into both getTokenId and _deploy, creating a tokenId/expiry mismatch.
**Exploitation:** Attacker pre-deploys a tokenId for a future day with an off-cycle expiry; because _deploy only runs when the tokenId is inactive, the protocol cannot correct the expiry later, locking that day's bond token to the attacker-chosen timestamp.
**Insight:** When a tokenId is derived from a rounded value but metadata stores the raw value, check every entry point that can create the id — a permissionless deploy() bypasses the rounding invariant and permanently pins the id's metadata.
