-
Notifications
You must be signed in to change notification settings - Fork 11.8k
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
Strings: add toUint, toInt and hexToUint #5166
base: master
Are you sure you want to change the base?
Conversation
🦋 Changeset detectedLatest commit: 26cec97 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
contracts/utils/Strings.sol
Outdated
* @dev Parse an decimal string and returns the value as a `int256`. | ||
* | ||
* This function will revert if: | ||
* - the string contains any character (outside the prefix) that is not in [0-9]. | ||
* - the result does not fit in a int256. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* @dev Parse an decimal string and returns the value as a `int256`. | |
* | |
* This function will revert if: | |
* - the string contains any character (outside the prefix) that is not in [0-9]. | |
* - the result does not fit in a int256. | |
* @dev Parse a string in decimal (i.e. base 10) and returns the value as a `int256`. | |
* | |
* This function will revert if: | |
* - the string contains any character (outside the prefix) that is not in [0-9]. | |
* - the result does not fit in a `int256`. |
contracts/utils/Strings.sol
Outdated
* @dev Parse an decimal string and returns the value as a `uint256`. | ||
* | ||
* This function will revert if: | ||
* - the string contains any character that is not in [0-9]. | ||
* - the result does not fit in a uint256. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* @dev Parse an decimal string and returns the value as a `uint256`. | |
* | |
* This function will revert if: | |
* - the string contains any character that is not in [0-9]. | |
* - the result does not fit in a uint256. | |
* @dev Parse a string in decimal (i.e. base 10) and returns the value as a `uint256`. | |
* | |
* This function will revert if: | |
* - the string contains any character that is not in [0-9]. | |
* - the result does not fit in a `uint256`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When looking online, It looks like "decimal string" is the correct way. Maybe "string in decimal format" would be ok, but "string in decimal" doesn't look commonly used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be fine with decimal string
too. I see that's the current state so it's fine imo
Co-authored-by: cairo <[email protected]>
Co-authored-by: cairo <[email protected]>
Co-authored-by: cairo <[email protected]>
contracts/utils/Strings.sol
Outdated
function hexToUint(string memory input) internal pure returns (uint256) { | ||
bytes memory buffer = bytes(input); | ||
|
||
// skip 0x prefix if present. Length check doesn't appear to be critical |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
second sentence feels out of place
// skip 0x prefix if present. Length check doesn't appear to be critical | |
// skip 0x prefix if present |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just for the record, this is what the comment was about:
The string length may be less than 2. String could be empty, of just "1"
. In some cases, doing a input[1]
or even a input[0]
would revert (out of bound acces). Doing bytes2(input)
does not revert if the string is to short.
So we check the length to verify that it ok to read the prefix ? It turn out no.
- If the string is empty, then regardless of the result of that lookup (that could read dirty bytes), the loop will not run (because length == 0), and the result will be 0 -> that is ok
- If the string has length 1 then we have two options
- the check identifies the prefix
- that means the string is
"0"
, and there is a dirtyx
after. - In that case we have an offset of 2, and the length is 1, so the for loop does not run and the function returns 0 -> that is ok
- that means the string is
- the check does not find the prefix
- the only "digit" is read by the loop, and the result should be just fine
- the check identifies the prefix
- If the string has length >= 2, then the prefix lookup is in the bounds
That is the long explanation (I'm happy its visible in the PR 😃) to something that is not really trivial, and can be missed, but missing it is not a risk.
We may get questions about it though ...
Co-authored-by: cairo <[email protected]>
TODO: add functions to specify start and end of string to parse
9c2c8b1
to
a7a6e9e
Compare
} | ||
|
||
// TODO: documentation. | ||
function unsafeReadBytesOffset(bytes memory buffer, uint256 offset) internal pure returns (bytes32 value) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bytes operation so it shouldn't be in the Strings
library.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where should that go ? A Bytes
library ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that the same function exists in RSA.sol
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this function was present in other places but always private.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. private, and marked as memory safe, because the private calls are all enforcing the safety.
But we are starting to use it in many places ... so having 3 private implementation of the same functions (with different names?) doesn't feel right.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. private, and marked as memory safe, because the private calls are all enforcing the safety.
Right... That was the issue. That using memory-unsafe functions disables some optimizations globally, so they were important to avoid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So do we want to have:
- multiple private (and memory safe) implementations
- one internal, none memory safe implementation
- one internal, memory safe (checks memory bound) implementation
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see we added more variations of the base functions and understand that we might want to reduce it. However, I like that the interface is pretty versatile (especially by providing pointers).
I'm not too worried about the length of this particular library since it's not procedurally generated
contracts/utils/Strings.sol
Outdated
* @dev Parse an decimal string and returns the value as a `uint256`. | ||
* | ||
* This function will revert if: | ||
* - the string contains any character that is not in [0-9]. | ||
* - the result does not fit in a uint256. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be fine with decimal string
too. I see that's the current state so it's fine imo
Co-authored-by: Ernesto García <[email protected]>
As discussed. Usefull for parsing addresses from CAIP10 identifier (strings)
PR Checklist
npx changeset add
)