Wagmi Feature Development
wevm/wagmi
Walks through adding a Wagmi feature across its layers: a Viem-based core action, TanStack Query options, and React and Vue bindings.
Clean up and future-proof a ported static test. An agent skill from ethereum/execution-specs.
$ npx skills add ethereum/execution-specs --skill enhance-ported-test -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install ethereum/execution-specs enhance-ported-test --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/ethereum/execution-specs.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/enhance-ported-test .claude/skills/enhance-ported-test && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "enhance-ported-test" agent skill from https://github.com/ethereum/execution-specs/tree/forks%2Fbogota/.agents/skills/enhance-ported-test into .claude/skills/enhance-ported-test/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "enhance-ported-test", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/ethereum/execution-specs/tree/forks%2Fbogota/.agents/skills/enhance-ported-testType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add ethereum/execution-specs --skill enhance-ported-test -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install ethereum/execution-specs enhance-ported-test --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ethereum/execution-specs.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.agents/skills/enhance-ported-test .agents/skills/enhance-ported-test && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "enhance-ported-test" agent skill from https://github.com/ethereum/execution-specs/tree/forks%2Fbogota/.agents/skills/enhance-ported-test into .agents/skills/enhance-ported-test/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "enhance-ported-test", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add ethereum/execution-specs --skill enhance-ported-test -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install ethereum/execution-specs enhance-ported-test --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ethereum/execution-specs.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.agents/skills/enhance-ported-test .cursor/skills/enhance-ported-test && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "enhance-ported-test" agent skill from https://github.com/ethereum/execution-specs/tree/forks%2Fbogota/.agents/skills/enhance-ported-test into .cursor/skills/enhance-ported-test/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "enhance-ported-test", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/ethereum/execution-specs.git --path .agents/skills/enhance-ported-test--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add ethereum/execution-specs --skill enhance-ported-test -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install ethereum/execution-specs enhance-ported-test --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ethereum/execution-specs.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.agents/skills/enhance-ported-test .gemini/skills/enhance-ported-test && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "enhance-ported-test" agent skill from https://github.com/ethereum/execution-specs/tree/forks%2Fbogota/.agents/skills/enhance-ported-test into .gemini/skills/enhance-ported-test/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "enhance-ported-test", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install ethereum/execution-specs enhance-ported-testInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add ethereum/execution-specs --skill enhance-ported-test -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/ethereum/execution-specs.git skills-src && mkdir -p .github/skills && cp -r skills-src/.agents/skills/enhance-ported-test .github/skills/enhance-ported-test && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "enhance-ported-test" agent skill from https://github.com/ethereum/execution-specs/tree/forks%2Fbogota/.agents/skills/enhance-ported-test into .github/skills/enhance-ported-test/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "enhance-ported-test", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add ethereum/execution-specs --skill enhance-ported-test -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install ethereum/execution-specs enhance-ported-test --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ethereum/execution-specs.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.agents/skills/enhance-ported-test .opencode/skills/enhance-ported-test && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "enhance-ported-test" agent skill from https://github.com/ethereum/execution-specs/tree/forks%2Fbogota/.agents/skills/enhance-ported-test into .opencode/skills/enhance-ported-test/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "enhance-ported-test", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
enhance-ported-testClean up and future-proof a ported static test. An agent skill from ethereum/execution-specs.
Enhance Ported Test is an agent skill from ethereum/execution-specs. Clean up and future-proof a ported static test.
Its SKILL.md is about 12k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It works with Ethereum. The repository describes itself as: Specification for the Execution Layer. Tracking network upgrades. The licence is CC0-1.0.
12 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit dc6d1a5. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
uvFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use uv, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Enhance Ported Test loads about 12k tokens when it runs. Until then it costs about 17 tokens; SKILL.md has 6,565 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from ethereum/execution-specs at commit dc6d1a5, republished under its CC0-1.0 licence (© ethereum). 6,565 words, ~12,012 tokens.
.claude/skills/enhance-ported-test/SKILL.md (or your agent's skills folder).Future-proof and clean up a test under tests/ported_static/. These tests were
machine-ported from the legacy ethereum/tests static fillers (YAML/JSON) and
carry a lot of boilerplate, hardcoded values, and weak/incomplete post-state
checks. This skill is the ordered methodology for turning one into idiomatic,
robust Python.
This skill is a living document: it captures the cases we have validated so far. Real tests will hit shapes not covered here — that is expected. When you find one, solve it, then add the new case/step to this file.
The end state is a test that passes on every fork from its valid_from
onward (not just the baseline), expresses its intent explicitly, and has no
fragile hardcoded constants. "Future-proof" = a later fork that re-prices gas,
adds state costs, or changes account rules should not silently break it.
Most of the work is removing boilerplate one piece at a time and proving the test still passes after each removal:
uv run fill <path> --fork=<valid_from-fork> -q --clean.Do low-risk, independent removals in small batches if you like, but anything that can plausibly interact (addresses, contracts, gas) goes one at a time so a failure is attributable.
--fork=<baseline> (usually Cancun) — fast.valid_from range (omit --fork) so all
deployed forks are exercised.--fork Amsterdam (or the latest fork
that enables new EIPs). A gas/state-cost change there is the most likely
future breakage. (Historical note: broken tests used to be parked in a
tests/ported_static/amsterdam_skip_list.txt consumed by a local conftest;
the list was emptied and both were removed. If a future fork's repricing
breaks tests en masse, the same parking pattern — a substring-matched skip
list plus a pytest_collection_modifyitems hook — is in git history.)fill output: writes to ./fixtures (--clean resets it), or pass
--output <dir> for a scratch location. Do not use -o — that is
pytest's --override-ini, not the output dir.Do them roughly in this order. Earlier steps unblock later ones (notably: audit the bytecode before touching gas, since restoring elided opcodes moves the budget; and max out gas before strengthening post-state, so added opcodes don't hit a gas ceiling).
# Source: yul commentThe # Source: yul blocks are the filler's source; the bytecode beside them is
what solc emitted, and the optimizer is free to delete operations the test
depends on. A port that faithfully reproduces the compiled bytecode therefore
faithfully reproduces the hole the optimizer left. Do this first —
restoring elided operations changes gas, so it must precede any budget work
(steps 2 / 10).
The canonical fold: a self-cancelling SSTORE pair. Refund tests set a slot
then clear it (sstore(k, 1); sstore(k, 0)) to earn a refund. In a fresh
CREATE frame slot k is already zero, so solc folds the pair down to
sstore(k, 0) — a no-op that generates no refund at all, leaving the test
vacuous while still passing. Validated on test_create_oog_from_call_refunds,
where 2 of 24 init codes had lost their sstore(1, 1): the OoG arms assert the
sender's balance reaches exactly zero, which is the "refund earned inside a
reverted frame must be discarded" check — and it was asserting nothing.
How to check. Disassemble every bytecode blob and diff it against the comment
above it. Comparing opcode counts per mnemonic (sstore( in the Yul vs.
SSTORE in the asm) catches the whole class in one pass. A throwaway script that
ast-parses the test, evals each Op... assignment against a namespace of the
test's constants, and walks bytes(...) through a PUSH*-aware opcode table is
enough — there is no disassembler in execution_testing.
Tells in the ported source. Dense DUP/SWAP juggling
(Op.SSTORE(key=Op.DUP2, value=Op.DUP2), a bare Op.PUSH1[0x1] + Op.PUSH1[0x0]
prologue, a trailing argument-less Op.RETURN) is solc's stack reuse — the shape
most likely to hide a fold, and unreadable regardless. Rewrite those from the Yul
into explicit Op.SSTORE(key=..., value=...) / Op.RETURN(offset=..., size=...)
form: it restores the intent and makes the next audit trivial.
Benign deviations — do not "fix" them. solc drops a POP before a terminator
(pop(call(...)); return(0, 1) compiles without the POP, as RETURN ignores
leftover stack) and encodes repeated literal zeros as DUP1 chains
(Op.CALL(..., args_offset=Op.DUP1, ...)). Both are semantically identical to
the Yul. Only a missing or added state-changing operation is a real
deviation.
Expect to re-budget afterwards. Restoring an elided op adds its cost — a
zero->non-zero SSTORE is ~22.1k pre-EIP-8037 and ~97.9k of state gas on
Amsterdam — so a test with a hardcoded gas_limit may now OOG. That is usually
not a regression you introduced: it reveals that the sibling cases which never
lost their op were already failing on the future fork for the same reason.
Establish this before re-budgeting by copying the pre-change file aside under a
different test name, filling both, and diffing the failure sets — in the
validated case that separated 12 pre-existing Amsterdam failures from the 3 the
fix added.
Verify the restoration is observable, not merely green. Fill before and
after and reconcile the gas delta. Above, consumption moved 77731 -> 97857 (the
added cold SSTORE, minus the reset dropping to a warm 100) and the 19900 refund
was capped by EIP-3529 at 97857 // 5 = 19571, giving the reported 78286 exactly.
A delta you cannot account for means the rewrite changed the program (see
"Re-pinning" below).
envDelete the Environment(...) block, the env=env arg to state_test, and any
now-orphaned vars (coinbase) and the Environment import. The framework
supplies sensible defaults.
Keep env only if the post asserts on the coinbase/fee_recipient balance,
or the bytecode reads block fields (NUMBER, TIMESTAMP, PREVRANDAO,
BASEFEE, GASLIMIT, COINBASE). fee_recipient=sender alone is not a reason
to keep it.
gas_limit from the transaction (if gas is not the subject)This is the common case and belongs early. Omitting gas_limit maxes out the
gas the tx receives, so the body executes fully. See the [Transactions section]
(../write-test/SKILL.md#transactions) of the write-test skill.
fork.is_eip_enabled(8037) budget bumps) and often the fork param itself.GAS
reading or a SUB(@gas_before, GAS) delta (legacy slots 0 / 0x64), the
test measures gas — handle it under step 10 (preserve via CodeGasMeasure),
do not just strip gas_limit. This was the dominant skip-list shape:
the stored gas value is exactly what EIP-8037 re-prices and breaks.gas_limit on a test that measures an
operation incurring state gas (account creation, storage writes), add
state_gas_reservoir=0 to the tx, or that state gas is silently dropped from
the measurement on EIP-8037 forks (see step 10). Pure-execution opcodes
(e.g. PUSH0, arithmetic) have no state gas and do not need it.gas_limit; omission is
the default.nonceDrop nonce=0 from pre.deploy_contract(...). If a compute_create_address(..., nonce=N) in the post depends on it, keep them consistent.
Two sub-cases:
contract = Address(0x...) literal that is immediately
overwritten by pre.deploy_contract(...) (no address=). Just delete the
literal; the deploy returns a fill-generated address.address=: remove both the literal and the address=
argument, per contract, filling after each.to=None creation tests often have no hardcoded address at all
(the created address is compute_create_address(sender, nonce=0)). Confirm by
grepping for Address(0x / address=.to/data). Thread the dynamic address through the caller and the tx
entry point instead.Op.BALANCE(0xF172…) where 0xF172… is its own address=). Threading a
fill-generated address in is impossible (chicken-and-egg), so replace the
self-reference with the opcode that yields it at runtime — Op.BALANCE(Op. ADDRESS). Don't substitute a different opcode that happens to be shorter
(e.g. Op.SELFBALANCE) if it changes what the test exercises.@pytest.mark.pre_alloc_mutable once the test no longer hardcodes
addresses/nonces or assigns pre[...] directly — i.e. all allocation now goes
through fund_eoa / deploy_contract / nonexistent_account. Fill to confirm.Independent and usually safe (batchable): pre.fund_eoa(amount=...) → fund_eoa();
tx value; tx data when it is empty (Bytes("")); explicit gas price fields.
Keep any of these that the post actually checks or that triggers the behavior
under test.
Op.CALL(..., args_offset=0, args_size=0, ret_offset=0, ret_size=0) — all four are 0 by default. Removing
them is a no-op on the assembled bytecode (verify once with
bytes(a) == bytes(b)) and cuts noise. Applies to any opcode arg equal to its
default.gas operand — this is a correctness fix, not
cosmetics. Op.CALL/CALLCODE/DELEGATECALL/STATICCALL default gas to
Op.GAS (forward all remaining). Ported fillers hardcode a constant
(gas=0xEA60, gas=0x186A0) that was sized for the old gas schedule; once
EIP-8037 inflates the callee's state gas (e.g. a zero→non-zero SSTORE jumps to
~97920), that fixed budget no longer covers the callee and the subcall OOGs on
Amsterdam — a common reason a pure-behavior test lands on the skip list. Omit
the operand so it forwards everything. Caveat: forwarding all gas via
Op.GAS misbehaves on pre-EIP-150 (Homestead) — the sweep (step 11) fails
only there, so such tests floor at TangerineWhistle. Keep an explicit gas
operand only when the amount forwarded is the subject (an OOG-boundary test).
Budget vs. subject: before dropping the operand, ask why the constant
has its value. A mid-sized constant (0xEA60) is a budget sized for the old
schedule — drop it. An absurd or boundary constant (2**256 - 20) is the
subject: it exercises the 63/64 clamp on an oversized ask (a client that
computed e.g. requested + stipend in wrapping arithmetic would forward
almost nothing and fail). Keep it, name it (OVERSIZED_GAS_ASK), and state
the intent in a comment. Validated on test_make_money.pre.nonexistent_account(), not
pre.fund_eoa(amount=0). It yields an address guaranteed to hold no code and
no state, which is what "call an empty contract" tests mean.# noqa: F841 on contract = pre.deploy_contract(...) once the
variable is actually used (in to= / the post); leaving it triggers RUF100.data parameter isLook at tx.data / tx.to:
CALLs the address from calldata. Usually you
can delete the entry-point and call the target directly, and the N targets
are near-identical → replace N bytecode copies with a dynamic generator
parameterized by the small difference. When the targets are gas-measurement
contracts differing only by the measured opcode, the dedup collapses all the
way to a single CodeGasMeasure(code=opcode) parametrized on the opcode
(step 10) — the entry-point's CALL was only a delivery mechanism. Validated
on test_push0_gas2 (PUSH0 vs PUSH1 0x00).to=None. Decide whether
running inside initcode is required by the test (e.g. the test is about
initcode-context behavior, per its title/docstring) or just an artifact of the
static-filler format (most common — then the logic can move to a normal
deployed contract). If required, convert the tx_data array into an
initcode(d) generator function: even when variants are genuinely
different programs, the function form lets each branch be labeled by intent,
surfacing the one thing that varies.expect_entries_ / resolve_expect_postFirst, identify which index actually discriminates — it is not always d.
Ported tests also key on g (gas) or v (value); check both the
expect_entries_ indexes (which axis is non--1) and which of
tx_data[d]/tx_gas[g]/tx_value[v] is the list with >1 entry. The other two
indexes are pinned/wildcard. (Example: test_add_non_const varies v —
d/g are fixed at 0 and the indexes match on "value".)
Precondition (to collapse to a per-case form): every entry's network is
implied by valid_from and there is no expect_exception. Then the post is a
pure function of the discriminating index.
expect_entries_ into a plain list of result dicts indexed by the
discriminator — duplicating identical entries (e.g. data [0,1] → two
slots) is fine and preferred; an explicit flat list is easiest to reason about.value or gas),
parametrize directly on that quantity (parametrize("tx_value", [0, 1]))
rather than an opaque index, feed it straight into the Transaction, and
express the post as a function of it. A clean closed form is ideal —
e.g. Account(storage={0: 2 * tx_value}) for a contract that stores
ADD(BALANCE, BALANCE) of a balance equal to the sent value (this is the
"encode relationships" idea from step 9 applied to the post).resolve_expect_post import, the _exc it returned, and
the tx's error=_exc.if/elif/else on d that sets both initcode and post per case. This
co-locates each case's bytecode with its expected state — the strongest
readability win, and it tends to reveal incomplete verification. Use a final
else so every branch binds both vars; declare initcode: Bytecode and
post: dict above the switch. Prefer the array form when cases are many or
the switch would be unwieldy; this is a judgment call.parametrize signature. The ported "d, g, v" triple is
usually overkill: drop the pinned/unused indexes from both the parametrize
and the function signature, keep the discriminator, and rename it to something
meaningful (and fork too, if no longer used). Parametrize on the renamed axis:parametrize("opcode", ["calldataload", "calldatacopy", "codecopy"])) read best when the cases are distinct
programs; pytest derives the test ids straight from the strings (matching the
old id=s), and the switch branches become if opcode == "calldataload".Op values (e.g. parametrize("opcode", [Op.SLOAD, Op.TLOAD])) are
cleaner only when the opcode plugs directly into a shared bytecode template;
avoid forcing it when each case needs structurally different code.pytest.param(..., id=...) wrapping when the bare values
already give good ids.Ported fillers often arrive as a fan of files with near-identical names that
differ in one axis — test_non_zero_value_{call,callcode,delegatecall} ×
{,_to_empty,_to_one_storage_key,…}. Once enhanced to the same shape, join
them into one parametrized test (parametrize("opcode, target_kind", …) with
ids matching the old filenames), set up the varying piece (call op, target
pre-state) from the params, and merge every source into a single ported_from
list. One readable file replaces N. Validated: 10 NonZeroValue_* files →
test_non_zero_value.py.
Co-locating bytecode and post (step 7) often exposes that the ported test barely verifies anything. Improve coupling and observability:
CODECOPY+RETURN), assert code=initcode instead of a hand-copied
bytes.fromhex(...) — change the bytecode and the expectation follows.0 is indistinguishable from not
storing (and storage={} already asserts "all slots zero" — see
Storage.must_be_equal). To genuinely prove a read returned zero, store a
derived non-zero value (e.g. Op.ADD(Op.CALLDATALOAD(0), 1) → assert 1).data=bytes(range(1, 33)) for a CALLDATACOPY test) so a
client reading from a wrong in-bounds offset produces a visible mismatch.
Ported fillers often ship all-zero calldata; the rewrite is the moment to
fix it. Validated on test_copy_offset.test_raw_call_gas_ask (the
caller reports its remaining gas up the stack as a second return word).Op.SSTORE(0x2, 0xC0DE)), and assert it. If creation
reverts or the code doesn't run to completion, the slot stays zero and the
test fails loudly instead of silently passing on a coincidentally-matching
(often empty) account.SSTOREs costs gas — this is why step 2 (max out gas) comes first.*_after_value_transfer / *_with_value test that sends value=0, so the
observable it names (a callee's CALLVALUE, a recipient's balance) is
vacuously zero and would pass even if the behavior were broken. Fix it by
supplying the missing ingredient (a non-zero tx value) and asserting the
now-meaningful result (CALLVALUE == transferred, recipient balance moved) —
note the restoration in the @manually-enhanced line. Validated on
test_deleagate_call_after_value_transfer (DELEGATECALL preserves the
enclosing frame's value). Read the test's name and source comment against
what it actually checks; the gap is the enhancement. The compiler-optimized
init code of step 0 is the same family, one level down: there the bytecode
stopped matching the scenario its own Yul comment describes.Engine X packing can introduce an intentional collision into another test.
Two tests that deploy identical creator bytecode derive the same CREATE address.
If one predeploys a collider there and the other requires it absent, their
pre-allocations must not share a packed genesis. Give the collision test a named
@pytest.mark.pre_alloc_group(...), then fill both with
--generate-all-formats and verify Engine X matches its ordinary engine sibling.
Validated on the stRevertTest CREATE collision and CREATE-OOG pair.
Whenever a literal carries intent or two literals are logically linked, lift them
into named variables that express the relationship, not just the value. E.g.
create_value = 0xB fed to both Op.CREATE(value=create_value, ...) and the tx
value=create_value - 1 documents an intentional off-by-one (insufficient
balance) and keeps the two coupled so a future edit can't desync them. Same idea
ties a CREATE's size operand to the memory/gas math that depends on it.
BALANCE read mid-execution equals
sender_balance - gas_limit * effective_gas_price), express it as that formula
rather than a hardcoded number. Such a test is gas-sensitive — keep an explicit
gas_limit (step 10), since the observable depends on it, but derive that
gas_limit too — fork.transaction_intrinsic_cost_calculator()() + code.gas_cost(fork) + buffer (conservative metadata so it can't undershoot) —
so it is neither a magic number nor fork-fragile. Validated on
test_sender_balance (EIP-1559 effective-vs-max price).sender balance to initial − value − gas_used * price — pure filler bookkeeping, not what the test is about. If the
real subject is a gas-independent fact (a value flow tx → caller → callee,
a storage write, a created account), drop the gas_limit (step 2), drop the
fragile sender-balance assertion, and instead assert the gas-independent
facts, encoding them as a relationship (caller: INITIAL + tx_value - call_value, callee: INITIAL + call_value). Only reach for the "derive the
fee formula" machinery above when the fee itself is the observable. Validated
on test_make_money.return(0, 5000) — raising gas_limit to fit the successful cases
can quietly fund the failing ones, flipping them to success. That direction
fails silently, because a passing test is the failure mode. Name the quantity
(oversized_code_size = 5000), feed it to both the Op.RETURN operands and a
guard: assert tx_gas[g] < oversized_code_size * fork.gas_costs().CODE_DEPOSIT_PER_BYTE. That constant is the last-resort form
(see step 10's code_deposit_size note); it is legitimate here only because
it understates the deposit on 8037 forks, keeping an "is this unaffordable?"
guard conservative. Prefer Op.RETURN's metadata whenever the comparison can
be expressed against the init code's own gas_cost(fork). Couple the sender's
balance to the budget in
the same breath — balance=tx_gas[g] * tx_gas_price — whenever the post asserts
it reaches exactly zero; a hardcoded 0x3D0900 silently desyncs the moment the
budget moves, and "burned the whole allowance" stops meaning anything. Validated
on test_create_oog_from_call_refunds.Covers both tests that assert a gas amount and the dominant broken-port
shape: a legacy GAS snapshot / SUB(@gas_before, GAS) delta stored to slot 0/0x64. That stored value is why EIP-8037
breaks the test, but it is real coverage — preserve and fork-robustify it, do
not drop it.
The CodeGasMeasure workflow:
call_code = Op.CALL(...)). This often reveals the legacy measured window
bundled extra ops — e.g. it wrapped an SSTORE, inflating the value by a cold
SSTORE (~22100). Isolating the opcode measures only it (a large but
explainable re-pin — see Re-pinning).CodeGasMeasure(code=call_code, extra_stack_items=N, sstore_key=K).
It self-calibrates (subtracts its own GAS ops and overhead_cost) so the
stored value is the opcode's real cost. extra_stack_items = items the
measured code leaves on the stack (CREATE/CALL leave 1) — wrong value
corrupts the result. sstore_key = the slot the post asserts.extra_stack_items=1 silently discards a call's success flag — keep it
observable. CodeGasMeasure SWAP/POPs the extra item, and gas alone
cannot replace it: a wrongly failed call refunds the child gas + stipend,
so it measures identically to a success into an empty callee, and for
CALLCODE/DELEGATECALL no balance moves either — the whole post-state is
then blind to the failure. When the measured op is a call whose success is
not otherwise observable, fold the flag into the measured window:
store_code = Op.SSTORE(flag_slot, call_code, key_warm=False, original_value=0, new_value=1) with extra_stack_items=0, assert
flag_slot: 1 in the post, and expect store_code.gas_cost(fork) (the
SSTORE's cost is now part of the measurement — and a failed call would
store 0, shifting the measured gas too, so the failure is doubly loud).
Validated on test_non_zero_value.gas_cost(fork) is
correct (see docs/writing_tests/opcode_metadata.md). For CALL:
address_warm (is the target pre-accessed?), value_transfer (value > 0?),
account_new (target absent/empty and receiving value → created?). Use
pre.nonexistent_account() for a target that must stay cold + non-existent
so account_new holds — a fund_eoa() target already exists (warm/created) and
would change the cost.CREATE/CREATE2: new_memory_size (the init-code window the offset/
size operands touch, e.g. size=0x20 → new_memory_size=0x20) and
init_code_size (drives the EIP-3860 per-word cost, Shanghai+). Omitting
init_code_size silently under-predicts by CODE_INIT_PER_WORD * ceil(size/32) (2/word) — a small, easily-missed miss. CREATE leaves the
created address on the stack → extra_stack_items=1.SLOAD (the create-then-call idiom:
store CREATE's result, then CALL(address=Op.SLOAD(slot))) must mark that
SLOAD key_warm=True — the slot was just written so it is warm at runtime,
but the metadata default is cold and gas_cost(fork) would over-predict by
cold − warm (2000). An account freshly made by CREATE is warm + already
existing: address_warm=True, account_new=False on the following CALL.call_code.gas_cost(fork) (add fork: Fork). Both the bytecode and
the expectation are now fork-aware.CALL value-transfer stipend. A value-bearing CALL whose callee consumes
nothing (empty account / EOA) measures gas_cost(fork) - fork.gas_costs().CALL_STIPEND: gas_cost counts the full value cost, but the
2300 stipend is forwarded to the callee and returned unused. Confirm the
- CALL_STIPEND holds on every fork (it is a fork-stable relationship, not a
coincidence).
EIP-8037 state-gas reservoir — critical. Omitting gas_limit (step 2) on an
EIP-8037 fork maxes the state-gas reservoir, so state gas (e.g. account
creation) is not charged against what the GAS opcode sees — the measurement
silently loses it (observed 192921 → 9321) and only the future fork breaks. Fix:
keep gas_limit omitted and add an explicit state_gas_reservoir=0 to the
Transaction. That pins the gas limit to exactly the cap (no reservoir) so state
gas is charged and measurable, and is a no-op on pre-EIP-8037 forks (a positive
reservoir there raises; 0 does not, and it must be set explicitly — the default
is treated as "unset"). This keeps a CodeGasMeasure test clean (no magic
gas_limit) yet correct on Amsterdam.
Absolute GAS readings are unsalvageable — convert to a delta. A test that
stores a raw GAS value (not a SUB(before, GAS) delta) — e.g. SSTORE(0, GAS) right after entry — pins gas_limit - intrinsic - overhead. Amsterdam
re-priced the intrinsic transaction cost (EIP-2780: base 21000 → 15000), so
that stored value shifts by a fixed amount (observed 578998 → 584998, a 6000
jump) independent of any state gas — state_gas_reservoir=0 does not fix
it. The only robust move is to stop storing absolute readings: wrap the measured
op in CodeGasMeasure (which stores the delta between two GAS reads, immune
to intrinsic) and assert code.gas_cost(fork). A legacy [[0]](GAS) … [[100]](GAS) snapshot pair is such a delta in disguise — the pair brackets one
operation (e.g. a CREATE); collapse it to a single CodeGasMeasure around that
op and drop both raw slots. Validated on the CREATE_EmptyContract* family.
Look for opcode metadata before hand-rolling a gas formula. Opcodes carry
kwargs that fold fork-dependent charges into gas_cost(fork) — Op.RETURN's
code_deposit_size, Op.CREATE's init_code_size/new_memory_size,
Op.CALL's address_warm/value_transfer/account_new, Op.SSTORE's
key_warm/original_value/new_value. A formula assembled out of
fork.gas_costs() constants has to be re-audited at every repricing; the
metadata tracks it for you. Check the opcode's Metadata docstring block in
packages/testing/src/execution_testing/vm/opcodes.py before reaching for
constants — a fork.gas_costs() reference in a derivation is a smell that the
metadata was missed.
Decompose the constant empirically when no single helper applies (throwaway
script against the fork): pin each term to the known-good number, then assemble.
Map terms to fork-derived helpers: opcode base+pushes → bytecode.gas_cost(fork);
memory growth → fork.memory_expansion_gas_calculator()(new_bytes=, previous_bytes=); EIP-3860 init-code words → `fork.gas_costs().CODE_INIT_PER_WORD
. You can also call .gas_cost/.regular_cost/.state_cost`
on exactly the measured bytecode.Reservoir-less sub-calls pay state gas from their regular grant. With
the tx reservoir at 0, a sub-frame's state charges spill from its own
gas_left — a delegate that does one first-set SSTORE needs its whole
~111k inside the forwarded grant on Amsterdam, not just the ~13k regular
part. Size derived sub-call budgets from the callee composite's full
gas_cost(fork). Corollaries: (a) a failed sub-frame contributes its
entire forfeited grant to the parent's measured window, not its "cost";
(b) SSTORE(flag, <call>) silently degrades to a ~3k no-op store when
the call fails — the flag reads 0 and no state gas is charged, which can
mask a broken callee behind a plausible-looking measurement. Validated on
test_new_gas_price_for_codes (delegate budget derived; failed value
calls return their stipends: subtract one CALL_STIPEND per failed
value-bearing call from window measurements).
Nested / callee-side measurements. When the measured op is a CALL whose
callee does real work, the measured cost = call_code.gas_cost(fork) + callee_code.gas_cost(fork) (the CALL's own cost plus what the callee consumed).
Attach the callee's opcode metadata (e.g. SSTORE key_warm/original_value/
new_value) so its gas_cost is right, and decompose against the callee's
actual bytecode rather than a reconstruction — a value supplied by GAS costs
2, not a PUSH's 3, and that off-by-3 is a real trap. A callee-side gas snapshot
(SSTORE(k, GAS)) stores forward_gas - Op.GAS.gas_cost(fork). Derive the
forwarded gas dynamically — forward_gas = callee_store.gas_cost(fork) + buffer
— rather than a magic number; under EIP-8037 a cold zero->non-zero SSTORE can
cost ~100k, so a fixed value is both fork-fragile and brittle. (Size the SSTORE
with a placeholder new_value: its cost depends only on the zero->non-zero
transition, not the magnitude — which also breaks the forward_gas/new_value
circularity.) Set state_gas_reservoir=0 so the state gas is captured.
Validated on test_raw_call_gas.
An expensive store after a callee that eats all forwarded gas — pre-write
the slot. When a frame must SSTORE a result after a subcall that
deliberately consumes its whole 63/64 grant (an OOG-probe callee), the frame
retains only 1/64 — under EIP-8037 that cannot afford a cold zero→nonzero
store (~111k), and pre-8037 it often couldn't afford the cold 2.2k either
(making the ported {slot: 0} expectation vacuous: caller-OOG and
callee-failure were indistinguishable). Fix: write a sentinel to the slot
before the call (paying cold + state with the full budget), then store
BASE + result after it — now a dirty-warm write (100 gas) the retention
always covers, and the three outcomes (success BASE+1, failure BASE,
caller OOG sentinel) are all distinct. Validated on
test_static_execute_call_that_ask_fore_gas_then_trabsaction_has.
Caveat — EIP-2200's stipend rule caps this trick. Any SSTORE (even a
100-gas dirty-warm one) exceptionally halts unless gas_left > 2300
(Istanbul+), so the 1/64 retention must exceed ~2400, i.e. the pre-call
budget must exceed ~154k. When the scenario requires a smaller budget
(e.g. a starved arm whose forwarded gas must undercut the callee's cost),
no post-call SSTORE is possible at all: write the sentinel before the
call and put nothing but a POP after it — frame completion (the account
persists with the sentinel) plus the callee-side observable already
separate the outcomes. Validated on
test_contract_creation_make_call_that_ask_more_gas_then_transaction_provided.
Refund-cap derivations need the EIP-7623 kwarg. The EIP-3529 cap's
base is the gas deducted before execution, which excludes the calldata
floor: pass return_cost_deducted_prior_execution=True to the intrinsic
calculator whenever the tx has calldata, or the derived executed (and
the cap) overstate. Validated on test_refund_suicide50procent_cap.
A CREATE address collision burns the child's gas allowance (the
EIP-684 path): the withheld child grant is consumed and nothing is
created. Under EIP-8037 a colliding target is alive (it has code or a
nonce), so no new-account state gas is charged there in the first place.
The burn is only observable if some arm lets the creator survive it:
size the creator's post-collision slack so that its 1/64 retention cannot
pay the next store but the whole slack could (starved arm), or so the
retention clears the EIP-2200 gate and pays it (covered arm). A creator
that dies in every arm rolls the burn back with itself and the test
passes even when the grant is returned. Validated on both
test_revert_depth_create_address_collision files (mutation: returning
the grant on collision flips the starved arms).
Loop-to-depth-1024 cannot replace loop-to-OOG. With 63/64
attenuation, reaching depth 1024 needs ~e^16 × the terminal gas — no
legal budget gets there. For call-loop depth tests the honest shape is a
fixed named budget with per-gas-schedule-era pinned depth counts, each
shift explained (±1 frame ≈ 64·ln(cost ratio)). Validated on
test_loop_calls_depth_then_revert.
The SSTORE dirty-rewrite composite tracks the pre-Berlin schedules.
Op.SSTORE(key_warm=True, original_value=0, current_value=0xFF, new_value=1).gas_cost(fork) prices 5,006 on ConstantinopleFix, 806 on
Istanbul and 106 from Berlin, so a derived budget needs no extra
headroom constant for those forks (an earlier note here claimed
otherwise; the padding it prescribed also masked a wrongful new-account
charge on Amsterdam). Checked on
test_revert_depth_create_address_collision's ConstantinopleFix sweep.
A starved arm must still reach the opcode under test. When a
"RevertDepth" style filler proves that a completed nested CREATE is
rolled back by a later OOG, the starved grant has to cover the CREATE
(and whatever stores precede it) and fall short only on the frame's
last store. A grant of "half the creator's needs" dies at the CREATE's
own charge, so the arm's NONEXISTENT/nonce=1 expectations hold
without anything having been created. Prove the arm reaches the opcode
with a throwaway raise at the top of the fork's generic_create (or
generic_call): every arm must hit it. Validated on
test_revert_depth_create2_oog and test_revert_depth_create_oog.
A "must OOG" budget has to fund the counterfactual. A test whose
observable is "the frame ran out of gas because of X" (a collision burn,
a failed sub-call) only pins X if the same budget would have completed
without X. Size the slack as victims + what X would have cost had it gone through + margin, then guard that X's leavings (the 1/64
retention) cannot pay the victims. Check it by disabling X in a spec
copy (e.g. account_deployable returning True): the test must fail.
Validated on test_create2collision_selfdestructed_oog, whose 30k
slack had been below its victims on every fork.
EIP-8037 repriced the code deposit's regular part — boundaries beware.
On 8037 forks the deposit charges only the keccak word cost
(OPCODE_KECCAK256_PER_WORD * ceil32(len)/32, ~6 gas) as regular gas plus
len * 1530 state; fork.gas_costs().CODE_DEPOSIT_PER_BYTE (200) is the
pre-8037 constant. Using 200/byte in a sufficiency budget merely
overshoots (safe); using it in a one-gas-short boundary silently funds
the deposit on Amsterdam. Branch on fork.is_eip_enabled(8037) for exact
deposit boundaries. Validated on
test_create_oo_gafter_init_code_returndata_size.
Match the intrinsic calculator's kwargs to the transaction's shape.
fork.transaction_intrinsic_cost_calculator()() defaults to
sends_value=False; under EIP-2780 a value-bearing transaction's intrinsic
includes the folded value-transfer cost (~5.9k), so a derived budget or
GAS-observation formula silently skews by that amount on Amsterdam only.
Pass sends_value=True when the tx carries value — or drop an incidental
tx value entirely (step 5) so the default holds. Validated on
test_store_gas_on_create.
A creation transaction's top frame pays new-account state gas
(EIP-8037) — but only for a fresh target. When deriving a create-tx
budget, the intrinsic calculator does not include the created account's
state gas — add
fork.transaction_top_frame_state_gas(contract_creation=True) (183,600 on
Amsterdam, 0 before) or the whole creation silently OOGs only on the
future fork. Exception: prepare_dispatch charges it only when the
target's pre-state account is EMPTY_ACCOUNT — a prefunded create
address pays nothing (validated on
test_out_of_gas_prefunded_contract_creation, whose budgets omit the
term). A nested CREATE's new-account state is charged to the parent
before the 63/64 withhold and refunded if the child fails, so a derived
budget must cover its peak (use the composite gas_cost(fork)), even
on paths where the net is zero.
Measuring forwarded gas / the EIP-150 63/64 rule (the *_gas_ask shape).
Ported fillers probe "how much gas does a subcall receive when it asks for more
than is available" by pinning an absolute forwarded amount — fork-fragile,
because "available" moves with the EIP-2780 intrinsic change. Make it robust
with three moves: (1) cap the caller frame's gas to a known budget with an
outer call (entry → CALL(gas=CALLER_GAS) → caller); because CALLER_GAS is
far below the outer frame's 63/64, the caller receives exactly CALLER_GAS
independent of the tx gas limit. (2) Return the observed GAS up the stack
(MSTORE(0, GAS) + RETURN(0, 32) in the callee, RETURN again in the caller,
SSTORE only in the top frame) instead of SSTORE-ing in a lower frame —
avoids the EIP-8037 state-gas trap. (3) Derive the expectation from the fork:
available = CALLER_GAS - caller_call_code.gas_cost(fork)
forwarded = available - available // 64 # NOT available * 63 // 64
expected_gas = forwarded + stipend - Op.GAS.gas_cost(fork)where stipend = fork.gas_costs().CALL_STIPEND for a value-bearing call (0
otherwise). The // 64 form is the trap: available - available // 64 and
available * 63 // 64 differ by exactly 1 whenever available % 64 != 0 (the
EVM uses the former). One parametrize over (opcode, value, memory) covers the
whole CALL/CALLCODE/DELEGATECALL family; floor Berlin (the call metadata).
Validated on test_raw_call_gas_ask (10 RawCall*GasAsk fillers).
Error paths charge regular gas only — assert regular_cost(fork). A failed
CREATE/CALL still charges its regular costs (base, memory, init-code words)
but creates no account, so no state gas is charged under EIP-8037. For a
success/failure parametrize, that is exactly the gas_cost(fork) vs
regular_cost(fork) split: success measures code.gas_cost(fork) (regular +
state), failure measures code.regular_cost(fork) (regular only). On pre-8037
forks state_cost is 0 so the two coincide — one expression, correct on every
fork. Drive a CREATE down the balance-failure path by funding the creator one
wei short of the transferred value (balance = value - 1); the created
address is then Account.NONEXISTENT. Validated end-to-end on
test_raw_create_gas (6 RawCreate*Gas fillers consolidated).
valid_from to extend coverageThe ported valid_from (often Cancun) is usually higher than necessary — lower
it to widen coverage. Find the true floor empirically: temporarily delete the
valid_from marker and fill with no --fork (the framework then runs from
Frontier up); the earliest fork that passes is your floor. Set
@pytest.mark.valid_from("<that fork>") — the marker is mandatory, so this is a
lowering, never a true removal.
address_warm / cold-access metadata + gas_cost(fork) is only valid from
Berlin (EIP-2929): earlier forks have no warm/cold distinction, so
gas_cost over-predicts by cold − flat (2600 − 700 = 1900) and every
pre-Berlin fork fails the measurement. Same shape elsewhere — EIP-3860
init-code metering floors at Shanghai, etc. The floor is whichever EIP the
test's behavior/metadata depends on, which the empirical sweep reveals directly.nonce=1 floors at SpuriousDragon
(EIP-161) — earlier forks start contract nonces at 0, so Frontier/Homestead/
TangerineWhistle fail on the nonce, not the gas. Read what the sweep's
earliest-passing fork is gated on; it is not always a gas-schedule change.bad v / INVALID_SIGNATURE_VRS failure is a signature floor, not a
real one — don't raise valid_from for it. The default Transaction is
EIP-155-protected, which pre-SpuriousDragon forks reject. Instead set
protected=fork.supports_protected_txs() (add fork: Fork): it goes
unprotected on Frontier/Homestead/TangerineWhistle and protected from
SpuriousDragon on. This keeps the floor at the behavior's real EIP (e.g.
Homestead for DELEGATECALL) instead of masking it at SpuriousDragon.
Validated on test_delegatecall_emptycontract.When a measurement rewrite (step 10) or bytecode change shifts a stored value,
the workflow is: change → fill → read the KeyValueMismatchError (want … got …) → update the expected value to the got → fill again.
Sanity gate: the shift must be explainable — either small (the gas of
removed framing ops) or large-but-precisely-accounted (e.g. isolating an opcode
in CodeGasMeasure drops a cold SSTORE ~22100 the legacy window had bundled).
A jump you cannot account for means the rewrite changed what is being measured
— stop and investigate, don't just paste the number.
@manually-enhanced markersA docstring @manually-enhanced: Do not overwrite marks a deliberate prior fix.
Respect it by default. It may be removed only when a better enhancement makes
the workaround it documents obsolete (e.g. maxing out gas removes a per-fork gas
budget hack) — and only under explicit direction.
Add the marker as the closing step once a test's enhancements are intentional
(genuinely-verifying post, dynamic addresses/gas) so future auto-porting won't
regress them; briefly state what was enhanced. Place it in the module
docstring, after the Ported from: block (blank line before), as a single
line: @manually-enhanced: Do not overwrite. <what changed>. (keep it ≤79
chars).
Not yet covered by a validated walkthrough; figure out and append when hit:
data × value/gas matrix) — single-axis d/g/v discrimination is now
handled (step 7), but a multi-axis post is not yet exercised.blockchain_test ported tests.Confirm with a full-range fill (--fork omitted) — every deployed fork
green is the definition of done. (If a skip list is ever reintroduced for a
future fork, also delete the test's entry and keep its count headers
accurate.)
Final sweep checklist — each of these has been missed in practice; check them one by one before calling the test done:
@pytest.mark.pre_alloc_mutable removed if no hardcoded addresses/
nonces/pre[...] remain (it silently skips the test in execute mode).Test_<filename>.) — the
module and function docstrings say what the test verifies, in
imperative mood ("Verify/Measure ...", not "Gas cost of ...").FORWARDED_GAS, GAS_SLOT, ...) —
consistent with sibling files in the same directory.available = BUDGET - code.gas_cost(fork) gets an
assert available > 0, ... so a future repricing that outgrows the
budget fails loudly at fill time instead of producing a garbage
expectation.When done, offer to run /lint. Note that pydantic coercion warnings
(dict→Alloc/Storage, Bytecode→Bytes, unfilled optional Transaction params)
are false positives from the type checker, not real issues.
© ethereum, CC0-1.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .agents/skills/enhance-ported-test of ethereum/execution-specs.
Open the folder on GitHubat commit dc6d1a5
Enhance Ported Test next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Enhance Ported Test this skillethereum/execution-specs | 1.2k | — | ~12k | Automated safety check: Pass | CC0-1.0 | |
| Wagmi Feature Developmentwevm/wagmi | 6.8k | — | ~3.8k | Automated safety check: Pass | MIT | |
| Release Roundethereumjs/ethereumjs-monorepo | 2.8k | — | ~2k | Automated safety check: Pass | None | |
| Update Est Fixturesethereumjs/ethereumjs-monorepo | 2.8k | — | ~3.3k | Automated safety check: Pass | None | |
| Swapper Depositswapperfinance/swapper-toolkit | 852 | — | ~1.8k | Automated safety check: Pass | MIT | |
| BNB Chain MCP Serverinternet-court/internet-court-skill | 6.5k | 1 repos | ~1.7k | Automated safety check: Pass | MIT |
wevm/wagmi
Walks through adding a Wagmi feature across its layers: a Viem-based core action, TanStack Query options, and React and Vue bindings.
ethereumjs/ethereumjs-monorepo
Runs a coordinated EthereumJS npm release round in six human-gated phases — intent and readiness, CHANGELOG, version bump, publish (human executes), post-publish verification, and announcements.
ethereumjs/ethereumjs-monorepo
Updates EthereumJS execution-spec test fixtures from an ethereum/execution-specs release, then (after a human merge) points the monorepo submodule, updates VM npm scripts, reports a first test run…
swapperfinance/swapper-toolkit
Deposit and bridge funds into a wallet or protocol using Swapper Finance.
internet-court/internet-court-skill
Connects an agent to the BNB Chain MCP server to read blocks and contracts, move tokens and NFTs, register ERC-8004 agents and use Greenfield storage.
Minara-AI/minara-skills
Drives the Minara CLI for crypto swaps, perps, limit orders, wallet transfers, deposits and withdrawals, plus AI market analysis.
ethereum/execution-specs
Run locally filled fixtures against execution clients with a selected Hive simulator and a network client configuration from hive-tests.
ethereum/execution-specs
Track EIP test coverage with the repository checklist system.
ethereum/execution-specs
Fill test fixtures with the repository fill command. An agent skill from ethereum/execution-specs.
ethereum/execution-specs
Audit grammar in documentation and code comments. An agent skill from ethereum/execution-specs.
ethereum/execution-specs
Implement EIP specification changes using repository conventions.
ethereum/execution-specs
Write and run isolated pytester-based plugin tests. An agent skill from ethereum/execution-specs.
Works with
Clean up and future-proof a ported static test. An agent skill from ethereum/execution-specs. Enhance Ported Test is an agent skill from ethereum/execution-specs. Clean up and future-proof a ported static test.
Run `npx skills add ethereum/execution-specs --skill enhance-ported-test -a claude-code`. Or copy the skill folder (.agents/skills/enhance-ported-test in ethereum/execution-specs) into .claude/skills/enhance-ported-test in your project. Claude Code loads it when a task matches its description.
Run `npx skills add ethereum/execution-specs --skill enhance-ported-test -a codex`. Or copy the skill folder (.agents/skills/enhance-ported-test in ethereum/execution-specs) into .agents/skills/enhance-ported-test in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add ethereum/execution-specs --skill enhance-ported-test -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/enhance-ported-test, .gemini/skills/enhance-ported-test, .github/skills/enhance-ported-test and .opencode/skills/enhance-ported-test in your project.
Going by SKILL.md and its folder, Enhance Ported Test needs the command-line tools its instructions call (uv).
SKILL.md contains no URLs. Its commands use uv, which can reach the network depending on how they are called. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Enhance Ported Test is published under the CC0-1.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 12k tokens (SKILL.md is roughly 48k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Enhance Ported Test: Wagmi Feature Development (wevm/wagmi, 6.8k stars), Release Round (ethereumjs/ethereumjs-monorepo, 2.8k stars), Update Est Fixtures (ethereumjs/ethereumjs-monorepo, 2.8k stars) and Swapper Deposit (swapperfinance/swapper-toolkit, 852 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
ethereum (a GitHub organization) maintains it in ethereum/execution-specs, which has 1,195 GitHub stars. The repository holds 13 skills in this directory. The repository was last updated on October 8, 2026.
Source: ethereum/execution-specs on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.