# Logic Error due to different representation of Native ETH (0x0 & 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)

Notional Curve2Token vault init compares tokens against ALT_ETH_ADDRESS but constructor already normalized ETH to address(0), so checkApprove runs on native ETH.

- Payout: Contest reward
- Severity: medium
- Program: Notional
- Credited: xiaoming90
- Disclosed: 2023-02-27
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-02-notional-judging/issues/15
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-02-notional%3AM-4
- Tags: domain:web3 impact:dos kind:contest platform:sherlock sev:medium tech:evm tech:solidity technique:source-review vuln:business-logic

**Target:** Curve2TokenConvexVault.initialize / Curve2TokenPoolMixin constructor
**Root cause:** Constructor converts native ETH to Deployments.ETH_ADDRESS (address(0)) for SECONDARY_TOKEN, but initialize() only skips checkApprove when token equals ALT_ETH_ADDRESS (0xEeee...), so the guard never matches for native ETH.
**Steps:**
1. Read Curve2TokenPoolMixin constructor: primaryToken normalized to ALT_ETH_ADDRESS for pool lookup, then secondaryToken converted back to ETH_ADDRESS (address(0)) at line 50-52.
2. Read Curve2TokenConvexVault.initialize lines 56-61: guards compare PRIMARY_TOKEN/SECONDARY_TOKEN against ALT_ETH_ADDRESS only.
3. Deploy vault with a Curve pool containing native ETH; SECONDARY_TOKEN == address(0).
4. initialize() passes the != ALT_ETH_ADDRESS check and calls IERC20(address(0)).checkApprove(...).
**How found:** Code-reading of the constructor vs initialize: noticed the constructor normalizes ETH to address(0) while initialize assumes ALT_ETH_ADDRESS, making the guard always true for native ETH pools.
**Insight:** When a codebase uses two sentinel addresses for the same asset (address(0) and 0xEeee...), audit every comparison site for which sentinel is actually stored at that point in the lifecycle; constructor-time normalization can silently invalidate later guards.
