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

Is there a way to match calldata/memory encoding conventions? #185

Open
UsmannK opened this issue Jul 29, 2022 · 1 comment
Open

Is there a way to match calldata/memory encoding conventions? #185

UsmannK opened this issue Jul 29, 2022 · 1 comment

Comments

@UsmannK
Copy link

UsmannK commented Jul 29, 2022

In solidity calldata has special conventions for encoding. See: https://docs.soliditylang.org/en/v0.8.14/types.html#arrays

Variables of type bytes and string are special arrays. The bytes type is similar to bytes1[], but it is packed tightly in calldata and memory. string is equal to bytes but does not allow length or index access.

This results in a scheme where some things are packed tightly and others aren't.

Is there a way to use this library to easily match the semantics of abi.encodeWithSignature?

Specifically I am looking for a way to do the following:

>>> import eth_abi
>>> eth_abi.__version__
'3.0.1'
>>> eth_abi.encode(['uint256', 'bytes'], [0xDEADBEEF, b'']).hex()
'00000000000000000000000000000000000000000000000000000000deadbeef000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'

Here the empty bytes are getting encoded as 0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

but I'd like it to be 0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000

essentially, there should be 32 fewer bytes

@icodezjb
Copy link

icodezjb commented Aug 24, 2023

I had the same problem and found this info:
Don't add an empty data slot to ABI-encoded empty strings from storage

And I re-registered the bytes type encoder:

import eth_abi
from eth_abi.encoding import encode_uint_256
from eth_abi.registry import BaseEquals, encoding
from eth_abi.utils.padding import zpad_right


class NewByteStringEncoder(encoding.ByteStringEncoder):
    is_dynamic = True

    @classmethod
    def encode(cls, value):
        cls.validate_value(value)
        value_length = len(value)

        encoded_size = encode_uint_256(value_length)

        if value_length == 0:
            return encoded_size

        ceil32 = value_length if value_length % 32 == 0 else value_length + 32 - (value_length % 32)
        padded_value = zpad_right(value, ceil32)

        return encoded_size + padded_value


eth_abi.abi.registry.unregister_encoder(
    BaseEquals("bytes", with_sub=False),
)

eth_abi.abi.registry.register_encoder(
    BaseEquals("bytes", with_sub=False),
    NewByteStringEncoder
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants