如何在Solidity中将bytes3转换为十六进制字符串

3
我之前询问过将uint转换为十六进制字符串。现在我想要将一个16进制值0x00ff08存储到一个bytes3变量中,并能够在Solidity智能合约中将其转换为string。随后,我打算在至少使用0.8.0版本的Solidity编译器上将其部署到RSK。
我尝试了这个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
1个回答

4

观察到的行为原因

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

解决方案

在此情况下,你不能使用abi.encodePacked(..),因为"packing"与你尝试实现的相反 - 渲染一个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 具体情况的解决方案,因此不需要任何循环,而是一系列顺序语句即可。可能还能节省一些 gas(待确认!)。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接