Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NFTDescriptor: escape quotes #104

Merged
merged 5 commits into from
Apr 22, 2021
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
62 changes: 18 additions & 44 deletions contracts/libraries/NFTDescriptor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -113,43 +113,35 @@ library NFTDescriptor {
}

function formatTokenSymbol(string memory symbol) internal pure returns (string memory) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems this method should be more like escapeQuotes(string) returns (string) and could use some fuzz testing (it may not work right multibyte characters, not sure)

bytes memory symbolBytes = bytes(symbol);
uint8 quotesCount = 0;
for(uint8 i = 0; i < symbolBytes.length; i++) {
if (symbolBytes[i] == '"') {
quotesCount++;
bytes memory symbolBytes = bytes(symbol);
uint8 quotesCount = 0;
for (uint8 i = 0; i < symbolBytes.length; i++) {
if (symbolBytes[i] == '"') {
quotesCount++;
}
}
}
if (quotesCount > 0) {
bytes memory formattedBytes = new bytes(symbolBytes.length + (quotesCount));
uint index;
for(uint8 i = 0; i < symbolBytes.length; i++) {
if (symbolBytes[i] == '"') {
formattedBytes[index++] = "\\";
}
formattedBytes[index++] = symbolBytes[i];
if (quotesCount > 0) {
bytes memory formattedBytes = new bytes(symbolBytes.length + (quotesCount));
uint256 index;
for (uint8 i = 0; i < symbolBytes.length; i++) {
if (symbolBytes[i] == '"') {
formattedBytes[index++] = '\\';
}
formattedBytes[index++] = symbolBytes[i];
}
return string(formattedBytes);
}
return string(formattedBytes);
}
return symbol;
return symbol;
}

struct DecimalStringParams {
// significant figures of decimal
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prettier's gone rogue...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

think i ran into this once before, look for an issue in the solidity prettier plugin repo

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, I'm so sorry about this. I just opened a PR that fixes this: prettier-solidity/prettier-plugin-solidity#480 I'll try to have it merged and released today.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, Franco, that was so quick!! thank you! cc @fvictorio

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be fixed in prettier-plugin-solidity@1.0.0-beta.10. Let us know if it's not!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yess, that did the trick 💯 happy to be able to throw you weird edgecases as you guys get closer to a stable release 😂

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

Expand All @@ -163,11 +155,9 @@ library NFTDescriptor {
buffer[1] = '.';
}

// add leading/trailing 0's
for (uint256 zerosCursor = params.zerosStartIndex; zerosCursor < params.zerosEndIndex.add(1); zerosCursor++) {
buffer[zerosCursor] = bytes1(uint8(48));
}
// add sigfigs
while (params.sigfigs > 0) {
if (params.decimalIndex > 0 && params.sigfigIndex == params.decimalIndex) {
buffer[params.sigfigIndex--] = '.';
Expand Down Expand Up @@ -208,7 +198,6 @@ library NFTDescriptor {
if (roundUp) {
value = value + 1;
}
// 99999 -> 100000 gives an extra sigfig
if (value == 100000) {
value /= 10;
extraDigit = true;
Expand Down Expand Up @@ -243,8 +232,6 @@ library NFTDescriptor {
return uint256(x >= 0 ? x : -x);
}

// @notice Returns string that includes first 5 significant figures of a decimal number
// @param sqrtRatioX96 a sqrt price
function fixedPointToDecimalString(
uint160 sqrtRatioX96,
uint8 baseTokenDecimals,
Expand All @@ -255,44 +242,36 @@ library NFTDescriptor {

bool priceBelow1 = adjustedSqrtRatioX96 < 2**96;
if (priceBelow1) {
// 10 ** 43 is precision needed to retreive 5 sigfigs of smallest possible price + 1 for rounding
value = FullMath.mulDiv(value, 10**44, 1 << 128);
} else {
// leave precision for 4 decimal places + 1 place for rounding
value = FullMath.mulDiv(value, 10**5, 1 << 128);
}

// get digit count
uint256 temp = value;
uint8 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
// don't count extra digit kept for rounding
digits = digits - 1;

// address rounding
(uint256 sigfigs, bool extraDigit) = sigfigsRounded(value, digits);
if (extraDigit) {
digits++;
}

DecimalStringParams memory params;
if (priceBelow1) {
// 7 bytes ( "0." and 5 sigfigs) + leading 0's bytes
params.bufferLength = uint8(uint8(7).add(uint8(43).sub(digits)));
params.zerosStartIndex = 2;
params.zerosEndIndex = uint8(uint256(43).sub(digits).add(1));
params.sigfigIndex = uint8(params.bufferLength.sub(1));
} else if (digits >= 9) {
// no decimal in price string
params.bufferLength = uint8(digits.sub(4));
params.zerosStartIndex = 5;
params.zerosEndIndex = uint8(params.bufferLength.sub(1));
params.sigfigIndex = 4;
} else {
// 5 sigfigs surround decimal
params.bufferLength = 6;
params.sigfigIndex = 5;
params.decimalIndex = uint8(digits.sub(5).add(1));
Expand All @@ -304,8 +283,6 @@ library NFTDescriptor {
return generateDecimalString(params);
}

// @notice Returns string as decimal percentage of fee amount.
// @param fee fee amount
function feeToPercentString(uint24 fee) internal pure returns (string memory) {
if (fee == 0) {
return '0%';
Expand All @@ -315,7 +292,6 @@ library NFTDescriptor {
uint8 numSigfigs;
while (temp != 0) {
if (numSigfigs > 0) {
// count all digits preceding least significant figure
numSigfigs++;
} else if (temp % 10 != 0) {
numSigfigs++;
Expand All @@ -327,15 +303,13 @@ library NFTDescriptor {
DecimalStringParams memory params;
uint256 nZeros;
if (digits >= 5) {
// if decimal > 1 (5th digit is the ones place)
uint256 decimalPlace = digits.sub(numSigfigs) >= 4 ? 0 : 1;
nZeros = digits.sub(5) < (numSigfigs.sub(1)) ? 0 : digits.sub(5).sub(numSigfigs.sub(1));
params.zerosStartIndex = numSigfigs;
params.zerosEndIndex = uint8(params.zerosStartIndex.add(nZeros).sub(1));
params.sigfigIndex = uint8(params.zerosStartIndex.sub(1).add(decimalPlace));
params.bufferLength = uint8(nZeros.add(numSigfigs.add(1)).add(decimalPlace));
} else {
// else if decimal < 1
nZeros = uint256(5).sub(digits);
params.zerosStartIndex = 2;
params.zerosEndIndex = uint8(nZeros.add(params.zerosStartIndex).sub(1));
Expand Down Expand Up @@ -363,7 +337,7 @@ library NFTDescriptor {
string memory baseTokenColor = tokenToColorHex(uint256(baseToken));
svg = string(
abi.encodePacked(
'<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">',
'<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">', //www.w3.org/2000/svg">',
'<circle cx="12" cy="12" r="12" fill=',
quoteTokenColor,
' stroke="white"/>',
Expand Down