Skip to content

KernelFactory ABI mismatch vs IKernelFactory causes runtime failures when cast and used downstream #190

@lincicomb

Description

@lincicomb

Have you ensured that all of these are up to date?

  • This repo
  • Any dependencies (according to the package.json)

What command(s) is the bug in?

No response

Operating System

None

Describe the bug

  • Package: @rhinestone/modulekit

  • Area: src/accounts/kernel/KernelFactory.sol
    Summary
    The ModuleKit KernelFactory wrapper exposes functions with the parameter order (bytes32 salt, bytes data), but the IKernelFactory interface expects (bytes data, bytes32 salt). Downstream code that casts the wrapper to IKernelFactory and then calls createAccount(data, salt) or getAddress(data, salt) will fail at runtime because the function selectors do not match.

Impact
When the wrapper is cast to IKernelFactory, calls to createAccount(bytes, bytes32) and getAddress(bytes, bytes32) do not resolve to any function on the wrapper, causing reverts and preventing account creation.
This can be easy to miss in tests/examples and only show up at runtime.

Code references
IKernelFactory.sol

interface IKernelFactory {
    function createAccount(bytes calldata data, bytes32 salt) external payable returns (address);
    function getAddress(bytes calldata data, bytes32 salt) external returns (address);
}

KernelFactory.sol

contract KernelFactory is IAccountFactory, KernelPrecompiles {
    // ...
    function createAccount(
        bytes32 salt,
        bytes memory data
    ) public override returns (address account) {
        account = factory.createAccount(data, salt);
    }

    function getAddress(bytes32 salt, bytes memory data) public override returns (address) {
        return factory.getAddress(data, salt);
    }
}

Reproduction

  • Deploy KernelFactory and call init().
  • Cast to IKernelFactory and attempt to create an account:
    IKernelFactory(address(kernelFactory)).createAccount(initData, salt);
    The call fails because the wrapper doesn’t implement the createAccount(bytes,bytes32) selector.
    Expected behavior
    A contract used as an IKernelFactory should export the same ABI:
    createAccount(bytes data, bytes32 salt)
    getAddress(bytes data, bytes32 salt)
    Actual behavior
    Wrapper exports inverse parameter order:
    createAccount(bytes32 salt, bytes data)
    getAddress(bytes32 salt, bytes data)
    Proposed fixes
  • Option A (recommended): Make KernelFactory implement IKernelFactory directly and expose:
    function createAccount(bytes calldata data, bytes32 salt) external payable returns (address)
    function getAddress(bytes calldata data, bytes32 salt) external returns (address)
    Forward internally to the underlying factory.
  • Option B: Add overloads with both orders to preserve backward compatibility.
  • Option C: If the wrapper is intended for a different interface, rename the contract and update docs/examples to avoid casting it to IKernelFactory. Recommend users deploy IKernelFactory via KernelPrecompiles for production-parity usage.
    Environment

Solidity: 0.8.23

Tooling: Foundry

Context: Building ERC-7579 Kernel accounts with session validators and hooks. Using ModuleKit in tests and aiming for production parity.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions