Skip to content

test(python/evm): add unit tests for multicall module#141

Open
0xAxiom wants to merge 1 commit intocoinbase:mainfrom
0xAxiom:test/python-evm-multicall-unit-tests
Open

test(python/evm): add unit tests for multicall module#141
0xAxiom wants to merge 1 commit intocoinbase:mainfrom
0xAxiom:test/python-evm-multicall-unit-tests

Conversation

@0xAxiom
Copy link
Copy Markdown

@0xAxiom 0xAxiom commented May 3, 2026

What

Add 32 unit tests for python/x402/x402/mechanisms/evm/multicall.py — the largest EVM mechanism source file in the Python SDK without a dedicated unit test module.

Why

multicall.py is exercised indirectly through eip3009_utils paths but has no module-level test file. This PR fills that gap with focused tests that pin the public API and the key normalization edge cases.

Coverage

MULTICALL3_ADDRESS / MULTICALL3_TRY_AGGREGATE_ABI (3 tests)

  • Canonical Multicall3 address
  • ABI describes a tryAggregate function
  • Inputs match (bool, tuple[](address,bytes))

encode_contract_call (5 tests)

  • Selector + ABI-encoded args for balanceOf(address)
  • Selector-only output for no-arg function
  • Tuple input canonicalization (submit((address,uint256)))
  • ValueError when function name not in ABI
  • Skips non-function ABI entries (events, etc.)

multicall typed path (5 tests)

  • Decodes single uint256 output
  • Decodes single string output
  • Returns a list for multi-output function
  • Returns None for function with no outputs
  • ABI decode failure marks result unsuccessful with error populated

multicall raw call_data path (3 tests)

  • Skips decoding and signals success=True with result=None
  • Raw bytes propagate verbatim into aggregate calls
  • (False, b"") maps to RuntimeError("multicall: call reverted")

Validation guards (4 tests)

  • Empty calls list short-circuits without calling the signer
  • Typed entries missing ABI raise ValueError
  • Typed entries missing function_name raise ValueError
  • MULTICALL3_ADDRESS/tryAggregate/require_success=False propagation

Result-shape normalization (_normalize_results, 6 tests)

  • Dict entries with hex-string returnData
  • Objects with success / returnData attributes
  • Plain (bool, bytes) tuple entries
  • Rejects non-sequence response
  • Rejects entry of unexpected shape
  • Rejects non-bytes returnData

Mixed ordering & failures (2 tests)

  • Mixed typed + raw calls preserve input order
  • Revert on typed call returns success=False without attempting to decode

Length mismatch (2 tests)

  • Too few results raises ValueError
  • Too many results raises ValueError

MulticallResult dataclass (2 tests)

  • Default values for failed-with-no-error case
  • Error propagation

Test Run

$ uv run pytest tests/unit/mechanisms/evm/test_multicall.py -q
................................                                         [100%]
32 passed, 1 warning in 1.58s

$ uv run pytest tests/unit/ -q
843 passed, 1 warning in 3.48s

Checklist

  • No production code changes — pure unit tests
  • uvx ruff format clean
  • uvx ruff check clean
  • All 843 Python unit tests still pass
  • Changelog fragment added (changelog.d/multicall-unit-tests.doc.md)
  • Commit GPG-signed

Add 32 unit tests for python/x402/x402/mechanisms/evm/multicall.py — the
largest EVM mechanism source file without a dedicated unit test module.

Coverage:
- MULTICALL3_ADDRESS canonical deployment and MULTICALL3_TRY_AGGREGATE_ABI shape
- encode_contract_call: address argument, no-arg function, tuple input
  canonicalization, missing function ValueError, non-function ABI entries
- multicall typed-call path: single uint, string, multi-output list, no-output
  None, ABI decode failure marked unsuccessful with error
- multicall raw call_data path: skips decoding, propagates raw bytes to
  aggregate calls, revert maps to RuntimeError
- typed entries without ABI / function name raise ValueError
- mixed typed and raw arrays preserve input ordering
- _normalize_results accepts dict, attribute object, and tuple shapes; rejects
  non-sequence response, malformed entries, and non-bytes returnData
- length mismatch (too few or too many) raises ValueError
- MulticallResult dataclass defaults and error propagation
@cb-heimdall
Copy link
Copy Markdown

🟡 Heimdall Review Status

Requirement Status More Info
Reviews 🟡 0/1
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 1
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 0
Global minimum 0
Max 1
1
1 if commit is unverified 0
Sum 1

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

Development

Successfully merging this pull request may close these issues.

2 participants