7

I need to store a value of this kind 0xff0000 or 0x00ff08 (hex colour representation) in solidity smart contract and be able to convert it inside a contract to a string with the same text characters "ff0000". I intend to deploy this smart contract on RSK.

My idea was to store those values in a bytes3 or simply uint variable and to have a pure function converting bytes3 or uint to corresponding string. I found a function that does the job and working on 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);
    }
}

But I need a more recent compiler version (at least 0.8.0). The above function is not working on newer versions.

What's the way to convert bytes or uint to a hex string (1->'1',f->'f') what works in Solidity >=0.8.0 ?

bguiz
  • 27,371
  • 47
  • 154
  • 243
Aleks Shenshin
  • 2,117
  • 5
  • 18

1 Answers1

4

The following compiles, and was tested using solc 0.8.7 It is the same as your original version, with the following modifications:

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

The above changes overcame all of the compile-time differences in your original function. ... however there was still a run-time error that was causing this function to revert:

While debugging, the line bstr[k--] = curr > 9 ? triggered the revert in the last iteration of the loop it was in. This was because the while loop was set up such that k was 0 in its final iteration.

While the identification was tricky, the fix was simple: Change the decrement operator from postfixed to prefixed - 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);
    }
}

bguiz
  • 27,371
  • 47
  • 154
  • 243