# Unsafe downcasting in issue(...) can be exploited to cause permanent DoS

Unsafe uint192 downcast in Reserve RToken issue() lets attacker pass amtRToken multiple of 2^192, yielding zero baskets and pushing allVestAt to infinity, bricking issuance.

- Payout: Contest reward
- Severity: medium
- Program: Reserve
- Credited: Soosh
- Disclosed: 2023-04-27
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-01-reserve-findings/issues/320
- Library page: https://bugbountylibrary.com/r/c4%3A2023-01-reserve%3AM-10
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic vuln:dos

**Target:** RToken.issue(uint256) issuance/vesting logic
**Root cause:** mulDiv256 result is unsafely downcast to uint192; values that are multiples of 2^192 truncate to 0 baskets, and whenFinished(amtRToken) uses the raw huge amtRToken to set allVestAt astronomically far in the future.
**Steps:**
1. Set prime basket and refresh basket.
2. Attacker with zero collateral calls `rToken.issue(2**192)` (or any multiple of 2^192, or value where basketsNeeded*amtRToken/totalSupply truncates to 0).
3. amtBaskets downcasts to 0, quote returns empty erc20s/deposits, no collateral pulled.
4. whenFinished(amtRToken) sets allVestAt to ~6.27e53 block number.
5. Any later user calls `issue(10e18)` and `vest(...)` reverts with 'issuance not ready' even after advanceTime('123456789123456789').
**How found:** Warden noticed user-supplied amtRToken flows into an unsafe uint192 downcast in issue(); reasoned that a multiple of 2^192 truncates to 0 baskets, then traced whenFinished(amtRToken) to see allVestAt becomes unbounded.
**Exploitation:** Attacker needs no capital or basket tokens; single call to issue() with amtRToken = 2^192 (or computed multiple when totalSupply>0) truncates baskets to zero, deposits nothing, and permanently sets allVestAt so no issuance can ever vest. Redemption remains functional.
**Insight:** When a user-supplied amount is downcast after arithmetic, check whether the pre-cast value (not the truncated one) is reused elsewhere—here the raw amtRToken feeds a time/vesting calculation, turning a truncation into permanent state corruption.
