Last active
February 28, 2023 06:24
-
-
Save wilsoncusack/d2e680e0f961e36393d1bf0b6faafba7 to your computer and use it in GitHub Desktop.
Solidity Decimal String Helpers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function decimalString(uint256 number, uint8 decimals, bool isPercent) private pure returns(string memory){ | |
uint8 percentBufferOffset = isPercent ? 1 : 0; | |
uint256 tenPowDecimals = 10 ** decimals; | |
uint256 temp = number; | |
uint8 digits; | |
uint8 numSigfigs; | |
while (temp != 0) { | |
if (numSigfigs > 0) { | |
// count all digits preceding least significant figure | |
numSigfigs++; | |
} else if (temp % 10 != 0) { | |
numSigfigs++; | |
} | |
digits++; | |
temp /= 10; | |
} | |
DecimalStringParams memory params; | |
params.isPercent = isPercent; | |
if((digits - numSigfigs) >= decimals) { | |
// no decimals, ensure we preserve all trailing zeros | |
params.sigfigs = number / tenPowDecimals; | |
params.sigfigIndex = digits - decimals; | |
params.bufferLength = params.sigfigIndex + percentBufferOffset; | |
} else { | |
// chop all trailing zeros for numbers with decimals | |
params.sigfigs = number / (10 ** (digits - numSigfigs)); | |
if(tenPowDecimals > number){ | |
// number is less tahn one | |
// in this case, there may be leading zeros after the decimal place | |
// that need to be added | |
// offset leading zeros by two to account for leading '0.' | |
params.zerosStartIndex = 2; | |
params.zerosEndIndex = decimals - digits + 2; | |
params.sigfigIndex = numSigfigs + params.zerosEndIndex; | |
params.bufferLength = params.sigfigIndex + percentBufferOffset; | |
params.isLessThanOne = true; | |
} else { | |
// In this case, there are digits before and | |
// after the decimal place | |
params.sigfigIndex = numSigfigs + 1; | |
params.decimalIndex = digits - decimals + 1; | |
} | |
} | |
params.bufferLength = params.sigfigIndex + percentBufferOffset; | |
return generateDecimalString(params); | |
} | |
// With modifications, the below taken | |
// from https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/libraries/NFTDescriptor.sol#L189-L231 | |
struct DecimalStringParams { | |
// significant figures of decimal | |
uint256 sigfigs; | |
// length of decimal string | |
uint8 bufferLength; | |
// ending index for significant figures (funtion works backwards when copying sigfigs) | |
uint8 sigfigIndex; | |
// index of decimal place (0 if no decimal) | |
uint8 decimalIndex; | |
// start index for trailing/leading 0's for very small/large numbers | |
uint8 zerosStartIndex; | |
// end index for trailing/leading 0's for very small/large numbers | |
uint8 zerosEndIndex; | |
// true if decimal number is less than one | |
bool isLessThanOne; | |
// true if string should include "%" | |
bool isPercent; | |
} | |
function generateDecimalString(DecimalStringParams memory params) private pure returns (string memory) { | |
bytes memory buffer = new bytes(params.bufferLength); | |
if (params.isPercent) { | |
buffer[buffer.length - 1] = '%'; | |
} | |
if (params.isLessThanOne) { | |
buffer[0] = '0'; | |
buffer[1] = '.'; | |
} | |
// add leading/trailing 0's | |
for (uint256 zerosCursor = params.zerosStartIndex; zerosCursor < params.zerosEndIndex; zerosCursor++) { | |
buffer[zerosCursor] = bytes1(uint8(48)); | |
} | |
// add sigfigs | |
while (params.sigfigs > 0) { | |
if (params.decimalIndex > 0 && params.sigfigIndex == params.decimalIndex) { | |
buffer[--params.sigfigIndex] = '.'; | |
} | |
buffer[--params.sigfigIndex] = bytes1(uint8(uint256(48) + (params.sigfigs % 10))); | |
params.sigfigs /= 10; | |
} | |
return string(buffer); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment