Solidity 将 HEX 数字转换为 HEX 字符串

Solidity convert HEX number to HEX string

我需要在 solidity 智能合约中存储这种 0xff00000x00ff08(十六进制颜色表示)的值,并能够在合约中将其转换为具有相同文本的字符串字符 "ff0000"。我打算在 RSK 上部署这个智能合约。

我的想法是将这些值存储在 bytes3 或简单的 uint 变量中,并使用一个纯函数将 bytes3uint 转换为相应的字符串。我找到了一个可以完成这项工作并致力于 solidity 0.4.9

的功能
pragma solidity 0.4.9;

contract UintToString {
    function uint2hexstr(uint i) public constant returns (string) {
        if (i == 0) return "0";
        uint j = i;
        uint length;
        while (j != 0) {
            length++;
            j = j >> 4;
        }
        uint mask = 15;
        bytes memory bstr = new bytes(length);
        uint k = length - 1;
        while (i != 0){
            uint curr = (i & mask);
            bstr[k--] = curr > 9 ? byte(55 + curr ) : byte(48 + curr); // 55 = 65 - 10
            i = i >> 4;
        }
        return string(bstr);
    }
}

但我需要更新的编译器版本(至少 0.8.0)。以上功能不适用于较新的版本。

如何将 bytesuint 转换为十六进制字符串 (1->'1',f->'f') 在 Solidity >=0.8 中有效。 0 ?

以下编译,并使用solc 0.8.7测试 与您的原始版本相同,并进行了以下修改:

  • constant --> pure
  • returns (string) --> returns (string memory)
  • byte(...) --> bytes1(uint8(...))

以上更改克服了原始函数中的所有编译时差异。 ...但是仍然存在 运行 时间错误导致此函数恢复:

调试时,行 bstr[k--] = curr > 9 ? 在其所在循环的最后一次迭代中触发了还原。这是因为 while 循环的设置使得 k0 在最后一次迭代中。

虽然识别很棘手,但修复很简单:将减量运算符从后缀更改为前缀 - bstr[--k] = curr > 9 ?

Aside:

Q: Why did this not revert when compiled in solc 0.4.9, but revert when the same code was compiled in solc 0.8.7?

A: solc 0.8.0 introduced a breaking change where uint overflow and underflow checks were inserted by the compiler. Prior to this one would have needed to use SafeMath or similar to accomplish the same. See the "Silent Changes of the Semantics" section of the solc 0.8 release notes

pragma solidity >=0.8;

contract TypeConversion {
    function uint2hexstr(uint i) public pure returns (string memory) {
        if (i == 0) return "0";
        uint j = i;
        uint length;
        while (j != 0) {
            length++;
            j = j >> 4;
        }
        uint mask = 15;
        bytes memory bstr = new bytes(length);
        uint k = length;
        while (i != 0) {
            uint curr = (i & mask);
            bstr[--k] = curr > 9 ?
                bytes1(uint8(55 + curr)) :
                bytes1(uint8(48 + curr)); // 55 = 65 - 10
            i = i >> 4;
        }
        return string(bstr);
    }
}