Skip to content

seismic-web3: contract wrappers cannot resolve overloaded ABI functions #295

Description

@Kewe63

Summary

The Python contract wrappers resolve ABI functions by name only. When an ABI contains overloads, _find_function() always returns the first same-name entry, regardless of the supplied arguments. This can make valid overloads unusable and can also select the wrong selector, smart-routing decision, or output schema.

Affected commit and files

Commit: d99e46cdc2d7ec8c049452ba72127f0540582f53

Expected behavior

Given a valid ABI containing lookup(uint256) and lookup(address), calling contract.tread.lookup(address_value) should select lookup(address), encode with the address ABI encoder, and use the lookup(address) selector. This is also how the pinned web3.py dependency resolves the same ABI and arguments.

Actual behavior

The first ABI entry is always selected. If lookup(uint256) appears first, the valid address call fails before RPC dispatch:

eth_abi.exceptions.EncodingTypeError: Value ... cannot be encoded by UnsignedIntegerEncoder

Reversing the ABI order merely changes which overload is unusable.

Minimal local regression

def test_tread_resolves_overloaded_function_from_arguments() -> None:
    abi = [
        {
            "type": "function",
            "name": "lookup",
            "inputs": [{"name": "value", "type": "uint256"}],
            "outputs": [{"name": "", "type": "bool"}],
            "stateMutability": "view",
        },
        {
            "type": "function",
            "name": "lookup",
            "inputs": [{"name": "account", "type": "address"}],
            "outputs": [{"name": "", "type": "bool"}],
            "stateMutability": "view",
        },
    ]
    w3 = MagicMock()
    w3.eth.call.return_value = encode(["bool"], [True])

    result = PublicContract(w3, ADDRESS, abi).tread.lookup(ARGUMENT_ADDRESS)

    assert result is True
    request = w3.eth.call.call_args.args[0]
    assert bytes(request["data"][:4]) == keccak(b"lookup(address)")[:4]

Test command and observed output

uv run pytest tests/test_contract_audit_regressions.py::test_tread_resolves_overloaded_function_from_arguments -vv

Observed: 1 failed; EncodingTypeError from UnsignedIntegerEncoder. The mock provider was never reached.

Control: web3.py 7.14.1 encoded the same ABI/arguments with selector 0xd4b6b5da, equal to keccak("lookup(address)")[:4].

Root cause

_find_function(abi, function_name) stops at the first matching name. It has no argument-count/encodability/signature disambiguation, and all encoding/routing/decoding helpers use that same name-only lookup.

User impact

Applications cannot reliably call overloaded functions through any Python contract namespace. ABI order determines behavior, and overloads with different shieldedness or outputs can additionally route or decode incorrectly.

Duplicate-check evidence

I checked all 17 issues, 277 PRs, 42 discussion comments, 33 review comments, current open-PR file lists, and the affected file history. I found no report or patch for Python overload resolution. PR #36 introduced the shared name-only lookup but did not discuss overloads.

Suggested fix direction

Resolve one ABI entry from both function name and supplied arguments, and reuse that exact resolved entry for shielded detection, selector construction, argument encoding, and output decoding. A signature-qualified escape hatch would handle ambiguous encodable overloads. Add transparent, shielded-routing, and distinct-output overload regressions.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions