From 54cc6249d45c6192ae90268213c05695484ef78f Mon Sep 17 00:00:00 2001 From: AMATH <116212274+amathxbt@users.noreply.github.com> Date: Sun, 3 May 2026 03:19:39 -0700 Subject: [PATCH] fix: use safe staticcall in ConfidentialETH._cappedDecimals ConfidentialETH._cappedDecimals called IERC20Metadata(token).decimals() directly. If the WETH contract does not implement decimals() or reverts (e.g., non-standard or mis-deployed WETH), the entire ConfidentialETH initialise call reverts with no meaningful error, permanently bricking the proxy since UUPS initializers cannot be retried. ConfidentialERC20._cappedDecimals already uses a safe staticcall with an 18-decimal fallback. Apply the same pattern here for consistency and robustness. --- packages/hardhat/contracts/ConfidentialETH.sol | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/hardhat/contracts/ConfidentialETH.sol b/packages/hardhat/contracts/ConfidentialETH.sol index 6f9a1b1..5d1f1e9 100644 --- a/packages/hardhat/contracts/ConfidentialETH.sol +++ b/packages/hardhat/contracts/ConfidentialETH.sol @@ -32,7 +32,12 @@ contract ConfidentialETH is FHERC20NativeWrapperUpgradeable, OwnableUpgradeable, } function _cappedDecimals(address token) private view returns (uint8) { - uint8 d = IERC20Metadata(token).decimals(); + // Use a low-level staticcall so that non-standard WETH implementations + // that revert or omit decimals() do not brick initialization. + // Falls back to 18 (the ERC-20 default) on failure, matching the + // behaviour of ConfidentialERC20._cappedDecimals. + (bool ok, bytes memory data) = token.staticcall(abi.encodeCall(IERC20Metadata.decimals, ())); + uint8 d = (ok && data.length == 32) ? abi.decode(data, (uint8)) : 18; return d > 6 ? 6 : d; }