Skip to content

Conversation

@evilpeach
Copy link
Collaborator

@evilpeach evilpeach commented Oct 2, 2025

Summary

  • Add contract creation decoder that detects deployments via to === null
  • Improve error handling across all Ethereum decoders
  • Add comprehensive test coverage for contract deployments

Changes

Contract Creation Decoder

  • ✅ Detects contract creation using to === null (universal EVM standard)
  • ✅ Works with any bytecode prefix (0x6080604052, 0x60a06040, etc.)
  • ✅ Extracts: from, contractAddress, bytecodeLength
  • ✅ Validates contract address exists (throws error if deployment failed)

Error Handling Improvements

  • approveDecoder: Now throws error when Approval event log is missing
  • transferFromDecoder: Already throws error when Transfer event is missing
  • contractCreationDecoder: Throws error when contract address is missing
  • ✅ Updated interface: contractAddress is always string (never null)
  • ✅ Consistent pattern: all decoders throw errors on failure instead of silent failures

Test Coverage

  • ✅ Regular contract deployment test (0x6080604052 prefix)
  • ✅ Immutable contract deployment test (0x60a06040 prefix)
  • ✅ Validates bytecode length and extracted fields
  • ✅ All 66 tests pass

Technical Details

Why to === null instead of bytecode prefix?

  • Bytecode prefixes are compiler-specific (Solidity, Vyper, different versions)
  • to === null is the protocol-level indicator for contract creation
  • More reliable and future-proof approach

Error Handling Philosophy

  • Failed transactions should throw errors and fall back to not_supported
  • No silent failures with incorrect data
  • Clear error messages for debugging

Test plan

  • All 66 existing tests pass
  • Contract creation decoder works for both regular and immutable deployments
  • Error handling tested (decoders throw when events/addresses missing)
  • Linter passes

Summary by CodeRabbit

  • New Features
    • Ethereum transactions that deploy contracts are now decoded, showing action “contract_creation” with contract address, sender, and bytecode length.
  • Bug Fixes
    • Improved validation for token approval decoding: missing Approval events now surface a clear error instead of failing silently.
  • Tests
    • Added test coverage for decoding standard and immutable contract deployments, validating action, addresses, and bytecode length.

- Add contract creation decoder that detects deployments via `to === null`
- Works universally with any bytecode prefix (0x6080604052, 0x60a06040, etc.)
- Add error handling: throw when Approval/Transfer events or contract address missing
- Update interfaces to reflect contract address is always string (never null)
- Add test cases for both regular and immutable contract deployments
- Reorganize decoders: move approve/transferFrom to generic/ folder
- Reorganize constants into dedicated files (balance-changes, module-addresses)
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 2, 2025

Walkthrough

Introduces a new Ethereum contract creation decoder, exposes it via module exports, and integrates it into the decoder sequence. Updates interfaces to include a Contract Creation decoded type. Tightens error handling in the ERC approval decoder. Adds fixtures and tests for contract deployment decoding.

Changes

Cohort / File(s) Summary
Contract creation decoder integration
src/decoders/ethereum/contract/contract-creation.ts, src/decoders/ethereum/contract/index.ts, src/decoders/ethereum/index.ts, src/decoder.ts
Adds a new Ethereum contractCreationDecoder, re-exports it through contract and ethereum indexes, and includes it in the ethereumDecoders list.
Interfaces update
src/interfaces/ethereum.ts
Adds DecodedContractCreationCall interface and includes it in DecodedEthereumCall union.
Approval decoder guard
src/decoders/ethereum/generic/approve.ts
Replaces null-safe check with explicit error if Approval log is missing; computes isErc721 after guard.
Tests and fixtures
src/tests/ethereum/contract-deployment/single-contract-deployment.fixture.ts, src/tests/ethereum/contract-deployment/single-contract-deployment.test.ts
Adds deployment payload fixtures and tests verifying contract creation decoding (action, addresses, bytecode length).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant App as Caller
  participant Decoder as EthereumDecoder
  participant CDec as contractCreationDecoder
  participant OtherDec as Other Ethereum Decoders
  participant RPC as Ethereum RPC

  App->>Decoder: decode(payload)
  Note over Decoder: Iterate decoders in sequence
  Decoder->>CDec: check(payload)
  alt tx.to is null/empty AND tx.input non-empty
    CDec-->>Decoder: true
    Decoder->>RPC: fetch tx + receipt (if not provided)
    Decoder->>CDec: decode(payload)
    CDec->>CDec: validate receipt.contractAddress
    CDec-->>Decoder: { action: "contract_creation", data: { from, contractAddress, bytecodeLength } }
  else Not a creation
    CDec-->>Decoder: false
    Decoder->>OtherDec: check/decode(payload)
    OtherDec-->>Decoder: result (if matched)
  end
  Decoder-->>App: DecodedEthereumCall
  Note right of CDec: New path for contract creation
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

I nibbled bytes and traced a chain,
A newborn contract took the lane.
Addresses gleam, the logs align,
Bytecode length? A tasty sign.
With sharper checks, no ghosts slip through—
Hop, deploy, decode anew! 🐇✨


Comment @coderabbitai help to get the list of available commands and usage tips.

@evilpeach evilpeach requested a review from Poafs1 October 2, 2025 09:42
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/decoders/ethereum/contract/contract-creation.ts (1)

37-44: Clarify bytecodeLength semantics

  • tx.input.length returns the hex-string length (chars including "0x"), not byte count
  • To report bytes, use (tx.input.length - 2) / 2
  • Or rename the field to bytecodeHexLength to reflect its current behavior
    Tests only assert > 0, so they won’t catch this discrepancy.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Lite

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between f6046be and 0322776.

📒 Files selected for processing (8)
  • src/decoder.ts (1 hunks)
  • src/decoders/ethereum/contract/contract-creation.ts (1 hunks)
  • src/decoders/ethereum/contract/index.ts (1 hunks)
  • src/decoders/ethereum/generic/approve.ts (1 hunks)
  • src/decoders/ethereum/index.ts (1 hunks)
  • src/interfaces/ethereum.ts (2 hunks)
  • src/tests/ethereum/contract-deployment/single-contract-deployment.fixture.ts (1 hunks)
  • src/tests/ethereum/contract-deployment/single-contract-deployment.test.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/decoders/ethereum/contract/contract-creation.ts (3)
src/interfaces/decoder.ts (1)
  • EthereumDecoder (19-25)
src/schema/ethereum/transaction.ts (1)
  • EthereumRpcPayload (85-85)
src/interfaces/ethereum.ts (1)
  • DecodedContractCreationCall (17-24)
src/tests/ethereum/contract-deployment/single-contract-deployment.test.ts (2)
src/tests/_shared/helpers/initialize.ts (1)
  • initialize (3-9)
src/tests/ethereum/contract-deployment/single-contract-deployment.fixture.ts (2)
  • contractDeploymentPayload (1-62)
  • immutableContractDeploymentPayload (64-107)
🔇 Additional comments (11)
src/decoders/ethereum/generic/approve.ts (1)

65-71: LGTM! Explicit error handling improves decoder reliability.

The explicit check for approvalLog presence ensures that the ERC-20 vs ERC-721 type determination cannot proceed with invalid data. The error message clearly identifies the contract and transaction, aiding debugging. This change aligns with the PR's goal of consistent error handling across Ethereum decoders.

src/decoders/ethereum/index.ts (1)

1-1: LGTM! Module re-export is consistent.

The new re-export for the contract module follows the existing pattern and correctly exposes the contract creation decoder alongside other Ethereum decoders.

src/decoders/ethereum/contract/index.ts (1)

1-1: LGTM! Standard re-export pattern.

The re-export correctly exposes the contract creation decoder module.

src/decoder.ts (1)

80-80: LGTM! Decoder placement is optimal.

Adding the contract creation decoder at the start of the ethereumDecoders list is appropriate because:

  • The check (tx.to === null) is unambiguous and mutually exclusive with other decoders
  • Checking it first avoids unnecessary checks for subsequent decoders during contract deployments
  • Contract deployments are a distinct operation that should be identified early
src/tests/ethereum/contract-deployment/single-contract-deployment.test.ts (2)

13-30: LGTM! Test coverage for standard contract deployment is appropriate.

The test correctly validates:

  • The decoded action is "contract_creation"
  • The contractAddress and from fields match expected values from the fixture
  • The bytecodeLength exceeds 1000, which is a reasonable sanity check for real deployments

The conditional type narrowing at line 25 is defensive and ensures type safety when accessing data.bytecodeLength.


32-49: LGTM! Test coverage for immutable contract deployment is thorough.

The test validates that the decoder correctly handles immutable contracts (with 0x60a06040 prefix) in addition to standard contracts. The parallel structure with the first test case ensures consistency, and the comment provides helpful context about the bytecode prefix difference.

src/interfaces/ethereum.ts (2)

17-24: LGTM! Interface definition is well-structured.

The DecodedContractCreationCall interface correctly defines the contract creation decoded type with appropriate fields:

  • action: "contract_creation" enables discriminated union pattern
  • bytecodeLength captures the size of the deployment bytecode
  • contractAddress and from are strings (checksummed via viem's getAddress)

The interface follows the established pattern of other decoded call types.


7-7: LGTM! Union type extension is correct.

Adding DecodedContractCreationCall to the DecodedEthereumCall union correctly extends the type system to recognize contract_creation as a valid decoded Ethereum call variant.

src/decoders/ethereum/contract/contract-creation.ts (2)

8-18: LGTM! Contract creation detection is correct.

The check method correctly identifies contract creation transactions using the protocol-level indicator (tx.to === null). The additional checks ensure:

  • Both null and empty string cases for to are handled (defensive)
  • Contract bytecode (tx.input) is present and non-empty

This approach is more robust than prefix-based detection and works with any bytecode pattern.


1-47: Overall implementation is solid.

The contract creation decoder correctly implements the EthereumDecoder interface with:

  • Protocol-level detection (tx.to === null)
  • Proper validation and error handling
  • Address normalization using viem's getAddress
  • Clear error messages with transaction hash for debugging

The implementation aligns with the PR's goal of consistent error handling across Ethereum decoders.

src/tests/ethereum/contract-deployment/single-contract-deployment.fixture.ts (1)

1-107: LGTM! Test fixtures are comprehensive and realistic.

The two fixture payloads (contractDeploymentPayload and immutableContractDeploymentPayload) provide complete test coverage for contract deployment scenarios:

  • Both include all required fields for Ethereum RPC payloads
  • tx.to is correctly set to null (contract creation indicator)
  • tx.input contains realistic bytecode and constructor arguments
  • txReceipt.contractAddress is populated with the deployed contract address
  • txReceipt.status is true (successful deployment)

The fixtures cover both standard (0x6080604052 prefix) and immutable (0x60a06040 prefix) contract deployments, ensuring the decoder handles various bytecode patterns.

@evilpeach evilpeach merged commit f235517 into main Oct 2, 2025
2 checks passed
@evilpeach evilpeach deleted the feat/contract-deployment branch October 2, 2025 10:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants