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

Fix the issue of handling decimals. #2886

Merged
merged 7 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// Copyright 2020-2024 Trust Computing GmbH.
// This file is part of Litentry.
//
// Litentry is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Litentry is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Litentry. If not, see <https://www.gnu.org/licenses/>.

// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.8.0;
import "../openzeppelin/Strings.sol";
import "../openzeppelin/math/Math.sol";
library StringShift {
/**
* @dev Converts a uint256 input to a string and shifts the decimal point to the left by the specified number of places.
* @param value The uint256 parameter to be processed.
* @param decimal The number of decimal places to shift.
* @return The processed string.
*/
function toShiftedString(
uint256 value,
uint256 decimal
) internal pure returns (string memory) {
// Convert uint256 to string

if (value == 0) {
return "0";
} else {
string memory str = Strings.toString(value);

// Calculate the position to insert the decimal point
uint256 len = bytes(str).length;
uint256 digit = Math.log10(decimal);

if (len <= digit) {
// If the length is less than or equal to the number of digits, pad with leading zeros and add '0.'
string memory leadingZeros = new string(digit - len);
for (uint256 i = 0; i < digit - len; i++) {
leadingZeros = string(abi.encodePacked("0", leadingZeros));
}
str = string(abi.encodePacked("0.", leadingZeros, str));
} else {
// Otherwise, insert the decimal point at the correct position
str = string(
abi.encodePacked(
substring(str, 0, len - digit),
".",
substring(str, len - digit, len)
)
);
}

// Remove trailing zeros after the decimal point
str = removeTrailingZeros(str);

return str;
}
}

/**
* @dev Extracts a substring from a given string.
* @param str The original string.
* @param start The starting position of the original string.
* @param end The ending position of the original string.
* @return The extracted substring.
*/
function substring(
string memory str,
uint256 start,
uint256 end
) internal pure returns (string memory) {
bytes memory strBytes = bytes(str);
bytes memory result = new bytes(end - start);
for (uint256 i = start; i < end; i++) {
result[i - start] = strBytes[i];
}
return string(result);
}

/**
* @dev Removes trailing zeros after the decimal point in a string.
* @param str The input string.
* @return The processed string with trailing zeros removed.
*/
function removeTrailingZeros(
string memory str
) internal pure returns (string memory) {
bytes memory strBytes = bytes(str);
uint256 len = strBytes.length;

// Traverse from the end to find the position of the first non-zero character
uint256 newLen = len;
while (newLen > 0 && strBytes[newLen - 1] == "0") {
newLen--;
}

// If the last character is a decimal point, remove it as well
if (newLen > 0 && strBytes[newLen - 1] == ".") {
newLen--;
}

// Create a new byte array and copy the content
bytes memory trimmedBytes = new bytes(newLen);
for (uint256 i = 0; i < newLen; i++) {
trimmedBytes[i] = strBytes[i];
}

return string(trimmedBytes);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import "../libraries/AssertionLogic.sol";
import "../libraries/Identities.sol";
import "../DynamicAssertion.sol";
import "./Constants.sol";
import "../libraries/StringShift.sol";

abstract contract TokenHoldingAmount is DynamicAssertion {
mapping(string => string) internal tokenNames;
Expand Down Expand Up @@ -157,15 +158,18 @@ abstract contract TokenHoldingAmount is DynamicAssertion {
1,
variable,
AssertionLogic.Op.GreaterEq,
Strings.toString(min / Constants.decimals_factor)
StringShift.toShiftedString(min, Constants.decimals_factor)
);
if (max > 0) {
AssertionLogic.andOp(
cc,
2,
variable,
AssertionLogic.Op.LessThan,
Strings.toString(uint256(max) / Constants.decimals_factor)
StringShift.toShiftedString(
uint256(max),
Constants.decimals_factor
)
);
}

Expand Down