-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add contract creation decoder and improve error handling #83
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
Conversation
- 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)
WalkthroughIntroduces 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
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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
Comment |
There was a problem hiding this 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.lengthreturns the hex-string length (chars including"0x"), not byte count- To report bytes, use
(tx.input.length - 2) / 2- Or rename the field to
bytecodeHexLengthto 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
📒 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
approvalLogpresence 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
ethereumDecoderslist 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
contractAddressandfromfields match expected values from the fixture- The
bytecodeLengthexceeds 1000, which is a reasonable sanity check for real deploymentsThe 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
0x60a06040prefix) 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
DecodedContractCreationCallinterface correctly defines the contract creation decoded type with appropriate fields:
action: "contract_creation"enables discriminated union patternbytecodeLengthcaptures the size of the deployment bytecodecontractAddressandfromare strings (checksummed via viem'sgetAddress)The interface follows the established pattern of other decoded call types.
7-7: LGTM! Union type extension is correct.Adding
DecodedContractCreationCallto theDecodedEthereumCallunion correctly extends the type system to recognizecontract_creationas a valid decoded Ethereum call variant.src/decoders/ethereum/contract/contract-creation.ts (2)
8-18: LGTM! Contract creation detection is correct.The
checkmethod correctly identifies contract creation transactions using the protocol-level indicator (tx.to === null). The additional checks ensure:
- Both
nulland empty string cases fortoare handled (defensive)- Contract bytecode (
tx.input) is present and non-emptyThis 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
EthereumDecoderinterface 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 (
contractDeploymentPayloadandimmutableContractDeploymentPayload) provide complete test coverage for contract deployment scenarios:
- Both include all required fields for Ethereum RPC payloads
tx.tois correctly set tonull(contract creation indicator)tx.inputcontains realistic bytecode and constructor argumentstxReceipt.contractAddressis populated with the deployed contract addresstxReceipt.statusistrue(successful deployment)The fixtures cover both standard (
0x6080604052prefix) and immutable (0x60a06040prefix) contract deployments, ensuring the decoder handles various bytecode patterns.
Summary
to === nullChanges
Contract Creation Decoder
to === null(universal EVM standard)from,contractAddress,bytecodeLengthError Handling Improvements
approveDecoder: Now throws error when Approval event log is missingtransferFromDecoder: Already throws error when Transfer event is missingcontractCreationDecoder: Throws error when contract address is missingcontractAddressis alwaysstring(nevernull)Test Coverage
Technical Details
Why
to === nullinstead of bytecode prefix?to === nullis the protocol-level indicator for contract creationError Handling Philosophy
not_supportedTest plan
Summary by CodeRabbit