# Because of rounding issues, users may not be able to withdraw airdrop tokens if their claim has been adjust()'ed upwards

Tokensoft AdvancedDistributor rounds vote-token minting per adjust() call, so an upward adjust leaves users unable to burn enough votes to withdraw their airdrop claim.

- Payout: Contest reward
- Severity: medium
- Program: Tokensoft
- Credited: jkoppel
- Disclosed: 2023-06-30
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-06-tokensoft-judging/issues/56
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-06-tokensoft%3AM-2
- Tags: domain:web3 impact:dos kind:contest platform:sherlock sev:medium tech:evm tech:solidity vuln:accounting-error vuln:dos vuln:precision-loss

**Target:** AdvancedDistributor claim contract (ERC20Votes voting power)
**Root cause:** tokensToVotes truncates (tokenAmount*voteFactor)/fractionDenominator on each mint; minting in separate initializeDistributionRecord and adjust() steps loses fractional votes, but burn on claim recomputes from the full total, exceeding the user's balance.
**Steps:**
1. Deploy distributor with voteFactor=15000, fractionDenominator=10000, user claim = amount/3 (e.g. 1000e18/3).
2. User initializes distribution record; minted votes = floor((amount/3)*15000/10000).
3. Owner calls `adjust(user, int256(amount/3))`; another truncated vote mint occurs.
4. User fully vests and calls `claim(user)`; `_executeClaim` burns tokensToVotes(total) which exceeds minted balance -> revert `ERC20: burn amount exceeds balance`.
5. Confirm adjusting by `1+amount/3` instead avoids the revert.
**How found:** Code reading of tokensToVotes rounding combined with the observation that minting happens in two separate calls (initialize and adjust) while burning uses the aggregate total; verified with a Foundry test showing burn-exceeds-balance revert.
**Exploitation:** No attacker; admin's innocuous adjust() with non-multiple voteFactor permanently reverts user claims until admin sweeps tokens or performs an unintuitive compensating adjust sequence.
**Insight:** When a share/vote balance is minted incrementally but burned based on an aggregate recomputation, per-call truncation accumulates a deficit; check any adjust/increase path against the burn formula for non-divisible factors.
