NFT with saturation
= 100 and lightness
= 100 cant be generated, contradict the documentation
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]
Unable to generate NFT with saturation
= 100 and lightness
= 100.
Manual review
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(), "%)");
}
}
https://docs.codehawks.com/hawks-auditors/how-to-determine-a-finding-validity
https://docs.codehawks.com/hawks-auditors/how-to-determine-a-finding-validity
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.