Skip to content

Transaction7702.createTransaction() ignores accessList parameter - the field remains null in constructed object #2291

@zouxyan

Description

@zouxyan

Transaction7702.createTransaction() ignores accessList parameter - the field remains null in constructed object

Transaction7702.createTransaction() accepts an accessList parameter but does NOT actually set it to the constructed object. The accessList field (inherited from Transaction2930) remains null, causing incorrect RLP encoding when the transaction is serialized.

Steps To Reproduce

  1. Create a Transaction7702 using Transaction7702.createTransaction() with a non-empty accessList
  2. Call transaction.getAccessList() on the returned object
  3. Observe that it returns null instead of the provided access list

Sample code

import org.web3j.crypto.transaction.type.Transaction7702;
import org.web3j.crypto.AccessListObject;
import java.math.BigInteger;
import java.util.Collections;
import java.util.List;

public class ReproduceIssue {
    public static void main(String[] args) {
        List<AccessListObject> accessList = Collections.singletonList(
            new AccessListObject(
                "0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae",
                Collections.singletonList("0x0000000000000000000000000000000000000000000000000000000000000003")
            )
        );
        
        Transaction7702 tx = Transaction7702.createTransaction(
            42L,                                    // chainId
            BigInteger.valueOf(123),                // nonce
            BigInteger.valueOf(5_000_000_000L),     // maxPriorityFeePerGas
            BigInteger.valueOf(30_000_000_000L),    // maxFeePerGas
            BigInteger.valueOf(1_000_000),          // gasLimit
            "0x627306090abab3a6e1400e9345bc60c78a8bef57", // to
            BigInteger.ZERO,                        // value
            "0xdeadbeef",                           // data
            accessList,                             // <-- This is ignored!
            Collections.emptyList()                 // authorizationList
        );
        
        // This returns null, but should return the accessList provided above
        List<AccessListObject> actualAccessList = tx.getAccessList();
        System.out.println("Access list is null: " + (actualAccessList == null)); // prints "true"
    }
}

Expected behavior

The accessList field should be set to the provided value, and tx.getAccessList() should return the non-empty access list passed to createTransaction().

Actual behavior

The accessList parameter is accepted but silently ignored. The field remains null because Transaction7702.createTransaction() doesn't set the inherited accessList field from Transaction2930.

Root cause: Looking at the source code, Transaction7702.createTransaction() constructs the object but never calls setAccessList() on the parent class.

Environment

  • Web3j version: 5.0.2 (latest)
  • Java version: 21
  • Operating System: macOS / Linux

Additional context

Related code in Transaction2930

Transaction7702 extends Transaction2930, and the accessList field is defined in the parent class. The Transaction2930.createTransaction() method correctly sets this field, but Transaction7702.createTransaction() appears to have missed it.

Impact

This causes incorrect RLP encoding when encoding EIP-7702 transactions that should include an access list, potentially leading to:

  • Wrong transaction hash calculation
  • Failed transaction validation
  • Incorrect gas estimation

Suggested fix

Fix the Transaction7702 constructor to pass accessList to the parent class Transaction1559:

protected Transaction7702(
        long chainId,
        BigInteger nonce,
        BigInteger maxPriorityFeePerGas,
        BigInteger maxFeePerGas,
        BigInteger gasLimit,
        String to,
        BigInteger value,
        String data,
        List<AccessListObject> accessList,
        List<AuthorizationTuple> authorizationList) {
    // Pass accessList to Transaction1559 constructor (9-parameter version)
    super(chainId, nonce, gasLimit, to, value, data, maxPriorityFeePerGas, maxFeePerGas, accessList);
    this.authorizationList = authorizationList;
}

Root cause: The current code calls super(chainId, nonce, gasLimit, to, value, data, maxPriorityFeePerGas, maxFeePerGas) which invokes the 8-parameter constructor of Transaction1559 that internally passes Collections.emptyList() to the grandparent class. It should instead call the 9-parameter constructor that accepts and passes the accessList parameter.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugA bug in behaviour or functionality

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions