Skip to content

fix(ante): enforce EIP-3607 after Prague, exempting only EIP-7702 delegation designations - #1111

Merged
randy-cro merged 1 commit into
crypto-org-chain:developfrom
randy-cro:fix/eip3607-prague-delegation-only
Sep 25, 2026
Merged

randy-cro merged 1 commit into
crypto-org-chain:developfrom
randy-cro:fix/eip3607-prague-delegation-only

Conversation

@randy-cro

Copy link
Copy Markdown

Issue

Our current ante handler blocks accounts who holds contract code from executing an evm transaction.

// ante/eth.go
acct := statedb.NewAccountFromSdkAccount(accountGetter(from))
if !rules.IsPrague {                          // line 93
    if acct.IsContract() {
        fromAddr := common.BytesToAddress(from)
        return errorsmod.Wrapf(errortypes.ErrInvalidType,
            "the sender is not EOA: address %s, codeHash <%s>", fromAddr, acct.CodeHash)
    }
}

However, IsPrague = true by default. Therefore this code block doesn't run.

Solution

To allow eip7702 delegated accounts to execute evm transaction

@randy-cro
randy-cro requested a review from a team as a code owner September 25, 2026 09:06
@randy-cro
randy-cro requested review from JayT106 and thomas-nguy and removed request for a team September 25, 2026 09:06
@codecov

codecov Bot commented Sep 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 47.08%. Comparing base (db757f3) to head (878fb19).
⚠️ Report is 2 commits behind head on develop.

Files with missing lines Patch % Lines
ante/eth.go 0.00% 3 Missing ⚠️
evmd/ante/handler_options.go 0.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #1111      +/-   ##
===========================================
- Coverage    47.09%   47.08%   -0.01%     
===========================================
  Files          200      200              
  Lines        17647    17648       +1     
===========================================
  Hits          8310     8310              
- Misses        8475     8476       +1     
  Partials       862      862              
Files with missing lines Coverage Δ
evmd/ante/handler_options.go 62.88% <0.00%> (ø)
ante/eth.go 0.00% <0.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@JayT106

JayT106 commented Sep 25, 2026

Copy link
Copy Markdown

@claude review

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Claude finished @JayT106's task in 1m 54s —— View job


Code Review

Tasks

  • Gather context from PR description and changed files
  • Review ante/eth.go changes
  • Review evmd/ante/eth_test.go changes
  • Review evmd/ante/handler_options.go changes
  • Review CHANGELOG.md changes
  • Post final review

Summary

This PR fixes a real bug: the IsPrague guard was accidentally suppressing EIP-3607 enforcement for all post-Prague chains (the default), allowing any contract-code account to send transactions. The fix correctly re-enforces EIP-3607 while carving out an exemption for EIP-7702 delegation designators.


Findings

✅ Correctness — logic is right

The old code:

if !rules.IsPrague {   // always false → block never ran
    if acct.IsContract() { ... }
}

The new code runs unconditionally and passes the check only for EIP-7702 delegated accounts. This is exactly the correct EIP-3607 behaviour for post-Prague chains.

⚠️ Pre-Prague behaviour change

The old code silently skipped the check on Prague-enabled chains, and also skipped it on pre-Prague chains where IsPrague=false would have been wrong too. The new code applies uniformly to all forks. On a pre-Prague chain EIP-7702 delegation codes cannot exist, so ParseDelegation always returns false, and every contract sender is rejected — identical to the intended pre-Prague behaviour. This is fine, but worth stating explicitly since the signature change (removing rules) makes the fork-awareness implicit.

⚠️ API breaking change — rules parameter removed

VerifyEthAccount is a public function. Removing rules params.Rules from its signature is a breaking change for any downstream consumer that calls it directly. The CHANGELOG entry should mention this if this library is consumed externally.

⚠️ Extra GetCode read on every transaction from a delegated account

ante/eth.go:94:

code := evmKeeper.GetCode(ctx, common.BytesToHash(acct.CodeHash))

This is an additional DB read for every ante-handler execution where the sender has a non-empty code hash (i.e., all EIP-7702 delegated accounts). It's unavoidable with the current architecture, but the hot path for regular EOA senders (acct.IsContract() == false) is not affected. Worth noting in a comment.

⚠️ Test coverage — Codecov reports 0% for new lines in ante/eth.go

Codecov's report is 2 commits behind head on develop, so the numbers may be stale. Looking at the test code directly, both new cases are exercised: the delegated-account case calls vmdb.SetCode(addr, ethtypes.AddressToDelegation(...), 0) and the contract-code case uses raw bytecode {0x60, 0x00, 0x60, 0x00, 0xfd}. The test flow (malleate → Commit → VerifyEthAccount) should reach the new code. Coverage should be re-confirmed once the report catches up.

✅ ParseDelegation import is consistent

set_code_authorizations.go uses types.ParseDelegation from "github.com/ethereum/go-ethereum/core/types". The new code aliases the same package as ethtypes — identical function, consistent package. No issue.

✅ common.BytesToHash(acct.CodeHash) is consistent

This is the same pattern used in x/evm/statedb/state_object.go:157. Correct.

✅ No consensus/state-breaking changes

This is an ante-handler change (transaction validation). It affects which transactions are accepted, not how state is written. Validators running the new code will reject non-EIP-7702 contract senders that the old code (incorrectly) allowed. This is a consensus-level tightening of rules, but it is the correct behaviour according to EIP-3607 — the old behaviour was the bug. No migration needed.


Minor suggestions

ante/eth.go:93-99 — consider adding a one-line comment explaining why GetCode is needed (i.e., EIP-7702 exemption), to make the intent obvious to future readers.

// EIP-3607: reject contract senders, but allow EIP-7702 delegation designators.
if acct.IsContract() {
    code := evmKeeper.GetCode(ctx, common.BytesToHash(acct.CodeHash))
    if _, delegated := ethtypes.ParseDelegation(code); !delegated {

Verdict

The fix is correct and necessary. The two test cases cover the key scenarios. The 0% coverage report is likely stale. Before merging:

  1. Confirm coverage catches up once the CI run on head is reflected.
  2. Consider whether downstream callers of VerifyEthAccount exist outside this repo and need a deprecation note.

Comment thread ante/eth.go
@randy-cro
randy-cro merged commit e9c85d5 into crypto-org-chain:develop Sep 25, 2026
42 of 43 checks passed
@randy-cro
randy-cro deleted the fix/eip3607-prague-delegation-only branch September 25, 2026 09:34
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.

2 participants