low

Zero address check for tokens

Reward

Total

1.98 USDC

0.08 USDC
0.08 USDC
0.08 USDC
0.08 USDC
0.08 USDC
0.08 USDC
0.08 USDC
0.08 USDC
0.08 USDC
0.08 USDC
0.08 USDC
0.08 USDC
0.08 USDC
0.08 USDC
0.08 USDC
0.08 USDC
0.08 USDC
0.08 USDC
Selected
0.11 USDC
0.08 USDC
0.08 USDC
0.08 USDC
0.08 USDC
0.08 USDC
0.08 USDC
Selected Submission

Zero address check for tokens

Severity

Low Risk

Relevant GitHub Links

https://github.com/Cyfrin/2023-07-foundry-defi-stablecoin/blob/main/src/DSCEngine.sol#L112-L123

Summary

In the current implementation the token and price feed addresses aren’t checked for zero address upon initialization, there is a modifier which catch scenarios when price feed with zero address will be passed, but not for token addresses.

Vulnerability Details

When deploy the DSCEngine.sol, if pass token with address(0) and working price feed address, the deployment will be successful, but the user experience is going to fall when using the protocol, due to EVM Revert.

// Deploying the protocol localy with token address(0)

return NetworkConfig({
        wethUsdPriceFeed: address(ethUsdPriceFeed),
        wbtcUsdPriceFeed: address(btcUsdPriceFeed),
        weth: address(0),
        wbtc: address(wbtcMock),
        deployerKey: DEFAULT_ANVIL_KEY
    });
}

Impact

It will make freshly deployed DSCEngine unusable and the protocol deployer will have to redeploy everything.

Tools Used

Manual, Foundry

Recommendations

Add a check in the constructor

constructor(address[] memory tokenAddresses, address[] memory priceFeedAddresses, address dscAddress) {
    // USD Price Feeds
    if (tokenAddresses.length != priceFeedAddresses.length) {
        revert DSCEngine__TokenAddressesAndPriceFeedAddressesMustBeSameLength();
    }
    // For example ETH / USD, BTC / USD, MKR / USD, etc
    for (uint256 i = 0; i < tokenAddresses.length; i++) {
    +   if (tokenAddresses[i] == address(0) || priceFeedAddresses[i] == address(0)) {
    +       revert DSCEngine__TokenAddressZero();
    +   }
        s_priceFeeds[tokenAddresses[i]] = priceFeedAddresses[i];
        s_collateralTokens.push(tokenAddresses[i]);
    }
    i_dsc = DecentralizedStableCoin(dscAddress);
}
function getTokenAmountFromUsd(address token, uint256 usdAmountInWei) public view returns (uint256) {
    // price of ETH (token)
    // $/ETH ETH ??
    // $2000 / ETH. $1000 = 0.5 ETH
+   if (token == address(0)) {
+       revert DSCEngine__NotAllowedToken();
+   }
    AggregatorV3Interface priceFeed = AggregatorV3Interface(s_priceFeeds[token]);
    (, int256 price,,,) = priceFeed.staleCheckLatestRoundData();

    // ($10e3 * 1e18) / ($2000e8 * 1e10)
    return (usdAmountInWei * PRECISION) / (uint256(price) * ADDITIONAL_FEED_PRECISION);
}
function getUsdValue(address token, uint256 amount) public view returns (uint256) {
+   if (token == address(0)) {
+       revert DSCEngine__NotAllowedToken();
+   }

    AggregatorV3Interface priceFeed = AggregatorV3Interface(s_priceFeeds[token]);
    (, int256 price,,,) = priceFeed.staleCheckLatestRoundData();
    // 1 ETH = $1000
    // The returned value from CL will be 1000 * 1e8
    return ((uint256(price) * ADDITIONAL_FEED_PRECISION) * amount) / PRECISION;
}