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

Bytes32String unnecessary null termination #4965

Open
afa7789 opened this issue Mar 24, 2025 · 2 comments
Open

Bytes32String unnecessary null termination #4965

afa7789 opened this issue Mar 24, 2025 · 2 comments
Assignees
Labels
investigate Under investigation and may be a bug. v6 Issues regarding v6

Comments

@afa7789
Copy link

afa7789 commented Mar 24, 2025

Ethers Version

6.13.5

Search Terms

Bytes32String

Describe the Problem

Bytes32String Unnecessary Null Termination

bytes32 string must be less than 32 bytes

From the documentation:

Since we need only a single byte for the null termination, we can store strings up to 31 bytes long in a word.

Why limit strings to 31 bytes?

There is no need to force a null termination on a fixed-length data type if the string fits nicely into it. It can be safely assumed that the non-existent byte 33 is zero. The string already terminates at 32 bytes by definition — there’s no need for a redundant termination byte.

The output of formatBytes32String (v5) and encodeBytes32String (v6) always contains a null character at the last byte. This self-imposed limitation is wasteful and makes no practical sense.

Bytes32String should be able to handle 32 bytes long strings, otherwise it would be more truthful to call it Bytes31String.

If the string is exactly 32 bytes long, you can just use toUtf8Bytes, but what if the string length is variable up to 32 bytes?

Notably, the equivalent function in viem does not have this limitation and accepts 32 bytes long strings as input without issues.

Proposal: Raise the limit from 31 to 32 bytes

Additionally, decodeBytes32String behaves oddly — it searches backwards for the null terminator (assuming zero padding). This is not standard behavior in other languages, where it’s expected that the string would be cut at the first null character, not the first byte of the padding.


This would resolve:

Code Snippet

Contract ABI

Errors

Environment

No response

Environment (Other)

No response

@afa7789 afa7789 added investigate Under investigation and may be a bug. v6 Issues regarding v6 labels Mar 24, 2025
@afa7789
Copy link
Author

afa7789 commented Mar 27, 2025

ping @zemse @zemse @ricmoo

@ricmoo
Copy link
Member

ricmoo commented Apr 1, 2025

The term Byte32String came from the idea that it is a string that fits in Bytes32, not that the length of the string is 32 bytes. At the time it was created, there were a handful of ERC-20 contracts that used a bytes32 (and no meaningful standard) to store their symbol and name; of which no contract used a string anywhere close to that length.

Are there still contracts using this method to store strings?

One concern with this is that Solidity will currently allow a string of up to 31 bytes to fit within a single storage slot (32 bytes), so the null-termination makes it possible for any valid Bytea32String to fit in either a Solidity bytes32 or a Solidity string, consuming only 32 bytes.

Allowing a 32 byte string to be used means that a string could be selected that would require 64 bytes if stored as a Solidity string.

Not a huge issue, but I am curious as to how many contracts are still using this technique for storing strings (and I guess why? :)).

For more information on how Solidity uses a prefix byte (limiting single-slot strings to 31 bytes), here is some info on solidity string storage layout.

I'm not against making the change, I just want to make sure the motivation and consequences are discussed. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
investigate Under investigation and may be a bug. v6 Issues regarding v6
Projects
None yet
Development

No branches or pull requests

2 participants