Reason for the behaviour you've observed
abi.encodePacked(myBytes3)
produces 3 bytes because every 2 hexadecimal characters results in 1 bytes. so when you wrap that in string(..)
you do get a string with 1 character per 1 byte, which in this case, results in a string with 3 characters. For some inputs this results in a string that can be rendered as a human readable string. In other cases, it results in a string that cannot be, hence the parse error.
Solution
You cannot use abi.encodePacked(..)
in this case, because "packing" is the opposite of what you're trying to accomplish - to render a bytes3
as a hexadecimal string
- one that is human readable, ASCII encoded - you would need to do something similar to
my answer to your previous question, where you use a combination of bit shifting with bit masking to extract one character per half byte.
Code
Utility function that converts a single uint8
into the ASCII character that would represent it in hexadecimal:
function uint8tohexchar(uint8 i) public pure returns (uint8) {
return (i > 9) ?
(i + 87) : // ascii a-f
(i + 48); // ascii 0-9
}
Function that converts a uint24
to a 6 character hexadecimal string
.
Note that since this time you're not looking for a "general purpose" solution, but rather one that is specific to bytes3
, there is no need for any loops, but rather, a sequential set of statements will do. Probably nets some gas savings too .(to be confirmed!)
function uint24tohexstr(uint24 i) public pure returns (string memory) {
bytes memory o = new bytes(6);
uint24 mask = 0x00000f;
o[5] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[4] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[3] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[2] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[1] = bytes1(uint8tohexchar(uint8(i & mask)));
i = i >> 4;
o[0] = bytes1(uint8tohexchar(uint8(i & mask)));
return string(o);
}
And finally, you probably want a function that explicitly accepts bytes3
as a parameter.
Note that this is purely for convenience, as all it really does is a type cast. The bytes3
and uint24
can be thought of simply as "24 bits" being viewed/ interpreted in different ways.
function bytes3tohexstr(bytes3 i) public pure returns (string memory) {
uint24 n = uint24(i);
return uint24tohexstr(n);
}