Sablier

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

NFTDescriptor - generateAccentColor doesn't generate the color properly

Summary

The function generateAccentColor doesn't match the intended ranges for the color properly:

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(), "%)");
}
}

According to the docs:

  • For saturation:

The saturation is a percentage where 0% is grayscale and 100%, but here the range is bounded to [20,100]

The maximum saturation value achievable by this calculation is 99, not 100. This is due to how the modulo operation and subsequent addition are structured:
((bitField >> 8) & 0xFF) % 80 yields a maximum of 79 (when the byte is 255).
Adding 20 to 79 results in 99.

  • For lightness

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.

Same as for saturation, it will reach 30 to 99.

Tools Used

Manual Review

Recommendations

add + 1 for both lightness and saturation. i.e:

uint256 saturation = ((bitField >> 8) & 0xFF) % 81 + 20; // Now ranges from 20 to 100
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.