Skip to content

Instantly share code, notes, and snippets.

@pcaversaccio
Last active June 15, 2023 09:10
Show Gist options
  • Save pcaversaccio/32f0af715b4d0adabf5fc2a53a33689d to your computer and use it in GitHub Desktop.
Save pcaversaccio/32f0af715b4d0adabf5fc2a53a33689d to your computer and use it in GitHub Desktop.
A Python script that converts a function name into a name convention based on a checksum approach.
from re import sub
from eth_utils import keccak
from caseconverter import camelcase, flatcase, macrocase, pascalcase, snakecase
"""
Biased Assumption: Every single word of an interface function, event or custom error definition,
or anything else contained in an interface definition and used as an identifier, is capitalised
and concatenated with an underscore before running `to_checksum_name`.
Examples: `TRANSFER_FROM`, `BALANCE_OF`, `$I_HATE_PHP`.
Common naming conventions:
- camelCase
- kebab-case (not supported due to general language compatibility reasons)
- COBOL-CASE (not supported due to general language compatibility reasons)
- flatcase
- MACRO_CASE
- PascalCase
- snake_case
"""
MAX_UINT256 = 2**256 - 1 # Maximum value that a `keccak256` hash can reach.
INTERVAL = MAX_UINT256 / 5 # We support 5 different naming conventions.
def to_checksum_name(function_name):
assert isinstance(function_name, str), "Input argument must be a string."
assert function_name.isupper(), "String must be uppercase."
# Remove all non-alphanumeric characters excluding underscore.
# The expression `[\W]` is equal to `[^a-zA-Z0-9_]`, i.e. it
# matches any character which is not a word character. For further
# details, see: https://docs.python.org/3.11/library/re.html#regular-expression-syntax.
non_alphanumeric_name = sub(r"[\W]", "", function_name)
# `keccak256` hash and convert into an integer type. Note that in Python 3,
# the `int` type has no maximum limit. You can handle values as
# large as the available memory allows. For further details, see:
# https://docs.python.org/3/whatsnew/3.0.html#integers.
hashed = int(keccak(text=non_alphanumeric_name).hex(), 16)
# Check the hash value and return the converted name.
if hashed > (MAX_UINT256 - INTERVAL):
return camelcase(non_alphanumeric_name)
elif hashed > (MAX_UINT256 - 2 * INTERVAL):
return flatcase(non_alphanumeric_name)
elif hashed > (MAX_UINT256 - 3 * INTERVAL):
return macrocase(non_alphanumeric_name)
elif hashed > (MAX_UINT256 - 4 * INTERVAL):
return pascalcase(non_alphanumeric_name)
else:
return snakecase(non_alphanumeric_name)
# An example for each naming convention.
if __name__ == "__main__":
result = to_checksum_name("SAFE_BATCH_TRANSFER_FROM")
print(result) # safe_batch_transfer_from
result = to_checksum_name("BALANCE_OF")
print(result) # balanceof
result = to_checksum_name("TRANSFER_FROM")
print(result) # transferFrom
result = to_checksum_name("GET_APPROVED")
print(result) # GetApproved
result = to_checksum_name("$I_HA$TE_PHP_R'{'}0!_!")
print(result) # I_HATE_PHP_R0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment