如何在Solidity中将bytes3转换为HEX字符串



我之前问过如何将int转换为十六进制字符串。现在我想将十六进制值0x00ff08存储在bytes3变量中,并能够将其转换为Solidity智能合约中的string。随后,我打算将其部署在RSK上,Solidity编译器版本至少为0.8.0。

我试过这个string(abi.encodePacked(bytes3(0x00ff08)))但是它抛出一个运行时错误

解码输出失败:null:在偏移量1处无效的码点;错误码点前缀(argument="bytes", value={"0":0,"1":255,"2":8}, code=INVALID_ARGUMENT, version=strings/5.4.0)

不同的参数string(abi.encodePacked(bytes3(0x443322)))不会导致错误,但是返回一个非常奇怪的D3"结果。这里有什么问题呢?如何将bytes3转换为具有相同字符的string?

你观察到的行为的原因

abi.encodePacked(myBytes3)产生3个字节,因为每2个十六进制字符产生1个字节。所以当你在string(..)中包装它时,你会得到一个每1个字节有1个字符的字符串,在这种情况下,结果是一个有3个字符的字符串。对于某些输入,这会导致可以呈现为人类可读字符串的字符串。在其他情况下,它会产生一个不能存在的字符串,因此会出现解析错误。

<<p>

解决方案/strong>在这种情况下不能使用abi.encodePacked(..),因为"包装"是相反的你想要完成的-将bytes3呈现为十六进制string-一个是人类可读的,ASCII编码-你需要做类似的事情吗我对你上一个问题的回答,你使用位移位和位掩码的组合来提取每半个字节的一个字符。

将单个uint8转换为ASCII字符以十六进制表示的实用函数:

function uint8tohexchar(uint8 i) public pure returns (uint8) {
return (i > 9) ?
(i + 87) : // ascii a-f
(i + 48); // ascii 0-9
}

uint24转换为6位十六进制string的函数。

请注意,由于这次您不是在寻找"通用目的"。解决方案,而不是特定于bytes3的解决方案,不需要任何循环,而是一组连续的语句就可以了。可能还可以节省一些汽油(有待确认!)

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);
}

最后,您可能需要一个显式接受bytes3作为参数的函数。

注意,这纯粹是为了方便,因为它真正做的只是类型强制转换。bytes3uint24可以简单地理解为"24位"。被以不同的方式看待/解释。

function bytes3tohexstr(bytes3 i) public pure returns (string memory) {
uint24 n = uint24(i);
return uint24tohexstr(n);
}

最新更新