# Multiple issues with decimal scaling will cause incorrect accounting of hTokens and underlying tokens

Reversed normalize/denormalize decimal helpers plus missing scaling calls in Maia Ulysses bridge cause hToken/underlying accounting mismatch, letting depositors of >18-decimal tokens mint excess hTokens and withdraw more than deposited.

- Payout: Contest reward
- Severity: high
- Program: Maia DAO Ecosystem
- Credited: peakbolt
- Disclosed: 2023-09-18
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-05-maia-findings/issues/758
- Library page: https://bugbountylibrary.com/r/c4%3A2023-05-maia%3AH-05
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:precision-loss

**Target:** Ulysses Omnichain BranchBridgeAgent / BranchPort / ArbitrumBranchPort deposit and bridge functions
**Root cause:** _normalizeDecimals and _denormalizeDecimals are implemented reversed (normalize multiplies by 10**decimals/1e18 instead of 1e18/10**decimals), ArbitrumBranchPort.depositToPort omits denormalization before safeTransferFrom, and BranchBridgeAgent omits normalization when passing deposit amounts to _depositAndCall/_depositAndCallMultiple and storing in getDeposit.
**Steps:**
1. Identify non-18-decimal token support in Ulysses bridging via _normalizeDecimals/_denormalizeDecimals.
2. Read BranchBridgeAgent._normalizeDecimals: `_amount * (10 ** _decimals) / 1 ether` — reversed.
3. Read BranchPort._denormalizeDecimals: `_amount * 1 ether / (10 ** _decimals)` — also reversed.
4. Call ArbitrumBranchBridgeAgent.depositToPort with a >18-decimal token; amount is normalized then passed to ArbitrumBranchPort.depositToPort which transfers without denormalizing.
5. Observe excess hTokens minted via mintToLocalBranch; call withdrawFromPort to extract more underlying than deposited.
6. Also call callOutSignedAndBridge/callOutAndBridge with non-18-decimal token; deposit stored unnormalized in getDeposit, mismatching clearToken on redeemDeposit.
**How found:** Code review of decimal scaling helpers used for non-18-decimal token bridging; noticed the multiply/divide direction was inverted and traced call sites to find missing normalize/denormalize calls in ArbitrumBranchPort and BranchBridgeAgent.
**Exploitation:** Attacker deposits a token with >18 decimals through ArbitrumBranchBridgeAgent.depositToPort; the normalized amount is transferred as-is (no denormalization), so fewer underlying tokens are pulled than hTokens minted. Attacker then withdraws from the port to redeem excess underlying tokens for profit.
**Insight:** When a protocol supports arbitrary-decimal ERC20s, audit every normalize/denormalize helper for inverted multiply/divide direction and verify each call site actually applies the conversion on both the transfer path and the stored accounting state.
