LibString toHexString functions
Vectorized opened this issue · 0 comments
Vectorized commented
Sometimes, users may want to convert a uint256 into a hexadecimal representation.
The following code snippet may be helpful.
The behavior is based on OpenZeppelin's https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Strings.sol
Except that it will use the minimal length needed to encode the hex string instead of reverting if the length is too short.
function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) {
assembly {
let start := mload(0x40)
// We need 1 32-byte word for the length, 1 32-byte word for the prefix,
// and 2 32-byte words for the digits, totaling to 128 bytes.
// But if a custom length is provided, we will ensure there is minimally enough space,
// with the free memory pointer rounded up to a multiple of 32.
str := add(start, add(128, shl(6, shr(5, length))))
// Cache the end to calculate the length later.
let end := str
// Allocate the memory.
mstore(0x40, str)
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
// Costs a bit more vs early return for the zero case,
// but otherwise cheaper in terms of deployment and overall runtime costs.
for {
// Initialize and perform the first pass without check.
let temp := value
str := sub(str, 1)
mstore8(str, byte(and(temp, 15), "0123456789abcdef"))
temp := shr(4, temp)
str := sub(str, 1)
mstore8(str, byte(and(temp, 15), "0123456789abcdef"))
temp := shr(4, temp)
length := sub(length, gt(length, 0))
} or(length, temp) {
length := sub(length, gt(length, 0))
} {
str := sub(str, 1)
mstore8(str, byte(and(temp, 15), "0123456789abcdef"))
temp := shr(4, temp)
str := sub(str, 1)
mstore8(str, byte(and(temp, 15), "0123456789abcdef"))
temp := shr(4, temp)
}
// Compute the string's length.
let strLength := add(sub(end, str), 2)
// Move the pointer and write the "0x" prefix, which is 0x3078.
str := sub(str, 32)
mstore(str, 0x3078)
// Move the pointer and write the length.
str := sub(str, 2)
mstore(str, strLength)
}
}
function toHexString(uint256 value) internal pure returns (string memory str) {
str = toHexString(value, 0);
}
function toHexString(address value) internal pure returns (string memory str) {
str = toHexString(uint256(uint160(value)), 20);
}