# Incorrect earmark weight update in _sync

Alchemist _sync stores latest earmarkWeight instead of past redemption's weight, causing arithmetic underflow that reverts borrow/poke after redemptions.

- Payout: Contest reward
- Severity: high
- Program: Alchemix
- Credited: ZoA
- Disclosed: 2025-07-15
- Write-up quality: 7/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_alchemix_may2025.pdf#3.1.5
- Library page: https://bugbountylibrary.com/r/cantina%3Aalchemix_may2025%3A3.1.5
- Tags: domain:web3 impact:dos kind:contest platform:cantina sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:dos

**Target:** Alchemist _sync accounting logic (Solidity)
**Root cause:** When a redemption is in the past, _sync computes earmarked using previousRedemption.earmarkWeight but stores account.lastAccruedEarmarkWeight = _earmarkWeight (latest), so the next _sync subtracts a larger weight from a smaller one and underflows.
**Steps:**
1. Deposit collateral and mint alUSD debt via `alchemist.mint(tokenId, 1e4e6)`
2. Create redemption of 1,000 alUSD via `transmuterLogic.createRedemption(1e3e6)`
3. Roll forward ~5,256,000 blocks and `claimRedemption(1)`
4. Roll 1 block, call `alchemist.poke(tokenId)` — debt drops to 9,000, earmarked 0
5. Create another 1,000 alUSD redemption, roll ~5,256,000 blocks, `poke(tokenId)`
6. Create third redemption, roll ~5,256,000 blocks, `poke(tokenId)` — reverts with arithmetic underflow
**How found:** Code review of _sync: noticed earmarked computed from previousRedemption.earmarkWeight in the past-redemption branch but lastAccruedEarmarkWeight assigned the latest _earmarkWeight, then reasoned a second _sync would subtract a larger weight from a smaller one.
**Exploitation:** Not an attacker-profit exploit; any user calling poke/borrow after a past-block redemption triggers the underflow revert, breaking core borrow/repay functionality during the 3-month redemption window.
**Insight:** In weight-accrual accounting, check that every state variable updated in a branch uses the same historical snapshot as the value it was derived from; mismatched snapshot vs latest assignment creates underflow on the next call.
