Sablier

Sablier
DeFiFoundry
53,440 USDC
View results
Submission Details
Severity: low
Invalid

Unable to generate NFT with `saturation` = 100 and `lightness` = 100

Summary

NFT with saturation = 100 and lightness = 100 cant be generated, contradict the documentation

Vulnerability Details

Function generateAccentColor() is used to generate color

function generateAccentColor(address sablier, uint256 streamId) internal view returns (string memory) {
    // The chain ID is part of the hash so that the generated color is different across chains.
    uint256 chainId = block.chainid;

    // Hash the parameters to generate a pseudo-random bit field, which will be used as entropy.
    // | Hue     | Saturation | Lightness | -> Roles
    // | [31:16] | [15:8]     | [7:0]     | -> Bit positions
    uint32 bitField = uint32(uint256(keccak256(abi.encodePacked(chainId, sablier, streamId))));

    unchecked {
        // The hue is a degree on a color wheel, so its range is [0, 360).
        // Shifting 16 bits to the right means using the bits at positions [31:16].
        uint256 hue = (bitField >> 16) % 360;

        // The saturation is a percentage where 0% is grayscale and 100%, but here the range is bounded to [20,100]
        // to make the colors more lively.
        // Shifting 8 bits to the right and applying an 8-bit mask means using the bits at positions [15:8].
        uint256 saturation = ((bitField >> 8) & 0xFF) % 80 + 20;    //  <---

        // The lightness is typically a percentage between 0% (black) and 100% (white), but here the range
        // is bounded to [30,100] to avoid dark colors.
        // Applying an 8-bit mask means using the bits at positions [7:0].
        uint256 lightness = (bitField & 0xFF) % 70 + 30;    //  <---

        // Finally, concatenate the HSL values to form an SVG color string.
        return string.concat("hsl(", hue.toString(), ",", saturation.toString(), "%,", lightness.toString(), "%)");
    }
}

From dev's comment, range of saturation is [20, 100], but the formula ((bitField >> 8) & 0xFF) % 80 + 20 only can give value in [20, 99]. Similar with lightness, when the formula (bitField & 0xFF) % 70 + 30 only can give value in range [30, 99]

Impact

Unable to generate NFT with saturation = 100 and lightness = 100.

Tools Used

Manual review

Recommendations

Update function to:

function generateAccentColor(address sablier, uint256 streamId) internal view returns (string memory) {
    // The chain ID is part of the hash so that the generated color is different across chains.
    uint256 chainId = block.chainid;

    // Hash the parameters to generate a pseudo-random bit field, which will be used as entropy.
    // | Hue     | Saturation | Lightness | -> Roles
    // | [31:16] | [15:8]     | [7:0]     | -> Bit positions
    uint32 bitField = uint32(uint256(keccak256(abi.encodePacked(chainId, sablier, streamId))));

    unchecked {
        // The hue is a degree on a color wheel, so its range is [0, 360).
        // Shifting 16 bits to the right means using the bits at positions [31:16].
        uint256 hue = (bitField >> 16) % 360;

        // The saturation is a percentage where 0% is grayscale and 100%, but here the range is bounded to [20,100]
        // to make the colors more lively.
        // Shifting 8 bits to the right and applying an 8-bit mask means using the bits at positions [15:8].
     -  uint256 saturation = ((bitField >> 8) & 0xFF) % 80 + 20;
     +  uint256 saturation = ((bitField >> 8) & 0xFF) % 81 + 20;

        // The lightness is typically a percentage between 0% (black) and 100% (white), but here the range
        // is bounded to [30,100] to avoid dark colors.
        // Applying an 8-bit mask means using the bits at positions [7:0].
     -  uint256 lightness = (bitField & 0xFF) % 70 + 30;
     +  uint256 lightness = (bitField & 0xFF) % 71 + 30;
        // Finally, concatenate the HSL values to form an SVG color string.
        return string.concat("hsl(", hue.toString(), ",", saturation.toString(), "%,", lightness.toString(), "%)");
    }
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Info/Gas/Invalid as per Docs

https://docs.codehawks.com/hawks-auditors/how-to-determine-a-finding-validity

0xnevi Judge
about 1 year ago
inallhonesty Lead Judge
about 1 year ago
inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Info/Gas/Invalid as per Docs

https://docs.codehawks.com/hawks-auditors/how-to-determine-a-finding-validity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.